MediaWiki:Gadget-LargerGallery.js

/** // // window.largerGallery = 1.5; // Custom autorun factor // window.largerGalleryZoom = 1; // disable or change the hover zoom factor /* eslint indent:["error","tab",{"outerIIFEBody":0}] */ /* eslint-disable vars-on-top, one-var, no-bitwise, valid-jsdoc, space-in-parens, computed-property-spacing, curly */ /* global jQuery, mediaWiki */ (function ($, mw) { 'use strict'; var oldMag,	nsNr = mw.config.get('wgNamespaceNumber'),	isCat = nsNr === 14,	special,	zoom = 0,	initial, // default image size	factor = 1,	galleries, //, ul.gallery	galleryBoxes;
 * Larger gallerie thumbnail images (in categories and galleries) with extra zoom feature
 * Fulfilled T3340
 * @Author original Brian Wolff (User:Bawolff), archived in Village_pump/Archive/2016/08
 * @Author User:Perhelion expanded/improved as Gadget, 03-2018; tested and further User:Speravir
 * @Revision: 13:54, 14 September 2018 (UTC)

function mouseenter(e) { var $this = $(this || e.target), $img = $this.find('img'), img = $img[0]; e.stopPropagation; $this.parent.height('+=0'); // Set higher resolution (1.5x) if (img && img.srcset) $img.attr('src', img.srcset.split(' ')[0]);

$img.css({		position: 'absolute',		// if smaller as default width, a center must be emulated ("+=" is needed for -moz)		left: '+=' + String(($this.width - img.width) / 2),		zIndex: 1003,		background: 'none',		transform: 'scale(' + zoom + ')',		transformOrigin: 'center 25%',		transition: 'transform .6s'	}); }

// Reset function mouseleave(e) { e.stopPropagation; $(this || e.target) .find('img') .css({			position: 'relative',			left: ,			zIndex: 1,			background: ,			transform: '',			transition: 'transform .3s'		}); // [0].srcset = "" // not needed anymore, only maybe do set a new mag factor (which should very rarly the case!?) }

/** function run(galleryboxes, single) { var mag = Number(factor); // magnification factor (introduced by Speravir)
 * { Change all galleries properties }
 * @param   $ {DOM LI/IMG}               galleryboxes  The galleryboxes
 * @param   {boolean}                    single        not multiple elements
 * @return  {DOM IMG}  { }
 * @return  {DOM IMG}  { }

galleryboxes = galleryboxes || galleryBoxes; zoom = window.largerGalleryZoom || 0; // calculate new mag if (oldMag && !single) mag /= oldMag; if (single) { initial = 120; oldMag = 0; // To set hover }

// calculate relative to scale factor (max 2.5 x 1.4 = 3.5) zoom = zoom || 2.5 - factor * 0.6; if (zoom < 1.3) zoom = 0; else zoom.toFixed(1);

/**	function scaleImage(img) { var iW = img.width || $(img).width, max = 600, // initial * 5 as the default MW value for raster img, so it could maybe load faster iWnew, iHnew, // new dimensions // responsive scaling factor bW = img.getAttribute('data-file-width') || max, // max width // Round the thumps to decadic numbers due the cache issue decadicRound = function (number) { return Math.round(number / 10) * 10; };
 * Scale an image.
 * @param  {DOM IMG}   img   The image element
 * @return {number}  { The new image size }

if (/\.(svg|SVG)\.png$/.test(img.src)) { // SVG var SVGm = bW / iW; // SVG mag if (SVGm < 1) { // relative scaling to fixed dimension SVGm += -SVGm / mag + 1; } else { SVGm = mag; }			// max = 512; // as the default MW value for SVG img, so it could maybe loaded faster iWnew = iW * SVGm; } else { iWnew = Math.min(iW * mag, bW); // maximum }

iWnew = Math.min(iWnew, max); // maximum var proportion = img.height / iW; if (proportion > 1) { // higher then wide (needed for possible reset) iHnew = Math.max(120, proportion * iWnew); // minimum iWnew = iHnew / proportion; // if was lesser then 120 } else { iWnew = Math.max(120, iWnew); // minimum iHnew = proportion * iWnew; // if was lesser then 120 }		var zW = Math.min(decadicRound(iWnew * 1.5), max); // maximum (default WM on file pages) img.height = decadicRound(iHnew); // keep proportion; iWnew = decadicRound(iWnew); // we need integer

var zW2 = Math.min(decadicRound(iWnew * 2), max); // not larger as possible // img.srcset = img.src + " 1x, " + img.srcset || ''; // fallback if new image size not loaded? img.src = img.src.replace(/\d+(px-[^/]*$)/, iWnew + '$1'); img.srcset = img.srcset ? img.srcset.replace(/\d+(px-[^/]* 1\.5x)/, zW + '$1').replace(/\d+(px-[^/]* 2x)/, zW2 + '$1') : img.src.replace(/\d+(px-[^/]*$)/, zW + '$1') + ' 1.5x, ' + img.src.replace(/\d+(px-[^/]*$)/, zW2 + '$1') + ' 2x'; img.width = iWnew; return iWnew; }

if (special && !single) { if (special === 'Search') $('.mw-search-results').first.width(function (i, w) {				return w * Math.min(Math.max(mag, 0.66), 1.5);			}).css('maxWidth', 'none');

var i = galleryboxes.length; while (i--) { scaleImage(galleryboxes[i]); }	} else { if (galleries) galleries.hide; // JS speedup >^2 galleryboxes.each(function {			var $this = $(this),				child1 = $this.children('div'),				child2 = child1.children('div'), // .thumb				child3 = child2.first.children('div').first;			if (!child3[0])				return; // caption e.q. or faulty thumb

// var img = child3[0].querySelector('img'); // bit faster than .find("img")[0] var img = child3.find('a img')[0];

if (!img) return; // non image file

// already there? if (!oldMag && zoom) { // hover child3.on('mouseenter', mouseenter).on('mouseleave', mouseleave); } else { child3.height(''); // clear old absolute if (!zoom) child3.off('mouseenter mouseleave'); }

var iWnew = scaleImage(img); // box width not too small var bW = (iWnew < initial * mag) ? (initial * mag + Math.max(120, iWnew)) / 2 : // average iWnew, bH = Math.max(initial * mag, bW) / 2 - img.height / 2 + 15; // height bW += 35; // static padding

$this.width(bW); child1.width(bW); // child2.first.height(bW - 5); child2.first.height(''); child2.width(bW - 5); // Default margin on max iW is 15, margin-width (needed for lesser hover) child3.css('margin', bH + 'px ' + ((bW - 5 - iWnew) / 2) + 'px'); });		if (galleries) galleries.show;

}	if (!single) { initial *= mag; oldMag = factor; } }

/** function init(targetSelect, targetGallery) { $(function {		// only once		if (document.getElementById('largerGallery2')) return;		var customMag = window.largerGallery || 0, // magnification factor			// Then, build a select and bind the change-event			$select = $(' ', { id: 'largerGallery' + (targetSelect ? '2' : ''), title: 'Larger-Gallery', style: 'float:right;margin:2px 5px 0 .5em;' }).on('change', function (e) { e.preventDefault; factor = this.value; // Dynamic page if (special === 0) galleryBoxes = galleries.find('li'); run; }),			factors = [1, 1.25, 1.5, 1.66, 1.83, 2.08, 2.5], // official values: 120, 150, 180, 200, 220, 250, 300, 400px; linear would be: 1.25, 1.5, 1.75, 2, 2.25, 2.5			content = document.getElementById(isCat ? 'mw-category-media' : 'mw-content-text') || document.getElementById('bodyContent'),			mi = 0; // mag index		initial = 120;		oldMag = 0;
 * Create select element and autorun if possible
 * @param     {string}    targetSelect   The target id for the element before inserting the select
 * @param     {jQuery object}  targetGallery  The target gallery
 * @param     {jQuery object}  targetGallery  The target gallery

galleries = $('ul.mw-gallery-traditional, ul.mw-gallery-nolines'); //, .gallery if (nsNr % 2) galleries = $; // Not on talk pages if (targetGallery) { galleries = targetGallery; special = 0; } else if (nsNr === -1) { special = mw.config.get('wgCanonicalSpecialPageName'); if (special === 'Search' || special === 'Listfiles') { galleries = $(content); galleryBoxes = galleries.find('.image img'); } else { special = 0; }		}		if (!special) galleryBoxes = galleries.find('li');

if (!galleryBoxes[0]) return; // Nothing to do

customMag = Number(customMag); if (customMag && factors.indexOf(customMag) === -1) { factors.push(customMag); // We can use string sort as the numbers are only tens digits factors.sort; // Alignment to default values. Real add is disabled due cache issue mi = factors.indexOf(customMag); if (mi) { // It's closer to the lower value? if (mi < factors.length - 1) { if (customMag - factors[mi - 1] < factors[mi + 1] - customMag) customMag = factors[mi - 1]; else customMag = factors[mi + 1]; } // else { factors.pop; } its too big } // else { factors.shift; } its too small factors.splice(mi); }

factors.forEach(function (i) {			$select.append($(' ', {				value: i,				text: (i * 100).toFixed + '%' // Fix bad floating point arithmetic			}));		});

// Set custom value for dropdown (not on special pages) if (customMag > 1 && !special) { $select[0].selectedIndex = factors.indexOf(customMag); factor = customMag; run(galleryBoxes); // autorun }		// Insert dropdown field if (targetSelect) { targetSelect = document.getElementById(targetSelect); targetSelect.parentNode.appendChild($select[0]); } else { isCat = isCat ? content.getElementsByTagName('H2')[0] : 0; if (isCat) { var p = $(isCat).next; if (p && p.prop('tagName') === 'P') p.prepend($select); else content.insertBefore($select[0], isCat.nextSibling); } else { if (!$('#contentSub:visible, #siteSub:visible').first.prepend($select)[0]) content.insertBefore($select[0], content.firstChild); }		}	}); }

mw.libs.largerGallery = { init: init, run: run };

init;

}(jQuery, mediaWiki)); //