MediaWiki:Gadget-Thickbox.js

    From Hokuto no Ken Encyclopedia | HnKWiki
    Revision as of 08:56, 18 December 2023 by Madness (talk | contribs)

    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.
    /*
     * Thickbox4MediaWiki v3.12 - Based on Thickbox 3.1 By Cody Lindley (http://www.codylindley.com)
     * Copyright (c) 2010 - 2022 Jesús Martínez (User:Ciencia_Al_Poder), Original Thickbox Copyright (c) 2007 Cody Lindley
     * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
    */
    window.Thickbox = (function($, mw) {
    	'use strict';
    	var _version = '3.12',
    	// Minimum dimensions
    	_minWidth = 210,
    	// Margin between the image and the border of ThickBox
    	_imageMarginWidth = 15,
    	// Minimum margin to the edge of the window. If the image is exceeded it will be reduced
    	_minMarginWidth = 30,
    	_minMarginHeight = 15,
    	// Waiting time for the loader to appear in ms
    	_loaderWait = 500,
    	// Internal
    	_imgPreloader = null,
    	_galleryData = null,
    	_galleryIndex = -1,
    	_width = null,
    	_height = null,
    	_getCaption = null,
    	_imgTip = null,
    	_imgTipTarget = null,
    	_imgTipVisible = false,
    	_loaderPresent = false,
    	_loaderTm = null,
    	_logger = null,
    	// Private functions
    	_init = function() {
    		// COMPAT
    		if (window.Thickbox4MediaWikiLoaded) { return; }
    		window.Thickbox4MediaWikiLoaded = true;
    		// You could have put an event directly in each 'a.image', but this is much faster and more efficient (it only takes 20% in FF2) than to go through the entire DOM
    		$('#mw-content-text').off('click.thickbox mouseover.thickbox_imgtip').on({
    			'click.thickbox': _triggerEvent,
    			'mouseover.thickbox_imgtip': _imgTipEvent
    		});
    	},
    	_triggerEvent = function(e) {
    		// If there is any special key pressed, we exit
    		if (e.ctrlKey || e.altKey || e.shiftKey) {
    			return true;
    		}
    		var target = e.target;
    		if (_isTag(target,'img')) { // Gallery o thumb
    			var a = target.parentNode;
    			// Images with links to other articles do not have the "image" class, except in Wikia where it does and add "link-internal" or "link-external"
    			if (!a || !_isTag(a,'a') || !_isClass(a,'image') || _isClass(a, 'link-internal') || _isClass(a, 'link-external')) {
    				return true;
    			}
    			// Wikia 2 Gallery
    			if (_isClass(a,'lightbox')) {
    				target.blur();
    				_getCaption = _getCaptionWikia;
    				_galleryData = $(target).closest('div.wikia-gallery').find('> div.wikia-gallery-item > div.thumb > div.gallery-image-wrapper > a.lightbox');
    				if (_galleryData.length === 0) {
    					_galleryData = $(target).closest('div.wikia-gallery').find('> div.wikia-gallery-row > div.wikia-gallery-item > div.thumb > div.gallery-image-wrapper > a.lightbox');
    				}
    				if (_galleryData.length === 0) {
    					return true;
    				}
    				_galleryIndex = _galleryData.index(a);
    				_showImage(a);
    				return false;
    			}
    			if (_isClass(target,'thumbimage')) {
    				// Its thumbnail
    				a.blur();
    				_getCaption = _getCaptionThumb;
    				_showImage(a);
    				return false;
    			}
    			var gb = a.parentNode.parentNode.parentNode.parentNode;
    			// MediaWiki gallery
    			if (_isTag(gb,'li') && _isClass(gb,'gallerybox')) {
    				var t = gb.parentNode;
    				if (_isTag(t,'ul') && _isClass(t,'gallery')) {
    					a.blur();
    					_getCaption = _getCaptionMW;
    					_galleryData = $(t).find('div.thumb a.image');
    					_galleryIndex = _galleryData.index(a);
    					_showImage(a);
    					return false;
    				}
    			}
    			// Its generic thumbnail
    			a.blur();
    			_getCaption = _getCaptionEmpty;
    			_showImage(a);
    			return false;
    		/*} else if (_isTag(target,'a')) {
    			var sup = target.parentNode;
    			if (!_isTag(sup,'sup') || !_isClass(sup,'reference')) {
    				return true;
    			}
    			target.blur();
    			_showElement(target);
    			return false;*/
    		}
    		return true;
    	},
    	// Helper and speedy functions
    	_isClass = function(el, cn) {
    		return el.className && (el.className === cn || (' '+el.className+' ').indexOf(' '+cn+' ') != -1);
    	},
    	_isTag = function(el, tn) {
    		return (el.nodeName && el.nodeName.toUpperCase() === tn.toUpperCase());
    	},
    	// Loader image
    	_startLoader = function() {
    		if (_loaderPresent || _loaderTm) {
    			return;
    		}
    		if (_loaderWait > 0) {
    			_loaderTm = setTimeout(_displayLoader, _loaderWait);
    		} else {
    			_displayLoader();
    		}
    	},
    	_stopLoader = function() {
    		var t = _loaderTm;
    		_loaderTm = null;
    		if (t) {
    			clearTimeout(t);
    		}
    		if (_loaderPresent) {
    			$('#TB_load').remove();
    			_loaderPresent = false;
    		}
    	},
    	_displayLoader = function() {
    		_loaderPresent = true;
    		_loaderTm = null;
    		$(document.body).append('<div id="TB_load">');
    	},
    	// Main functions
    	_preload = function() {
    		$(document.body).addClass('thickbox_loaded');
    		$('#TB_overlay').add('#TB_window').add('#TB_load').remove();
    		$(document.body).append('<div id="TB_overlay"></div><div id="TB_window" class="fixedpos"></div>');
    		$('#TB_overlay').click(_remove);
    		_startLoader();
    	},
    	_showImage = function(elem) {
    		try {
    			var url, $a, $img, descUrl, TB_secondLine = '', TB_descLink;
    			_preload();
    			$a = $(elem);
    			$img = $a.find('> img').eq(0);
    
    			url = _getUrlFromThumb( $img.attr('src') );
    			descUrl = $a.attr('href');
    			if ($img.data('image-key')) {
    				// image-key is the name for the URL. Do not use image-name because it is encoded
    				descUrl = mw.util.wikiGetlink(mw.config.get('wgFormattedNamespaces')['6'] + ':' + decodeURIComponent($img.data('image-key')));
    			}
    			TB_descLink = '<a id="TB_descLink" class="sprite details" title="Go to the image\'s description page">File Page</a>';
    			// Is it a gallery?
    			if (_galleryIndex != -1) {
    				TB_secondLine = '<div id="TB_secondLine">'+
    					'<span id="TB_imageCount"></span>'+
    					'<span id="TB_prev"><a href="#" title="See previous image [Left arrow]"></a></span>'+
    					'<span id="TB_next"><a href="#" title="See next image [Right arrow]"></a></span></div>';
    			}
    			$('#TB_window').append('<div id="TB_closeWindow"><a href="#" id="TB_closeWindowButton" title="Close [ESC]">close</a></div>' +
    			'<div id="TB_ImageOff"><img id="TB_Image" alt="Image" title="Close" />' + TB_descLink + '</div>' + TB_secondLine + '<div id="TB_caption"></div>');
    			if (_galleryIndex != -1) {
    				_updateNavigation();
    			}
    			$('#TB_caption').html( ( _getCaption($a) || null ) );
    
    			$('#TB_Image').add('#TB_closeWindowButton').click(_remove);
    			$(document).on('keyup.thickbox', _keyListener);
    			$('#TB_prev').add('#TB_next').click(_navigate);
    			$('#TB_descLink').attr('href', descUrl);
    
    			if (_imgPreloader === null) {
    				_imgPreloader = new Image();
    			}
    			_imgPreloader.onload = _imageLoaded;
    			_imgPreloader.onerror = _imageError;
    			_imgPreloader.src = ''; // chromium bug 7731
    			if (url.length > 3 && url.substr(url.length - 4).toLowerCase() == '.svg') {
    				// For SVG we already know its aspect ratio, although not its original dimensions
    				// It would have to be done differently to load the SVG. Instead, here it is dynamically determined
    				// It is artificially enlarged, and then this function will reduce it to the maximum window size
    				_updateImageView($img.prop('width') * 1000, $img.prop('height') * 1000, url);
    			} else {
    				_imgPreloader.src = url;
    			}
    
    		} catch(e) {
    			_log(e);
    		}
    	},
    	_showElement = function(target) {
    		try {
    			var url = target.href, idx = url.indexOf('#');
    			if (idx == -1) {
    				return false;
    			}
    			var baseurl = url.substr(0, idx),
    				hash = decodeURIComponent(url.substr(idx + 1)),
    				// We check that the URL is from the same document
    				locbase = document.location.href.replace(baseurl, ''),
    				rel = document.getElementById(hash);
    			if ((locbase !== '' && locbase.indexOf('#') !== 0) || rel === null) {
    				return false;
    			}
    
    			$('#TB_overlay').add('#TB_window').remove();
    			$(document.body).append('<div id="TB_overlay" class="transparent"></div><div id="TB_window"></div>');
    			$('#TB_overlay').click(_remove);
    
    			var titleHTML = '<div id="TB_title"><div id="TB_closeAjaxWindow"><a href="#" id="TB_closeWindowButton" title="Close [ESC]">close</a></div></div>',
    				wnd = $('#TB_window'),
    				cel = $(rel).clone();
    			cel.contents().eq(0).remove();
    			cel.find('> sup').remove();
    			wnd.width(_minWidth).append(titleHTML+'<div id="TB_ajaxContent">'+cel.html()+'</div>');
    
    			var tgEl = $(target),
    				// horizontal space on each side of the element
    				elOffset = tgEl.offset(),
    				lw = elOffset.left,
    				rw = $(document).width() - elOffset.left - tgEl.width(),
    				// We calculate the optimal dimensions. We calculate the area and determine that the ideal is ratio 3/2
    				prefw = parseInt(Math.sqrt(wnd.width()*wnd.height()*3/2),10),
    				// Minimum width correction if scroll occurs
    				cd = $('#TB_ajaxContent')[0];
    			prefw += cd.scrollWidth-cd.clientWidth;
    			// The minimum width should not be reduced
    			if (prefw < _minWidth) {
    				prefw = _minWidth;
    			}
    			// Position. 5px of margin with respect to the origin. Ideal situation: to the right of the element
    			var margen = 5, left = $(document).width() - rw + margen;
    			if (rw > prefw + margen) {
    				// is already correct
    			} else if (lw > prefw + margen) {
    				left = lw - prefw - margen;
    			} else if (lw < 250 || rw < 250) { // It does not fit on either side. We look to see if the minimum width (250) cannot be used. In that case the width we force it and put it to the right
    				prefw = 250;
    			} else if (rw > lw) { // The available width of the major side is used
    				prefw = rw - margen;
    			} else {
    				prefw = lw - margen*2;
    				left = margen;
    			}
    			wnd.css({width: prefw, left: left});
    			// Now the vertical position. it needs that we have assigned the width to calculate it well
    			var top = elOffset.top - parseInt(wnd.height(), 10) - margen;
    			// If it does not fit above we place it below
    			if (top < margen) {
    				top = elOffset.top + tgEl.height() + margen;
    			}
    			wnd.css({top: top, visibility: 'visible'});
    			// Animation if it is outside the visual field
    			if (($('html')[0].scrollTop||$('body')[0].scrollTop) > top-margen) {
    				$('html,body').animate({scrollTop: top - margen}, 250, 'swing');
    			}
    
    			$('#TB_closeWindowButton').click(_remove);
    			$(document).on('keyup.thickbox', _keyListener);
    		} catch (e) {
    			_log(e);
    		}
    	},
    	//helper functions below
    	_displayClean = function() {
    		_stopLoader();
    		$('#TB_window').css('visibility','visible');
    	},
    	_remove = function() {
    		$(document).off('keyup.thickbox');
    		_galleryData = null;
    		_galleryIndex = -1;
    		if (_imgPreloader !== null) {
    			_imgPreloader.onload = null;
    			_imgPreloader.onerror = null;
    		}
    		$('#TB_ImageOff').add('#TB_Image').add('#TB_closeWindowButton').add('#TB_prev').add('#TB_next').off();
    		$('#TB_window').add('#TB_Image').queue('fx',[]).stop();
    		$('#TB_window').fadeOut('fast',function(){$('#TB_window').add('#TB_overlay').off().remove();});
    		_stopLoader();
    		$(document.body).removeClass('thickbox_loaded');
    		return false;
    	},
    	_keyListener = function(e) {
    		var keycode = e.which;
    		if (keycode == 27) { // close
    			_remove();
    		} else if (keycode == 37) { // 'Left arrow' display previous image
    			$('#TB_prev').click();
    		} else if (keycode == 39) { // 'Right arrow' display next image
    			$('#TB_next').click();
    		}
    	},
    	_position = function(anim) {
    		// Ancho mínimo
    		var border = 4;
    		if (_width < _minWidth) {
    			_width = _minWidth;
    		}
    		var o = {marginLeft: '-' + parseInt((_width / 2)+border,10).toString() + 'px', width: _width + 'px', marginTop: '-' + parseInt((_height / 2)+border,10).toString() + 'px'};
    		if (anim) {
    			$('#TB_window').animate(o, {queue: false, duration: 'fast'});
    		} else {
    			$('#TB_window').css(o);
    		}
    	},
    	_getPageSize = function() {
    		var de = document.documentElement,
    			w = window.innerWidth || (de&&de.clientWidth) || document.body.clientWidth,
    			h = window.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
    		return [w,h];
    	},
    	_getUrlFromThumb = function(thumb) {
    		if (thumb.indexOf('.svg/') != -1) {
    			return thumb;
    		}
    		// Wikia
    		//return thumb.replace(/\/revision\/latest\/scale-to-width(-down)?\/\d+/, '');
    		
    		// If the image is not thumb, or it is an SVG, we use the image as is.
    		if (thumb.indexOf('/thumb/') == -1 || thumb.indexOf('.svg/') != -1 ) {
    			return thumb;
    		}
    		var urlparts = thumb.split('/');
    		return thumb.replace('/thumb/','/').replace('/'+urlparts[urlparts.length-1], '');
    		
    	},
    	_getCaptionThumb = function(elem) {
    		return elem.closest('.thumbinner').find('> .thumbcaption').clone().find('> div.magnify').remove().end().html();
    	},
    	_getCaptionEmpty = function(elem) {
    		return $('<div>').text((elem.attr('title')||'')).html();
    	},
    	_getCaptionMW = function(gitem) {
    		return gitem.closest('li.gallerybox').find('div.gallerytext').eq(0).html();
    	},
    	_getCaptionWikia = function(gitem) {
    		return gitem.closest('div.wikia-gallery-item').find('> div.lightbox-caption').eq(0).html();
    	},
    	_imageError = function() {
    		_stopLoader();
    	},
    	_imageLoaded = function() {
    		_updateImageView(_imgPreloader.width, _imgPreloader.height, _imgPreloader.src);
    	},
    	_updateImageView = function(imageWidth, imageHeight, imageSrc) {
    		var navigation = (_galleryIndex != -1),
    			img = $('#TB_Image'),
    			wndH = $('#TB_window').height(),
    			// Resizing large images - orginal by Christian Montoya edited by me.
    			pagesize = _getPageSize(),
    			// Maximum dimensions
    			x = pagesize[0] - _minMarginWidth * 2 - _imageMarginWidth * 2,
    			y = pagesize[1] - _minMarginHeight * 2 - wndH + img.height(),
    			imageWidth = _imgPreloader.width,
    			imageHeight = _imgPreloader.height,
    			firstNav, imgOpt;
    		// You can enter by one or both. In fact, this check is enough, because if you have to go through both it does not matter which side is reduced first
    		if (imageWidth > x) {
    			imageHeight = imageHeight * (x / imageWidth);
    			imageWidth = x;
    		}
    		if (imageHeight > y) {
    			imageWidth = imageWidth * (y / imageHeight);
    			imageHeight = y;
    		}
    		// End Resizing
    
    		firstNav = (img.attr('src') || '') === '';
    		// Thickbox window dimensions to position
    		_width = imageWidth + _imageMarginWidth * 2; // 15px de espacio en cada lado
    		// We know the height of the window. Just replace the old image and put the new one, that is, its dimensions. The height has to be done differently because more elements are involved than in the width
    		_height = wndH - img.height() + imageHeight;
    		img.attr({
    			src: imageSrc,
    			alt: $('#TB_caption').text()
    		});
    
    		imgOpt = {width: imageWidth, height: imageHeight, opacity: 1};
    		// We look to see if it loads when opening or after browsing. If it comes from opening, without animation
    		if (firstNav) {
    			img.css(imgOpt);
    		} else {
    			img.animate(imgOpt, {duration: 'fast'});
    		}
    
    		_position(navigation && !firstNav);
    		_displayClean();
    	},
    	_updateNavigation = function() {
    		var seq = _galleryIndex, len = _galleryData.length;
    		$('#TB_prev').css('display', (seq === 0 ? 'none' : ''));
    		$('#TB_next').css('display', (seq >= len-1 ? 'none' : ''));
    		$('#TB_imageCount').text('Image ' + (seq+1) + ' of ' + len);
    	},
    	_navigate = function() {
    		var url, seq = _galleryIndex + (this.id == 'TB_prev' ? -1 : 1), len = _galleryData.length, gitem, $img;
    		if (seq < 0 || seq > len - 1) {
    			return false;
    		}
    		_galleryIndex = seq;
    		gitem = _galleryData.eq(seq);
    		url = _getUrlFromThumb(gitem.find('> img').eq(0).attr('src'));
    		_updateNavigation();
    		if (_imgPreloader.src != url) {
    			$('#TB_window').stop();
    			$('#TB_Image').queue('fx',[]).stop().animate({opacity: 0}, {duration: 'fast', complete: function() {
    				_startLoader();
    				if (url.length > 3 && url.substr(url.length - 4).toLowerCase() == '.svg') {
    					$img = gitem.find('> img').eq(0);
    			        	// For SVG we already know its aspect ratio, although not its original dimensions
    				        // It would have to be done differently to load the SVG. Instead, here it is dynamically determined
    				        // It is artificially enlarged, and then this function will reduce it to the maximum window size
    					_updateImageView($img.prop('width') * 1000, $img.prop('height') * 1000, url);
    					_imgPreloader.src = '';
    				} else {
    					_imgPreloader.src = url;
    				}
    			}});
    		}
    		// If the function does not find the item, it can return undefined, and in this case the content does not change. We force a null in that case
    		$('#TB_caption').html( ( _getCaption(gitem) || null ) );
    		$('#TB_descLink').attr('href',gitem.attr('href'));
    		return false;
    	},
    	_setParams = function(p) {
    		var val;
    		if (typeof p != 'object') {
    			return;
    		}
    		for (var n in p) {
    			if (p.hasOwnProperty(n)) {
    				val = p[n];
    				switch(n) {
    					case 'minWidth':
    						_minWidth = val;
    						break;
    					case 'imageMarginWidth':
    						_imageMarginWidth = val;
    						break;
    					case 'minMarginWidth':
    						_minMarginWidth = val;
    						break;
    					case 'minMarginHeight':
    						_minMarginHeight = val;
    						break;
    					case 'loaderWait':
    						_loaderWait = (typeof val == 'number' && val);
    						break;
    					case 'logger':
    						_logger = (typeof val == 'function' && val);
    						break;
    				}
    			}
    		}
    	},
    	_log = function(msg) {
    		if (_logger) {
    			_logger(msg);
    		}
    	},
    	_imgTipEvent = function(e) {
    		var target = e.target, a, t;
    		if (e.ctrlKey || e.altKey || e.shiftKey) {
    			_hideImgTip();
    			return;
    		}
    		if (_isTag(target,'img')) { // Gallery o thumb
    			a = target.parentNode;
    			if (!_isTag(a,'a') || !_isClass(a,'image') || _isClass(a,'link-internal')) {
    				_hideImgTip();
    				return;
    			}
    			t = $(target);
    			// We show only if the image has a minimum size
    			if (t.width() < 40 || t.height() < 40) {
    				return;
    			}
    			_showImgTip(t);
    			return;
    		}
    		_hideImgTip();
    	},
    	_imgTipClickEvent = function() {
    		if (_imgTipTarget) {
    			$(_imgTipTarget).click();
    			return false;
    		}
    	},
    	_createImgTip = function() {
    		_imgTip = $('<div id="TB_imagetip" title="Click on the image to enlarge. Click with Ctrl or Shift to go to the file page.">').appendTo(document.body);
    		_imgTip.on('click',_imgTipClickEvent);
    	},
    	_showImgTip = function(target) {
    		if (!_imgTip) {
    			_createImgTip();
    		}
    		var of = target.offset();
    		_imgTip.css({
    			display: 'block',
    			left: of.left + target.width(),
    			top: of.top
    		});
    		_imgTipVisible = true;
    		_imgTipTarget = target;
    	},
    	_hideImgTip = function() {
    		if (_imgTipVisible) {
    			_imgTip.css('display','none');
    			_imgTipVisible = false;
    			_imgTipTarget = null;
    		}
    	};
    
    	// Public functions
    	return {
    		init: _init,
    		showImage: _showImage,
    		showElement: _showElement,
    		remove: _remove,
    		setParams: _setParams
    	};
    
    }(jQuery, mw));
    
    if (mw.config.get('wgAction', '') != 'history' || !(mw.config.get('wgNamespaceNumber', 0) == -1 && mw.config.get('wgCanonicalSpecialPageName', '') == 'Recentchanges')) {
    	$(window.Thickbox.init);
    }