MediaWiki:Gadget-Thickbox.js: Difference between revisions

    From Hokuto no Ken Encyclopedia | HnKWiki
     
    No edit summary
     
    (2 intermediate revisions by the same user not shown)
    Line 7: Line 7:
    'use strict';
    'use strict';
    var _version = '3.13',
    var _version = '3.13',
    // Dimensiones mínimas
    // Minimum dimensions
    _minWidth = 210,
    _minWidth = 210,
    // Margen entre la imagen y el borde de ThickBox
    // Margin between the image and the border of ThickBox
    _imageMarginWidth = 15,
    _imageMarginWidth = 15,
    // Margen mínimo hasta el borde de la ventana. Si se supera la imagen se reducirá
    // Minimum margin to the edge of the window. If the image is exceeded it will be reduced
    _minMarginWidth = 30,
    _minMarginWidth = 30,
    _minMarginHeight = 15,
    _minMarginHeight = 15,
    // Tiempo de espera para la aparición del loader en ms
    // Waiting time for the loader to appear in ms
    _loaderWait = 500,
    _loaderWait = 500,
    // Internos
    // Internal
    _imgPreloader = null,
    _imgPreloader = null,
    _galleryData = null,
    _galleryData = null,
    Line 29: Line 29:
    _loaderTm = null,
    _loaderTm = null,
    _logger = null,
    _logger = null,
    // Funciones privadas
    // Private methods
    _init = function() {
    _init = function() {
    // Se podría haber puesto un evento directamente en cada 'a.image', pero esto es mucho más rápido y eficiente (tarda solo el 20% en FF2) que recorrerse todo el DOM
    // We could have this event listener directly on 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({
    $('#mw-content-text').off('click.thickbox mouseover.thickbox_imgtip').on({
    'click.thickbox': _triggerEvent,
    'click.thickbox': _triggerEvent,
    Line 38: Line 38:
    },
    },
    _triggerEvent = function(e) {
    _triggerEvent = function(e) {
    // Si hay alguna tecla especial pulsada, salimos
    // If there is any special key pressed, we exit
    if (e.ctrlKey || e.altKey || e.shiftKey) {
    if (e.ctrlKey || e.altKey || e.shiftKey) {
    return true;
    return true;
    Line 45: Line 45:
    if (_isTag(target,'img')) { // Gallery o thumb
    if (_isTag(target,'img')) { // Gallery o thumb
    var a = target.parentNode;
    var a = target.parentNode;
    // Imágenes con enlaces a otros artículos no tienen la clase "image", excepto en Wikia donde sí la tiene y añaden "link-internal" o "link-external"
    // 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,'mw-file-description')) || _isClass(a, 'link-internal') || _isClass(a, 'link-external')) {
    if (!a || !_isTag(a,'a') || !(_isClass(a,'image') || _isClass(a,'mw-file-description')) || _isClass(a, 'link-internal') || _isClass(a, 'link-external')) {
    return true;
    return true;
    Line 78: Line 78:
    }
    }
    }
    }
    // Es thumb genérico
    // Is generic thumbnail
    a.blur();
    a.blur();
    _getCaption = _getCaptionEmpty;
    _getCaption = _getCaptionEmpty;
    Line 146: Line 146:
    descUrl = $a.attr('href');
    descUrl = $a.attr('href');
    if ($img.data('image-key')) {
    if ($img.data('image-key')) {
    // image-key es el nombre para la URL. No usar image-name porque está codificado doble (& --> &)
    // image-key is the name for the URL. So not use image-name because it's encoded (& --> &)
    descUrl = mw.util.wikiGetlink(mw.config.get('wgFormattedNamespaces')['6'] + ':' + decodeURIComponent($img.data('image-key')));
    descUrl = mw.util.wikiGetlink(mw.config.get('wgFormattedNamespaces')['6'] + ':' + decodeURIComponent($img.data('image-key')));
    }
    }
    TB_descLink = '<a id="TB_descLink" class="sprite details" title="Ir a la página de descripción de la imagen"></a>';
    TB_descLink = '<a id="TB_descLink" class="sprite details" title="Ir a la página de descripción de la imagen"></a>';
    // Se trata de un gallery?
    // Is it a gallery?
    if (_galleryIndex != -1) {
    if (_galleryIndex != -1) {
    TB_secondLine = '<div id="TB_secondLine">'+
    TB_secondLine = '<div id="TB_secondLine">'+
    '<span id="TB_imageCount"></span>'+
    '<span id="TB_imageCount"></span>'+
    '<span id="TB_prev"><a href="#" title="Ver imagen anterior [A]">&lt; Ant.</a></span>'+
    '<span id="TB_prev"><a href="#" title="See previous [A]">&lt; Prev.</a></span>'+
    '<span id="TB_next"><a href="#" title="Ver imagen siguiente [S]">Sig. &gt;</a></span></div>';
    '<span id="TB_next"><a href="#" title="See next [S]">Next. &gt;</a></span></div>';
    }
    }
    $('#TB_window').append('<div id="TB_closeWindow"><a href="#" id="TB_closeWindowButton" title="Cerrar [ESC]">cerrar</a></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="Imagen" title="Cerrar" />' + TB_descLink + '</div>' + TB_secondLine + '<div id="TB_caption"></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) {
    if (_galleryIndex != -1) {
    _updateNavigation();
    _updateNavigation();
    Line 184: Line 184:
    _imgPreloader.src = ''; // chromium bug 7731
    _imgPreloader.src = ''; // chromium bug 7731
    if (url.length > 3 && url.substr(url.length - 4).toLowerCase() == '.svg') {
    if (url.length > 3 && url.substr(url.length - 4).toLowerCase() == '.svg') {
    // Para SVG ya conocemos su relación de aspecto, aunque no sus dimensiones originales
    // For SVG we already know its aspect ratio, although not its original dimensions
    // Habría que hacerlo diferente para cargar el SVG. En su lugar, aquí se determina dinámicamente
    // It would have to be done differently to load the SVG. Instead, here it is dynamically determined
    // Se agranda artificialmente, y luego esta función lo reducirá al tamaño máximo de la ventana
    // 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);
    _updateImageView($img.prop('width') * 1000, $img.prop('height') * 1000, url);
    } else {
    } else {
    Line 203: Line 203:
    var baseurl = url.substr(0, idx),
    var baseurl = url.substr(0, idx),
    hash = decodeURIComponent(url.substr(idx + 1)),
    hash = decodeURIComponent(url.substr(idx + 1)),
    // Comprobamos que la URL sea del mismo documento
    // Check that the URL is from the same document
    locbase = document.location.href.replace(baseurl, ''),
    locbase = document.location.href.replace(baseurl, ''),
    rel = document.getElementById(hash);
    rel = document.getElementById(hash);
    Line 214: Line 214:
    $('#TB_overlay').click(_remove);
    $('#TB_overlay').click(_remove);


    var titleHTML = '<div id="TB_title"><div id="TB_closeAjaxWindow"><a href="#" id="TB_closeWindowButton" title="Cerrar [ESC]">cerrar</a></div></div>',
    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'),
    wnd = $('#TB_window'),
    cel = $(rel).clone();
    cel = $(rel).clone();
    Line 222: Line 222:


    var tgEl = $(target),
    var tgEl = $(target),
    // espacio horizontal a cada lado del elemento
    // horizontal space on each side of the element
    elOffset = tgEl.offset(),
    elOffset = tgEl.offset(),
    lw = elOffset.left,
    lw = elOffset.left,
    rw = $(document).width() - elOffset.left - tgEl.width(),
    rw = $(document).width() - elOffset.left - tgEl.width(),
    // Calculamos las dimensiones óptimas. Calculamos el área y determinamos que lo ideal es proporción 3/2
    // Calculating the optimal dimensions. Calculating the area and determine that the ideal is ratio 3/2
    prefw = parseInt(Math.sqrt(wnd.width()*wnd.height()*3/2),10),
    prefw = parseInt(Math.sqrt(wnd.width()*wnd.height()*3/2),10),
    // Corrección de ancho mínimo en caso de producirse scroll
    // Minimum width correction if scroll occurs
    cd = $('#TB_ajaxContent')[0];
    cd = $('#TB_ajaxContent')[0];
    prefw += cd.scrollWidth-cd.clientWidth;
    prefw += cd.scrollWidth-cd.clientWidth;
    // No se debe reducir el ancho mínimo
    // Should not go below minimum
    if (prefw < _minWidth) {
    if (prefw < _minWidth) {
    prefw = _minWidth;
    prefw = _minWidth;
    }
    }
    // Posición. 5px de margen respecto el origen. Situación ideal: a la derecha del elemento
    // 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;
    var margen = 5, left = $(document).width() - rw + margen;
    if (rw > prefw + margen) {
    if (rw > prefw + margen) {
    // ya es correcto
    // is already correct
    } else if (lw > prefw + margen) {
    } else if (lw > prefw + margen) {
    left = lw - prefw - margen;
    left = lw - prefw - margen;
    } else if (lw < 250 || rw < 250) { // No cabe en ninguno de los dos lados. Miramos si no puede usarse el ancho mínimo (250). En ese caso el ancho lo forzamos y lo ponemos a la derecha
    } 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;
    prefw = 250;
    } else if (rw > lw) { // Se usa el ancho disponible del lado mayor
    } else if (rw > lw) { // Using the width of the larger side
    prefw = rw - margen;
    prefw = rw - margen;
    } else {
    } else {
    Line 250: Line 250:
    }
    }
    wnd.css({width: prefw, left: left});
    wnd.css({width: prefw, left: left});
    // Ahora la posición vertical. necesita que hayamos asignado el width para que lo calcule bien
    // Now the vertical position. Width needs to be assigned in order to calculate correctly.
    var top = elOffset.top - parseInt(wnd.height(), 10) - margen;
    var top = elOffset.top - parseInt(wnd.height(), 10) - margen;
    // Si no cabe arriba lo colocamos debajo
    // If it does not fit above we place it below
    if (top < margen) {
    if (top < margen) {
    top = elOffset.top + tgEl.height() + margen;
    top = elOffset.top + tgEl.height() + margen;
    }
    }
    wnd.css({top: top, visibility: 'visible'});
    wnd.css({top: top, visibility: 'visible'});
    // Animación si queda fuera del campo visual
    // Animation if it is outside the visual field
    if (($('html')[0].scrollTop||$('body')[0].scrollTop) > top-margen) {
    if (($('html')[0].scrollTop||$('body')[0].scrollTop) > top-margen) {
    $('html,body').animate({scrollTop: top - margen}, 250, 'swing');
    $('html,body').animate({scrollTop: top - margen}, 250, 'swing');
    Line 324: Line 324:
    //return thumb.replace(/\/revision\/latest\/scale-to-width(-down)?\/\d+/, '');
    //return thumb.replace(/\/revision\/latest\/scale-to-width(-down)?\/\d+/, '');
    // Si la imagen no es thumb, o bien es un SVG, usamos la imagen tal cual.
    // 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 ) {
    if (thumb.indexOf('/thumb/') == -1 || thumb.indexOf('.svg/') != -1 ) {
    return thumb;
    return thumb;
    Line 359: Line 359:
    // Resizing large images - orginal by Christian Montoya edited by me.
    // Resizing large images - orginal by Christian Montoya edited by me.
    pagesize = _getPageSize(),
    pagesize = _getPageSize(),
    // Dimensiones máximas
    // Maximum dimensions
    x = pagesize[0] - _minMarginWidth * 2 - _imageMarginWidth * 2,
    x = pagesize[0] - _minMarginWidth * 2 - _imageMarginWidth * 2,
    y = pagesize[1] - _minMarginHeight * 2 - wndH + img.height(),
    y = pagesize[1] - _minMarginHeight * 2 - wndH + img.height(),
    firstNav, imgOpt;
    firstNav, imgOpt;
    // Puede entrar por una o por las dos. De hecho, con esta comprobación basta, ya que si tiene que pasar por las dos da igual por qué lado se reduzca primero
    // 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) {
    if (imageWidth > x) {
    imageHeight = imageHeight * (x / imageWidth);
    imageHeight = imageHeight * (x / imageWidth);
    Line 375: Line 375:


    firstNav = (img.attr('src') || '') === '';
    firstNav = (img.attr('src') || '') === '';
    // Dimensiones de la ventana Thickbox para posicionar
    // Thickbox window dimensions for positioning
    _width = imageWidth + _imageMarginWidth * 2; // 15px de espacio en cada lado
    _width = imageWidth + _imageMarginWidth * 2; // 15px gap on both sides
    // La altura de la ventana la conocemos. Solo hay que reemplazar la imagen antigua y poner la nueva, esto es, sus dimensiones. El height se tiene que hacer diferente porque intervienen más elementos que en el ancho
    // 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;
    _height = wndH - img.height() + imageHeight;
    img.attr({
    img.attr({
    Line 385: Line 385:


    imgOpt = {width: imageWidth, height: imageHeight, opacity: 1};
    imgOpt = {width: imageWidth, height: imageHeight, opacity: 1};
    // Miramos si se carga al abrir o después de navegar. Si viene de abrirse, sin animación
    // We look to see if it loads when opening or after browsing. If it comes from opening, skip animation
    if (firstNav) {
    if (firstNav) {
    img.css(imgOpt);
    img.css(imgOpt);
    Line 399: Line 399:
    $('#TB_prev').css('display', (seq === 0 ? 'none' : ''));
    $('#TB_prev').css('display', (seq === 0 ? 'none' : ''));
    $('#TB_next').css('display', (seq >= len-1 ? 'none' : ''));
    $('#TB_next').css('display', (seq >= len-1 ? 'none' : ''));
    $('#TB_imageCount').text('Imagen ' + (seq+1) + ' de ' + len);
    $('#TB_imageCount').text('Image ' + (seq+1) + ' of ' + len);
    },
    },
    _navigate = function() {
    _navigate = function() {
    Line 416: Line 416:
    if (url.length > 3 && url.substr(url.length - 4).toLowerCase() == '.svg') {
    if (url.length > 3 && url.substr(url.length - 4).toLowerCase() == '.svg') {
    $img = gitem.find('> img').eq(0);
    $img = gitem.find('> img').eq(0);
    // Para SVG ya conocemos su relación de aspecto, aunque no sus dimensiones originales
    // For SVG we already know its aspect ratio, although not its original dimensions
    // Habría que hacerlo diferente para cargar el SVG. En su lugar, aquí se determina dinámicamente
    // It would have to be done differently to load the SVG. Instead, here it is dynamically determined
    // Se agranda artificialmente, y luego esta función lo reducirá al tamaño máximo de la ventana
    // 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);
    _updateImageView($img.prop('width') * 1000, $img.prop('height') * 1000, url);
    _imgPreloader.src = '';
    _imgPreloader.src = '';
    Line 426: Line 426:
    }});
    }});
    }
    }
    // Si la función no encuentra el elemento, puede devolver undefined, y en este caso no cambia el contenido. Forzamos un null en ese caso
    // 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_caption').html( ( _getCaption(gitem) || null ) );
    $('#TB_descLink').attr('href',gitem.attr('href'));
    $('#TB_descLink').attr('href',gitem.attr('href'));
    Line 473: Line 473:
    return;
    return;
    }
    }
    if (_isTag(target,'img')) { // Gallery o thumb
    if (_isTag(target,'img')) { // Gallery or thumb
    a = target.parentNode;
    a = target.parentNode;
    if (!_isTag(a,'a') || !(_isClass(a,'image') || _isClass(a,'mw-file-description')) || _isClass(a,'link-internal')) {
    if (!_isTag(a,'a') || !(_isClass(a,'image') || _isClass(a,'mw-file-description')) || _isClass(a,'link-internal')) {
    Line 480: Line 480:
    }
    }
    t = $(target);
    t = $(target);
    // Mostramos solo si la imagen tiene un tamaño mínimo
    // We show only if the image has a minimum size
    if (t.width() < 40 || t.height() < 40) {
    if (t.width() < 40 || t.height() < 40) {
    return;
    return;
    Line 496: Line 496:
    },
    },
    _createImgTip = function() {
    _createImgTip = function() {
    _imgTip = $('<div id="TB_imagetip" title="Clic sobre la imagen para ampliar. Ctrl, Alt o Mayús. para acceder a la página de descripción de la imagen.">').appendTo(document.body);
    _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);
    _imgTip.on('click',_imgTipClickEvent);
    },
    },
    Line 534: Line 534:
    $(window.Thickbox.init);
    $(window.Thickbox.init);
    }
    }
    /* </pre> */

    Latest revision as of 09:24, 18 December 2023

    /* <pre>
     * Thickbox4MediaWiki v3.13 - Based on Thickbox 3.1 By Cody Lindley (http://www.codylindley.com)
     * Copyright (c) 2010 - 2023 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.13',
    	// 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 methods
    	_init = function() {
    		// We could have this event listener directly on 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,'mw-file-description')) || _isClass(a, 'link-internal') || _isClass(a, 'link-external')) {
    				return true;
    			}
    			// MW < 1.40
    			if (_isClass(target,'thumbimage')) {
    				// Es thumb
    				a.blur();
    				_getCaption = _getCaptionThumb;
    				_showImage(a);
    				return false;
    			}
    			// MW >= 1.40
    			if (_isTag(a.parentNode,'figure')) {
    				// Es thumb
    				a.blur();
    				_getCaption = _getCaptionThumb140;
    				_showImage(a);
    				return false;
    			}
    			var gb = $(a).closest('li.gallerybox').get(0);
    			// MediaWiki gallery
    			if (gb) {
    				var t = gb.parentNode;
    				if (_isTag(t,'ul') && _isClass(t,'gallery')) {
    					a.blur();
    					_getCaption = _getCaptionMW;
    					_galleryData = $(t).find('div.thumb a.image,div.thumb a.mw-file-description'); // MW<1.40,MW>=1.40
    					_galleryIndex = _galleryData.index(a);
    					_showImage(a);
    					return false;
    				}
    			}
    			// Is 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. So not use image-name because it's encoded (& --> &amp;amp;)
    				descUrl = mw.util.wikiGetlink(mw.config.get('wgFormattedNamespaces')['6'] + ':' + decodeURIComponent($img.data('image-key')));
    			}
    			TB_descLink = '<a id="TB_descLink" class="sprite details" title="Ir a la página de descripción de la imagen"></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 [A]">&lt; Prev.</a></span>'+
    					'<span id="TB_next"><a href="#" title="See next [S]">Next. &gt;</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);
    			$('#TB_ImageOff').on({
    				mouseover: function() {
    					$('#TB_descLink').css('display','block');
    				},
    				mouseout: function() {
    					$('#TB_descLink').css('display','none');
    				}
    			});
    
    			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)),
    				// 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(),
    				// Calculating the optimal dimensions. Calculating 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;
    			// Should not go below minimum
    			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) { // Using the width of the larger side
    				prefw = rw - margen;
    			} else {
    				prefw = lw - margen*2;
    				left = margen;
    			}
    			wnd.css({width: prefw, left: left});
    			// Now the vertical position. Width needs to be assigned in order to calculate correctly.
    			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 == 65) { // 'A' display previous image
    			$('#TB_prev').click();
    		} else if (keycode == 83) { // 'S' 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();
    	},
    	_getCaptionThumb140 = function(elem) {
    		return elem.closest('figure').find('> figcaption').clone().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(),
    			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 for positioning
    		_width = imageWidth + _imageMarginWidth * 2; // 15px gap on both sides
    		// 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, skip 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 or thumb
    			a = target.parentNode;
    			if (!_isTag(a,'a') || !(_isClass(a,'image') || _isClass(a,'mw-file-description')) || _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 + target.height()
    		});
    		_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);
    }