Thumbnail preview of an item by hovering my mouse over


#1

Hi I need to see a thumbnail preview of an item (image, pdf, html etc) by hovering my mouse over it so I can easily see what the item is without having to load it fully. It should show preview in a pop-up window when I’m mouses over for 1 second and should disappear when I’m mouses off the item. If the preview cannot be shown in a browser window, then show a message like “Cannot display”.

For the pdf preview of html code (Icon with the label) is below:

<div id="ember8734" class="ember-view managed-object-tools-icon managed-object-icon-view container-view clickable" style="font-size: 20px">
<rs-icon id="ember8737" class="ember-view primary-icon managed-object-primary-icon icon" style="font-size: 20px">
<icon glyph="type_pdf" class="type_pdf" set="types" style="font-size: 20px;">
</icon>
</rs-icon>
<rs-icon id="ember8743" class="ember-view version-icon icon" style="width: 1em; height: 1em; font-size: 20px">
</rs-icon>
</div>
<managed-object-label id="ember8749" class="ember-view content-data managed-object-label-view managed-object-label-view managed-object-label data-view managed-object-label-view-core_component_data-view-mixin managed-object-label-core_component_data-view-mixin data-view-core_component_data-view-mixin">
<div core-role="primaryLabel" class="" data-bindattr-49="49">story.​pdf</div>

For all the item(html, pdf, image etc) Thumbnail-preview.js code is here:

