Jump to content

User:Vivvt/galleryZoomHover.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// 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($('<a>', { 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($('<span>', { css: 'display:none;' }).append('<br/>', 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 = $('<img>', { 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 = $('<div>', { 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 = $('<div>', { 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();
});