User:Vivvt/galleryZoomHover.js

// Copied shamelessly from "User:Rillke/galleryZoomHover.js" from wikicommons

// google-image-search-like popup-boxes mw.util.addCSS( '#ibox{ position:absolute; overflow-y:none; background:#fff; z-index:1001; display:none; padding:10px; -webkit-box-shadow: 0px 0px 7px 2px #aaa; -moz-box-shadow: 0px 0px 7px 2px #aaa; box-shadow: 0px 0px 7px 2px #aaa; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; border: 2px solid #bbb }' ); mw.util.addCSS(	'img.speed { -ms-interpolation-mode:nearest-neighbor; image-rendering: -moz-crisp-edges; }\n'			+ 'img.quality { -ms-interpolation-mode:bicubic; image-rendering: optimizeQuality; }');

/** ** GalleryZoomHover for Wikimedia Commons ** @description **    Opens a magnified image on hovering on galleries and search results ** ** @autor Rillke, 2012 ** @license GPL v.3 **/

var gzh = window.galleryZoomHover = { fileNameFromImg: function($el) { try { return 'File:' + decodeURIComponent($el.attr('src')).match(/\/\S\/\S\S\/(\S+\.\S{2,5})\//)[1].replace(/_/g, ' '); } catch (ex) { try { return 'File:' + decodeURIComponent($el.attr('src')).match(/thumb\.php.*(?:\?|\&)f=(\S+\.\S{2,5})(?:\&.+)?$/)[1].replace(/_/g, ' '); } catch (ex2) {} } }, showImage: function($el, d) { if (this.showing) return; this.ibox.html(''); var $iNClone = d.zoomImageNode.clone.addClass('speed'), // Offset: $content <-> document (the ibox is a child of $content) contdOffset = mw.util.$content.offset, // Offset: image <-> document imgdOffset = $el.offset,

// 12 is border+padding; the rest is necessary to catch absolute/relative positioning elOT = Math.round(imgdOffset.top - contdOffset.top - 12), elOL = Math.round(imgdOffset.left - contdOffset.left - 12), iOW = $el.width, iOH = $el.height, wW = Math.min($(window).width-150, mw.util.$content.width), wH = $(window).height, iNW = d.zoomImageNode.width, iNH = d.zoomImageNode.height, elNT = (elOT - ((iNH - iOH) >> 1) - 12) + (contdOffset.top), elNL = (elOL - ((iNW - iOW) >> 1) - 12);

// Now adjust the new positions in case of overflow right/bottom var oflowY = Math.min(0, wH - (elNT + iNH + 46 - (this.$gzhFixed.position.top - contdOffset.top))); elNT += oflowY; var oflowX = Math.min(0, wW - (elNL + iNW + 24)); elNL += oflowX; // overflow top/left oflowY = Math.max(0, (this.$gzhFixed.position.top - contdOffset.top) - elNT); elNT += oflowY; oflowX = Math.max(0, (0 - elNL)); elNL += oflowX;

this.ibox.append($('', { href: d.zoomImageDescURL }).append($iNClone)); $iNClone.css({		width: iOW + 'px',		height: iOH + 'px'	}); this.ibox.css({		top: elOT + 'px',		left: elOL + 'px'	}); gzh.showing = true; this.ibox.stop(true).fadeTo(200, 1, function {		var animationReady = 0;		checkReady = function {			animationReady++;			if (2 === animationReady) {				gzh.showing = false;				gzh.showEl = $el;				gzh.ibox.append($(' ', { css: 'display:none;' }).append(' ', d.prettyTitle, gzh.$slideShowButtons.css({ display: 'inline-block', 'margin-top': '3px', 'float': 'right' })).fadeToggle('slow'));				$iNClone.removeClass('speed');			}		};		$(this).animate({ top: elNT, left: elNL }, 500, checkReady);		$iNClone.animate({ width: iNW, height: iNH }, 500, checkReady);	}); }, createImage: function($el, d) { if (-1 !== $.inArray(d.zoomImageState, ['loading', 'error'])) return; if (d.zoomImageNode) return gzh.showImage($el, d); d.zoomImageState = 'loading'; d.zoomImageNode = $(' ', { width: d.zoomImageWidth, height: d.zoomImageHeight }); d.zoomImageNode.load(function {		d.zoomImageState = 'ready';		if ('loading' === d.state) gzh.showImage($el, d);	}); d.zoomImageNode.error(function {		d.zoomImageState = 'error';	});

var wasReg; gzh.$slideShowButtons = $('#GallerySlideStartButtons').clone(true); if (!gzh.$slideShowButtons.length) { $(document).bind('slideshow', function(e, status, $gButtons) {			if ('loadedInstaller' === status) {				gzh.$slideShowButtons = $gButtons.clone(true);				if (wasReg) $gButtons.hide;			}		}); wasReg = (mw.loader.getState('ext.gadget.Slideshow') === 'registered'); mw.loader.load('ext.gadget.Slideshow'); }

// Finally assign the source path d.zoomImageNode.attr('src', d.zoomImage); }, over: function($el, d) { var $gb = $el.parents('.thumbinner'); if (!$gb.length) $gb = $el.parents('.thumb'); if (!$gb.length) $gb = $el.parents('tr'); if (!$gb.length) $gb = $el.parents('.image'); var cssOld = $gb.attr('style') || '';

if (!d.title) { $gb.css('border', 'dotted 1px #C88'); $gb.css('background', '#FDD'); return setTimeout(function {			$gb.attr('style', cssOld);		}, 500); }

$gb.css('border', 'dotted 1px #88C'); $gb.css('background', '#DDF'); setTimeout(function {		$gb.attr('style', cssOld);	}, 500);

if (d.zoomImage) return gzh.createImage($el, d);

var defaultSizes = [{w: 1280, h: 1024}, {w: 1024, h: 768}, {w: 800, h: 600}, {w: 640, h: 480}, {w: 320, h: 240}, {w: 220, h: 240}], iW = $el.width, iH = $el.height, wW = Math.min($(window).width-150, mw.util.$content.width) - 25, wH = $(window).height - 40, iRatio = iW / iH, wRatio = wW / wH, // Limiting Factor lF = iRatio > wRatio ? 'w' : 'h', // Limit l = iRatio > wRatio ? wW : wH, // Requested image size ris = {};

$.each(defaultSizes, function(i, s) {		if (s[lF] < l) {			ris = s;			return false;		}	}); var mwa = new mw.Api; mwa.get({		prop: 'imageinfo',		iiprop: 'timestamp|user|url|size|sha1|mime|metadata',		iiurlwidth: ris.w,		iiurlheight: ris.h,		titles: d.title	}, function(result) {		if (!result.query || !result.query.pages) return;		$.each(result.query.pages, function(i, pg) { if (!pg.imageinfo || !pg.imageinfo[0] || !pg.imageinfo[0].thumburl) return false; var ii = pg.imageinfo[0]; d.zoomImage = ii.thumburl; d.zoomImageDescURL = ii.descriptionurl; d.zoomImageWidth = ii.thumbwidth; d.zoomImageHeight = ii.thumbheight; d.originalIi = ii; d.prettyTitle = d.title.match(/^File:(.+)\.\w{2,5}/)[1]; if ('loading' === d.state) gzh.createImage($el, d); });	}); }, init: function { var $imgs; //.gallerybox > div > div.thumb, .searchResultImage, .thumbinner $imgs = mw.util.$content.find('a.image > img'); if (0 === $imgs.length) return;

// For computing the viewport offset this.$gzhFixed = $(' ', { style: 'position:fixed; top:0px; left:0px; height:0px; overflow:hidden;', id: 'gzhFixed' }).appendTo(mw.util.$content);

this.showEl = 0;

$imgs.each(function {		var $el = $(this);		$el.data('gzh', { title: gzh.fileNameFromImg($el), prettyTitle: '', zoomImage: '', zoomImageDescURL: '', zoomImageNode: null, zoomImageState: '', zoomImageWidth: 0, zoomImageHeight: 0, originalIi: {}, state: 'hidden' });	});	var _mouseIn = function { var $el = $(this), d = $el.data('gzh');

if (gzh.showing) return; if (gzh.showEl[0] === $el[0]) return gzh.ibox.triggerHandler('mouseenter');

if ('hidden' === d.state) { d.state = 'loading'; gzh.over($el, d); }	};	var _mouseOut = function { var $el = $(this), d = $el.data('gzh'); if ('loading' === d.state) { d.state = 'hidden'; }		if (gzh.showing) return; gzh.ibox.triggerHandler('mouseleave'); };	$imgs.mouseleave(_mouseOut); mw.loader.using('jquery.hoverIntent', function {		$imgs.hoverIntent({ interval: 250, over: _mouseIn, // Too slow out: function {}, timeout: 0 });	});	var fadeTimeout = 0; this.ibox = $(' ', { id: 'ibox' }).appendTo(mw.util.$content).bind('mouseleave click', function {		clearTimeout(fadeTimeout);		if (gzh.showing || gzh.hiding) return;		fadeTimeout = setTimeout(function { gzh.hiding = true; gzh.ibox.stop(true).fadeTo(500, 0, function{				gzh.hiding = false;				gzh.showEl = 0;				gzh.ibox.html('');				gzh.ibox.hide;			}); }, 500);	})	this.ibox.mouseenter(function {		clearTimeout(fadeTimeout);		if (gzh.showing) return;		if (gzh.hiding) {			gzh.ibox.stop(true).fadeTo(100, 1, function{ gzh.hiding = false; });		}	}); } } $(function {	gzh.init; });