(function () {
    var childView = function (name, ext) {
            return function () {
                return this.createChildView(this.get(name), ext);
            }.property();
        },
        ScalerMixin = {
            imageWidth: null,
            imageHeight: null,
            containerWidth: null,
            containerHeight: null,
            width: null,
            height: null,
            top: null,
            left: null, 
            attributeBindings: [ 'style', 'src' ],
            style: function () {
                if (!this.get('width') || !this.get('height') || isNaN(this.get('top')) || isNaN(this.get('left'))) {
                    return '';
                }
                return 'width: ' + this.get('width') + 'px; height: ' + this.get('height') + 'px; margin-top: ' + this.get('top') + 'px; margin-left: ' + this.get('left') + 'px;';
            }.property('width', 'height', 'top', 'left'),
            captureImageSize: function () {
                if (this.isDestroying || this.isDestroyed) { return; }
                var i = new window.Image();
                i.src = this.get('src');
                this.set('imageWidth', i.width);
                this.set('imageHeight', i.height);
                this.updateSize();
            },
            updateSize: function () {
                if (this.isDestroying || this.isDestroyed) { return; }
                if (!this.imageWidth || !this.imageHeight || !this.containerWidth || !this.containerHeight) {
                    return;
                }
                var iar = this.imageWidth / this.imageHeight,
                    car = this.containerWidth / this.containerHeight;
                var width, height;
                if (car > iar) {
                    height = this.containerHeight;
                    width = iar * this.containerHeight;
                } else {
                    height = this.containerWidth / iar;
                    width = this.containerWidth;
                }
                if (this.width !== width) {
                    this.set('width', width);
                }
                if (this.height !== height) {
                    this.set('height', height);
                }
                this.set('top', (this.containerHeight - height) / 2);
                this.set('left', (this.containerWidth - width) / 2);
            }.observes('imageWidth', 'imageHeight', 'containerWidth', 'containerHeight'),
            containerWidthBinding: 'parentView.width',
            containerHeightBinding: 'parentView.height',
            _attachLoadHandler: function () {
                this.get('element').onload = this.captureImageSize.bind(this);
            }.on('didInsertElement')
        },


        ThumbnailImage = Ember.View.extend(ScalerMixin, {
            tagName: 'img',         
            isVisible: function () {
                return !!this.get('src');
            }.property('src'),  
            objectBinding: 'parentView.object',
            click: function () {
                alert('thumb1');
                var i = new window.Image(),
                    src = this.get('object').uri();
                i.onload = function () {
                    Core.openWindow(src, {
                        width: i.width,
                        height: i.height
                    });
                };
                i.src = src;
            },
            classNames: [ 'clickable' ]
        }),
        Thumbnail = ThumbnailImage.extend({
            src: function () {
                var object = this.get('object');
                if (!object) { return; }
                var thumb = object.get('keyedVariants.core:thumbnail');
                if (thumb) {
                    return object.uri({ variantName: thumb.variantName });
                }
                return null;
            }.property('object', 'object.keyedVariants.core:thumbnail', 'object.variants.length')
        }),
        Image = ThumbnailImage.extend({
            src: function () {
                var object = this.get('object');
                if (!object) { return; }
                var type = object.get('contentType');
                if (/^image\/(?:jpeg|gif|png|svg)/.test(type)) {
                    return object.uri();
                }
                return null;
            }.property('object')
        }),             
        Playable = Ember.ContainerView.extend({
            object: null,
            playableSources: function () {
                var playerTag = document.createElement(this.get('playerTagName')),
                    sources = this.get('sources') || [];
                return sources.filter(function (source) {
                    if (!playerTag.canPlayType) { return false; }
                    return !!playerTag.canPlayType(source.type + ';').replace(/no/, '');
                }, this);
            }.property('sources.@each.type'),
            updateSizes: function () {
                var w = Math.min(this.get('parentView.width') | 0),
                    h = Math.min(this.get('parentView.height') | 0),
                    s = Math.min(128, Math.min(this.get('parentView.width'), this.get('parentView.height')) * 0.75) | 0,
                    l = Math.floor((w - s) / 2),
                    t = Math.floor((h - s) / 2),
                    m = 'margin: ' + t + 'px 0 0 ' + l + 'px';
                this.set('margin', m);
                this.set('iconSize', s);
            }.on('didInsertElement').observes('parentView.width', 'parentView.height'),
            iconSize: 128,
            marginLeft: 0,
            marginTop: 0, 
            PlayView: Ember.ContainerView.extend({
                tagName: null,
                ThumbnailView: ThumbnailImage,
                thumbnailView: childView('ThumbnailView'),
                objectBinding: 'parentView.object',
                attributeBindings: [ 'controls', 'preload', 'style' ],
                style: function () {
                    var w = this.get('parentView.parentView.width'),
                        h = this.get('parentView.parentView.height');
                    return "max-width: " + w + "px; max-height: " + h + "px;";
                }.property('parentView.parentView.width', 'parentView.parentView.height'),
                controls: "true",
                preload: 'metadata',
                poster: 'thumbnailView.src',
                SourceView: Ember.View.extend({
                    tagName: 'source',
                    attributeBindings: ['src', 'type'],
                    src: null,
                    type: null
                }),
                PlayButton: Core.view.Icon.extend({
                    classNames: ['play-button'],
                    sizeBinding: 'parentView.parentView.iconSize',
                    marginBinding: 'parentView.parentView.margin',
                    model: 'play',
                    click: function () {
                        alert('thumb2');
                        var el = this.get('parentView.element');
                        if (el) {
                            this.get('parentView.element').play();
                        }
                    }
                }),
                playButton: childView('PlayButton'),
                sourceViews: function () {
                    return this.get('parentView.sources').map(function (source) {
                        return this.createChildView(this.SourceView, source);
                    }, this);
                }.property(),
                setupView: function () {
                    if (this.isDestroying || this.isDestroyed) { return; }
                    this.set('tagName', this.get('parentView.playerTagName'));
                    this.replace(0, this.get('length'), []);
                    this.get('sourceViews').forEach(function (sourceView) {
                        this.pushObject(sourceView);
                    }, this);
                    this.pushObject(this.get('thumbnailView'));
                    this.pushObject(this.get('playButton'));
                }.on('init').observes('parentView.sources')
            }),
            playView: childView('PlayView'),
            PremediaView: Ember.ContainerView.extend({
                ThumbnailView: ThumbnailImage,
                thumbnailView: childView('ThumbnailView'),
                PlayButton: Core.view.Icon.extend({
                    classNames: ['play-button'],
                    sizeBinding: 'parentView.parentView.iconSize',
                    marginBinding: 'parentView.parentView.margin',
                    model: 'play',
                    click: function () {
                        alert('thumb3');
                        this.get('parentView.parentView').play();
                    }
                }),
                playButton: childView('PlayButton'),
                setupView: function () {
                    this.replace(0, this.get('length'), []);
                    this.pushObject(this.get('thumbnailView'));
                    this.pushObject(this.get('playButton'));
                }.on('init').observes('thumbnailView.src')
            }),
            premediaView: childView('PremediaView'),
            PlaceholderView: Ember.ContainerView.extend({
                ThumbnailView: ThumbnailImage,
                thumbnailView: childView('ThumbnailView'),
                CantPlayButton: Core.view.Icon.extend({
                    classNames: ['play-button', 'cant-play'],
                    sizeBinding: 'parentView.parentView.iconSize',
                    marginBinding: 'parentView.parentView.margin',                  
                    model: 'play_not_available',
                    titleBinding: 'Core.messageTable.content/icon/preview/cant-play'
                }),
                cantPlayButton: childView('CantPlayButton'),
                setupView: function () {
                    this.replace(0, this.get('length'), []);
                    this.pushObject(this.get('thumbnailView'));
                    this.pushObject(this.get('cantPlayButton'));
                }.on('init').observes('thumbnailView.src')
            }),
            placeholderView: childView('PlaceholderView'),
            media: false,
            play: function () {
                this.set('media', true);
                Ember.run.schedule('render', this, function () {
                    var go = function () {
                        var el = this.get('playView.element');
                        if (!el) {
                            Ember.run.later(this, go);
                        } else {
                            $(el).on('canplay', function () {
                                el.play();
                            });
                        }
                    }.bind(this);
                    go();                   
                });
            },
            setupView: function () {
                this.replace(0, this.get('length'), []);
                if (!this.media) {
                    this.pushObject(this.get('premediaView'));
                } else {
                    if (this.get('playableSources.length') === 0) {
                        this.pushObject(this.get('placeholderView'));
                    } else {
                        this.pushObject(this.get('playView'));
                    }
                }
            }.on('init').observes('playableSources.length', 'media')
        });
    Core.component.ManagedObjectPreview.MediaPreview = Ember.ContainerView.extend({
        classNames: [ 'thumbnail-preview' ],
        height: 250,
        width: 292,
        captureSizeForRealsies: function () {
            if (this.isDestroying || this.isDestroyed) { return; }
            var el = this.get('element');
            if (!el) {
                Ember.run.later(this, 'captureSizeForRealsies', 125);
                return;
            }
            var rect = el.getBoundingClientRect();
            if (!rect.width || !rect.height) {
                Ember.run.later(this, 'captureSizeForRealsies', 125);
                return; 
            }
            // Find first scrollable containment
            var scrollX = scrollY = el;
            while (scrollX && scrollX.nodeType !== Node.DOCUMENT_NODE && $(scrollX).css('overflow-x') !== 'auto') {
                scrollX = scrollX.parentNode;
            }
            while (scrollY && scrollY.nodeType !== Node.DOCUMENT_NODE && $(scrollY).css('overflow-y') !== 'auto') {
                scrollY = scrollY.parentNode;
            }
            if (scrollY) {
                rect.height = Math.min(rect.height, scrollY.clientHeight);
            }
            if (scrollX) {
                rect.width = Math.min(rect.width, scrollX.clientWidth);
            }
            this.beginPropertyChanges();
            if (rect.width !== this.width) {
                this.set('width', rect.width);
            }
            if (rect.height !== this.height) {
                this.set('height', rect.height);
            }
            this.endPropertyChanges();
        },
        captureSize: function () {
            Ember.run.later(this, 'captureSizeForRealsies', 125);
        }.on('didInsertElement').observes('Core.document.width'),
        classNameBindings: [ 'isImage:ui-clickable' ],
        objectBinding: 'model.finalManagedObject',
        thumb: Ember.computed(function () {
            var uri, mo = this.get('object');
            if (!mo) { return; }
            if (mo.getVariant('core:thumbnail')) {
                uri = Core.restUrl(2, 'content/binary/id/' + this.get('object.id') + '?variant=core:thumbnail');
                if (mo.get('revision')) {
                    uri += '&revision=' + mo.get('revision');
                }
                return uri;
            }
            return null;
        }).property(
            'object.variants.@each.variantName',
            'object.id',
            'object.revision'
        ),
        isImage: function () {
            var contentType = this.get('object.contentType'),
                isImage = (/^image\/(?:jpeg|gif|png|svg)/).test(contentType);
            return isImage;
        }.property('object.contentType'),
        urlsFor: function (type) {
            var obj = this.get('object') || this.get('model');
            URL = obj.streamingUri;
            var parentId = $('.preview-and-information-view').attr('id');
            var childId = $('#' + parentId).find('div').attr('id');
            if (obj.contentType == 'application/vnd.openxmlformats-officedocument.presentationml.presentation') {
                $('#'+childId).html('<a href="'+URL+'" target=_blank><span style=cursor:pointer><img src=/core-cms/plugin/core-cms-theme/images/core/content-type/24/office-powerpoint.png  alt=power-point style=width: 20px; cursor:pointer;></span></a>');
                return false;
            }
            else if(obj.contentType == 'text/plain' || obj.contentType == 'application/vnd.ms-xpsdocument'){
                $('#'+childId).html('<a href="'+URL+'" target=_blank><span style=cursor:pointer><img src=/core-cms/plugin/core-cms-theme/images/core/content-type/24/file-generic.png style=width: 20px;cursor:pointer;></span></a>');
                return false;
            }
            else if(obj.contentType == 'application/pdf'){
                $('#'+childId).html('<a href="'+URL+'" target=_blank ><span style=cursor:pointer><icon glyph=type_pdf class=type_pdf set=types style=font-size:20px;cursor:pointer;></icon></span></a>');
                return false;
            }
            else if(obj.contentType == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'){
                $('#'+childId).html('<a href="'+URL+'" target=_blank ><span style=cursor:pointer><img src=/core-cms/plugin/core-cms-theme/images/core/content-type/24/office-word.png alt=office-word style=width: 20px;cursor:pointer;></span></a>');
                return false;
            }
            else if(obj.contentType == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'){
                $('#'+childId).html('<a href="'+URL+'" target=_blank ><span style=cursor:pointer><img src=/core-cms/plugin/core-cms-theme/images/core/content-type/24/office-excel.png style=width: 20px;cursor:pointer;></span></a>');
                return false;
            }
            else if(obj.contentType == 'application/x-shockwave-flash'){
                $('#'+childId).html('<a href="'+URL+'" target=_blank ><span style=cursor:pointer><icon glyph=type_adobe_flash_ class=type_adobe_flash set=types style=font-size: 20px;cursor:pointer;></icon></span></a>');
                return false;
            }
            else {
                $('#'+childId).html('');
            }
            if (!obj) { return; }
            var items = [obj].concat(obj.get('variants') || []);
            items = items.map(function (variant) {
                var ret = {};
                if (Ember.get(variant, 'variantName')) {
                    ret.src = obj.uri({ variantName: Ember.get(variant, 'variantName') });
                } else {
                    ret.src = obj.uri();
                }
                ret.type = Ember.get(variant, 'contentType');
                return ret;
            });
            items = items.filter(function (item) {
                if (!item.src || !item.type) { return false; }
                return item.type.substr(0, type.length + 1) === (type + '/');
            });
            return items;
        },
        videoUrls: function () {
            return this.urlsFor('video');
        }.property('object.contentType', 'object.variants.@each.contentType'),
        isVideo: function () {
            return !!this.get('videoUrls.length');
        }.property('videoUrls.length'),
        audioUrls: function () {
            return this.urlsFor('audio');
        }.property('object.contentType', 'object.variants.@each.contentType'),
        isAudio: function () {
            return !!this.get('audioUrls.length');
        }.property('audioUrls.length'),
        objectChanged: function () {
            console.log(this);
            if (this.get('length')) {
                this.replace(0, this.get('length'), []);
            }
            if (this.get('isVideo')) {
                this.pushObject(this.get('videoView'));
            } else if (this.get('isAudio')) {
                this.pushObject(this.get('audioView'));
            } else {
                this.pushObject(this.get('imageView'));
            }
        }.on('init').observes('object', 'media'),
        VideoView: Playable.extend({
            classNames: [ 'video-preview' ],
            playerTagName: 'video',
            objectBinding: 'parentView.object',
            sourcesBinding: 'parentView.videoUrls'
        }),
        videoView: childView('VideoView'),
        AudioView: Playable.extend({
            classNames: [ 'audio-preview' ],
            playerTagName: 'audio',
            objectBinding: 'parentView.object',
            sourcesBinding: 'parentView.audioUrls'
        }),
        audioView: childView('AudioView'),
        ImageView: Image.extend({
            classNames: [ 'image-preview' ]
        }),
        imageView: childView('ImageView'),
        ThumbView: Thumbnail.extend({
            classNames: [ 'thumbnail-preview' ]
        }),
        thumbView: childView('ThumbView')
    });
    Core.component.ManagedObjectPreview.ThumbPreview = Core.component.ManagedObjectPreview.MediaPreview.extend({
        objectChanged: function () {
            if (this.get('length')) {
                this.replace(0, this.get('length'), []);
            }
            if (this.get('thumb')) {
                this.pushObject(this.get('thumbView'));
            }       
        }.on('init').observes('object')
    });
    var LocalNavigator = Core.component.NavigableSection.Navigator.extend({
        objectBinding: 'sectionView.model.finalManagedObject',
        tooltipBinding: "Core.messageTable.content/preview/thumbnail",
        enabled:function () {
            return !!this.get('types.length');
        }.property('types', 'types.length')
    });
    Core.component.ManagedObjectPreview.proto().navigators.pushObjects([
        LocalNavigator.extend({
            enabled: function () {
                return !!this.get('types.length');
            }.property('types.length'),
            icon: function () {
                if (this.get('thumb')) {
                    return 'thumbnail_missing';
                }
                var types = this.get('types'),
                    isAudio = false,
                    isVideo = false;
                types.forEach(function (type) {
                    if (/^video\//.test(type)) {
                        isVideo = true;
                    }
                    if (/^audio\//.test(type)) {
                        isAudio = true;
                    }
                    if (/^application\//.test(type)) {
                        isDocument = true;
                    }
                });
                if (isVideo) {
                    return 'types:type_video';
                }
                if (isAudio) {
                    return 'types:type_audio';
                }
                return types.find(function (type) {
                    return /^image\//.test(type);
                }) ? 'types:type_image' : 'thumbnail_missing';
            }.property('thumb', 'object'),
            thumb: function () {
                var obj = this.get('object'),
                    variants = obj && obj.get('variants'),
                    types;
                if (!variants) { return null; }
                return obj && obj.get('keyedVariants.core:thumbnail');
            }.property('object.keyedVariants.core:thumbnail'),
            types: function () {
                var thumb = this.get('thumb');
                if (thumb) {
                    return [ thumb.contentType ];
                }
                var obj = this.get('object'),
                    variants = (obj && obj.get('variants')) || [],
                    types;
                if (!obj) { return []; }
                types = [ obj.get('contentType') ];
                variants.forEach(function (variant) {
                    if (variant.variantName !== 'core:thumbnail') {
                        types.push(variant.contentType);
                    }
                });
                types = types.filter(function (type) {
                    return (/^(image|audio|video|application)\//).test(type);
                });
                return types;       
            }.property('object', 'object.keyedVariants', 'object.variants.length'),
            bodyView: function () {
                if (this.get('thumb')) {
                    return Core.component.PrimaryTile.extend({
                        contains: Core.component.ManagedObjectPreview.ThumbPreview.extend({
                            modelBinding: 'parentView.model'
                        }),
                        scrollable: false,
                        style: function () {
                            return 'overflow: hidden';
                        }.property(),
                        attributeBindings: ['style']
                    });
                } else {
                    return Core.component.PrimaryTile.extend({
                        contains: Core.component.ManagedObjectPreview.MediaPreview.extend({
                            modelBinding: 'parentView.model'
                        }),
                        scrollable: false,
                        style: function () {
                            return 'overflow: hidden';
                        }.property(),
                        attributeBindings: ['style']
                    });                 
                }
            }.property('thumb', 'object')
        }).create()
    ]);
}());

for that corresponding icon tool mention in managedObjecttool.js:

ObjectIconView: Ember.ContainerView.extend(childMOMixin, {
				classNames: ['managed-object-tools-icon'],
				classNameBindings: [ 'clickable' ],
				attributeBindings: [ 'style' ],
				style: function () {
					return 'font-size: ' + this.get('size') + 'px';
				}.property('size'),
				mouseDown: function () { return false; },
				click: function () {
					var actionMenuContext = this.get('actionMenuContext'),
						element = this.$(),
						row = element.parents('tr:first'),
						ctl = this.get('controller');
					if (ctl && ctl.send) {
						ctl.send('contentItemActionMenu', row.length ? row : element, element, actionMenuContext);
					}
					return false;
				},
				clickable: function () {
					return !!this.get('controller._actions.contentItemActionMenu');
				}.property(''),
				childViews: [
					'PrimaryIcon',
					'TypeOverlay',
					'VersionStatus',
					'DraftStatus'
				],
				size: 20,
				PrimaryIcon: Core.component.ManagedObjectPrimaryIcon.extend(childMOMixin, {
					sizeBinding: 'parentView.size',
					loadStateBinding: 'parentView.loadState',
					suggestedIconsBinding: 'parentView.suggestedIcons'
				}),
				VersionStatus: Core.view.Icon.extend(childMOMixin, {
					sizeBinding: 'parentView.size',
					classNames: ['version-icon'],
					classNameBindings: [ 'model' ],
					model: function () {
						if (this.get('isFrozen')) { return 'status_pinned'; }
						if (this.get('isOwned')) { return 'status_checked_out'; }
						if (this.get('isLocked')) { return 'status_locked'; }
					}.property('isFrozen', 'isOwned', 'isLocked')
				}),
				DraftStatus: Core.view.Icon.extend(childMOMixin, {
					sizeBinding: 'parentView.size',
					classNames: ['version-icon'],
					classNameBindings: [ 'model' ],
					model: function () {
						if (this.get('hasDraft')) { return 'status_draft'; }
						return "$blank";
					}.property('hasDraft')
				}),
				TypeOverlay: Core.view.Icon.extend(childMOMixin, {
					sizeBinding: 'parentView.size',
					classNames: ['type-icon'],
					classNameBindings: [ 'model' ],
					model: function () {
						var type = this.get('finalObjectType');
						if (type === 'canode') {
							return 'status_ca_node';
						}
						if (type === 'mo') {
							return 'status_is_xml';
						}
						//if (type === 'mononxml' && this.get('variants.length') > 0) {
						//	return 'status_has_variants';
						//}
						return '$blank';
					}.property('parentView.finalMO.objectType', 'finalObjectType')
				})
			}).named("ManagedObjectIconView")

Please provide me the suggestion for this. I’m new to the ember. If you need the further detail ask me in the comment. Your help will be more appreciate. Thanks in advance.


#2

Seems like you are using a very old version of Ember. ContainerView was deprecated in 1.13 and removed in Ember 2.0, which was released in August 2015. If you have any chance, I would recommend to upgrade your code.


#3

Thanks @jelhan. I’m using Ember 1.4.0 only. That only supporting to my project. Please provide any suggestion for this code.