MediaWiki:Gadget-GalleryFilterExtension.js

From wikishia

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/**
 * Filter any gallery by file-type
 * @author [[User:Rillke]], 2011
 * @author [[User:Perhelion]], 2017 (jQuery replaced for performance)
 * @revision 22:31, 19 January 2018 (UTC)
 * This code is jshint-valid!
 * required modules: mediawiki.Title, mediawiki.util, mediawiki.page.ready
 */
 
/*global jQuery, mediaWiki*/
/*jshint curly:false, forin:false */
(function ($, mw) {
"use strict";

var boxes = [];
var ok = 0;
var GalleryFilterMIME = window.GalleryFilterMIME || 1;
var isCAT = mw.config.get('wgNamespaceNumber') === 14;
var content = ( isCAT ? $('#mw-category-media')[0] : null ) || $('#mw-content-text')[0];

var galleries = content.getElementsByClassName('gallery');
if (!galleries[0]) return;

for (var i = 0; i < galleries.length; i++) {
	var gal = galleries[i].getElementsByClassName('gallerybox');
	if (ok || gal.length > 3) ok = 1;
	boxes.push(gal);
}
if (!ok) return;

function init() {
	var boxByMIME = {}; // boxes by MIME-type
	var mime = "unknown", ext;

	// First, find out which types we have on the page.
	// We do not use jQuery on start in a loop for performance.
	for (var box in boxes) {
		box = boxes[box];
		for (var b = 0; b < box.length; b++) {
			var li = box[b];
			var t = li.getElementsByClassName('thumb')[0];
			if (!t) continue;
			ext = mime = "other";
			var e = t.getElementsByClassName('mw-file-description')[0];
			if (e) ext = mime = "images";
			else {
				e = t.querySelector('.PopUpMediaTransform');
				if (e) ext = mime = "videos";
			}
			if (e) {
				e = e.getElementsByTagName('img')[0];
				if (e)
					ext = mw.Title.newFromImg(e).getExtension().toUpperCase().replace(/(?:(JP)E(G)|(TI)F(F))$/, '$1$2$3$4');
			} else if(t.querySelector('audio, video, .mediaContainer')) {
				ext = mime = t.querySelector('video') ? 'videos' : 'audios';
				e = li.getElementsByClassName('galleryfilename')[0]; // exists also on non categories
				if (e && e.title)
					ext = e.title.match(/\.([^\. ]{2,5})$/)[1].toUpperCase();
			} // else other?

			if (!boxByMIME[mime]) boxByMIME[mime] = {};
			if (!boxByMIME[mime][ext]) boxByMIME[mime][ext] = [];
			boxByMIME[mime][ext].push(li);
		}
	}
	// Don't show selection if only one file-type
	if (Object.keys(boxByMIME).length === 1 && Object.keys(boxByMIME[mime]).length === 1) return;
	
	function showAll(list) {
		$.each(list, function(i, box) {
			$(box).show();
		});
	}

	// Then, build a select and bind the change-event
	var $select = $('<select id="galleryFilterExt">').on('change', function (e) {
			var ext = this.value;
			if ('all' === ext)
				return showAll(boxes);
			var sel = this.options[this.selectedIndex];
			if (sel.className === 'optionGroup')
				$.each(boxByMIME, function(value, boxesOfMIME) {
					if (ext === value) {
						showAll(boxesOfMIME);
					} else $.each(boxesOfMIME, function(i, boxesOfExt) {
						$(boxesOfExt).hide();
					});
				});
			else {
				var type = sel.getAttribute('name');
				if (!type) return;
				$.each(boxByMIME, function(mime, boxesOfExt) {
					var selBoxes = boxByMIME[mime];
					$.each(selBoxes, function(value, boxesOfExt) {
						if (ext === value && mime === type) {
							$(boxesOfExt).show();
						} else {
							$(boxesOfExt).hide();
						}
					});
				});
			}
		});

	var all = 0;
	var opt = 1; // Only for groups 
	var width = 0; // For absolute

	for (var type in boxByMIME) {
		$select.append($('<option>', {
				// value: mime,
				'class': "optionGroup",
				'text': type
			})
		);
		opt++;

		for (var fext in boxByMIME[type]) {
			var cnt = boxByMIME[type][fext].length;
			all += cnt;
			opt++;
			$select.append($('<option>', {
					'class': "optionChild",
					'value': fext,
					'name': type, // sure?
					'text': fext + ' (' + cnt + ')'
				})
			);
		}
	}
	$select.append($('<option>', {
			selected: 'selected',
			value: 'all',
			text: mw.msg("Pagetriage-filter-all") + (isCAT ? '' : ' (' + all + ')')
		})).css({
			margin: '0 5px'
			// display: 'inline-block'
		});
	if (!GalleryFilterMIME || Object.keys(boxByMIME).length === 1) { // Remove MIME select
		GalleryFilterMIME = 0;
		$select.find(".optionGroup").remove();
		width = 1;
	} else {
		mw.util.addCSS(
			'.optionGroup{font-weight:bold;font-style:italic;}\n.optionChild{padding-left:15px;}');
		$select.css({
				position: 'absolute',
				zIndex: 9
			}).on('focus', function (e) {
			e = $(this);
			e.height(opt * e.height());
			e.one('change', function (e) {
				if (this.multiple) return $(this).blur();
			}).one('blur', function (e) {
				this.multiple = false;
				$(this).height('auto');
			});
			this.multiple = true;
		});
	}

	isCAT = isCAT ? content.getElementsByTagName('h2')[0] : 0;
	if (isCAT) {
		var p = $(isCAT).next(); // content.getElementsByTagName('p')[0];
		if (p && p.prop("tagName") === 'P') {
			p.prepend($select); // p.insertBefore($select[0], p.firstChild);
			if (GalleryFilterMIME) {
				width = $select.outerWidth() + 5; // width first after insert
				p.css({ 'paddingLeft': width + 5 });
				$select.offset({ left: $select.offset().left - width - 5 });
			}
		} else {
			content.insertBefore(
				$select[0],
				content.getElementsByTagName('h2')[0].nextSibling);
		}
	} else {
		content.insertBefore($select[0], content.firstChild);
	}
	if (!width)
		$select.wrap($("<p>").css({
				width: $select.outerWidth(),
				height: $select.outerHeight()
			})
		);
}

$.when(mw.loader.using('mediawiki.api'), $.ready).then(function () {
	return new mw.Api().loadMessagesIfMissing(['Pagetriage-filter-all']);
}).then(init);

}(jQuery, mediaWiki));