MediaWiki:Gadget-Thickbox.js: Difference between revisions

    From Hokuto no Ken Encyclopedia | HnKWiki
     
    No edit summary
    Line 1: Line 1:
    /* <pre>
    /*
      * Thickbox4MediaWiki v3.13 - Based on Thickbox 3.1 By Cody Lindley (http://www.codylindley.com)
      * Thickbox4MediaWiki v3.12 - 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
      * 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
      * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
    */
    */
    window.Thickbox = (function($, mw) {
    window.Thickbox = (function($, mw) {
    'use strict';
    'use strict';
    var _version = '3.13',
    var _version = '3.12',
    // 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 functions
    _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
    // 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({
    $('#mw-content-text').off('click.thickbox mouseover.thickbox_imgtip').on({
    'click.thickbox': _triggerEvent,
    'click.thickbox': _triggerEvent,
    Line 38: Line 41:
    },
    },
    _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 48:
    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, 'link-internal') || _isClass(a, 'link-external')) {
    return true;
    return true;
    }
    }
    // MW < 1.40
    // Wikia 2 Gallery
    if (_isClass(target,'thumbimage')) {
    if (_isClass(a,'lightbox')) {
    // Es thumb
    target.blur();
    a.blur();
    _getCaption = _getCaptionWikia;
    _getCaption = _getCaptionThumb;
    _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);
    _showImage(a);
    return false;
    return false;
    }
    }
    // MW >= 1.40
    if (_isClass(target,'thumbimage')) {
    if (_isTag(a.parentNode,'figure')) {
    // Its thumbnail
    // Es thumb
    a.blur();
    a.blur();
    _getCaption = _getCaptionThumb140;
    _getCaption = _getCaptionThumb;
    _showImage(a);
    _showImage(a);
    return false;
    return false;
    }
    }
    var gb = $(a).closest('li.gallerybox').get(0);
    var gb = a.parentNode.parentNode.parentNode.parentNode;
    // MediaWiki gallery
    // MediaWiki gallery
    if (gb) {
    if (_isTag(gb,'li') && _isClass(gb,'gallerybox')) {
    var t = gb.parentNode;
    var t = gb.parentNode;
    if (_isTag(t,'ul') && _isClass(t,'gallery')) {
    if (_isTag(t,'ul') && _isClass(t,'gallery')) {
    a.blur();
    a.blur();
    _getCaption = _getCaptionMW;
    _getCaption = _getCaptionMW;
    _galleryData = $(t).find('div.thumb a.image,div.thumb a.mw-file-description'); // MW<1.40,MW>=1.40
    _galleryData = $(t).find('div.thumb a.image');
    _galleryIndex = _galleryData.index(a);
    _galleryIndex = _galleryData.index(a);
    _showImage(a);
    _showImage(a);
    Line 78: Line 87:
    }
    }
    }
    }
    // Es thumb genérico
    // Its generic thumbnail
    a.blur();
    a.blur();
    _getCaption = _getCaptionEmpty;
    _getCaption = _getCaptionEmpty;
    _showImage(a);
    _showImage(a);
    return false;
    return false;
    } else if (_isTag(target,'a')) {
    /*} else if (_isTag(target,'a')) {
    var sup = target.parentNode;
    var sup = target.parentNode;
    if (!_isTag(sup,'sup') || !_isClass(sup,'reference')) {
    if (!_isTag(sup,'sup') || !_isClass(sup,'reference')) {
    Line 90: Line 99:
    target.blur();
    target.blur();
    _showElement(target);
    _showElement(target);
    return false;
    return false;*/
    }
    }
    return true;
    return true;
    Line 146: Line 155:
    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 (& --> &amp;amp;)
    // 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')));
    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="Go to the image\'s description page">File Page</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 image [Left arrow]"></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 image [Right arrow]"></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 168: Line 177:
    $('#TB_prev').add('#TB_next').click(_navigate);
    $('#TB_prev').add('#TB_next').click(_navigate);
    $('#TB_descLink').attr('href', descUrl);
    $('#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) {
    if (_imgPreloader === null) {
    Line 184: Line 185:
    _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 {
    _imgPreloader.src = url;
    _imgPreloader.src = url;
    }
    }
    } catch(e) {
    } catch(e) {
    _log(e);
    _log(e);
    Line 203: Line 205:
    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
    // We 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 216:
    $('#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 224:


    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
    // 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),
    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
    // The minimum width should not be reduced
    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) { // The available width of the major side is used
    prefw = rw - margen;
    prefw = rw - margen;
    } else {
    } else {
    Line 250: Line 252:
    }
    }
    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. it needs that we have assigned the width to calculate it well
    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 292: Line 294:
    if (keycode == 27) { // close
    if (keycode == 27) { // close
    _remove();
    _remove();
    } else if (keycode == 65) { // 'A' display previous image
    } else if (keycode == 37) { // 'Left arrow' display previous image
    $('#TB_prev').click();
    $('#TB_prev').click();
    } else if (keycode == 83) { // 'S' display next image
    } else if (keycode == 39) { // 'Right arrow' display next image
    $('#TB_next').click();
    $('#TB_next').click();
    }
    }
    Line 324: Line 326:
    //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 334: Line 336:
    _getCaptionThumb = function(elem) {
    _getCaptionThumb = function(elem) {
    return elem.closest('.thumbinner').find('> .thumbcaption').clone().find('> div.magnify').remove().end().html();
    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) {
    _getCaptionEmpty = function(elem) {
    Line 359: Line 358:
    // 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(),
    imageWidth = _imgPreloader.width,
    imageHeight = _imgPreloader.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 376:


    firstNav = (img.attr('src') || '') === '';
    firstNav = (img.attr('src') || '') === '';
    // Dimensiones de la ventana Thickbox para posicionar
    // Thickbox window dimensions to position
    _width = imageWidth + _imageMarginWidth * 2; // 15px de espacio en cada lado
    _width = imageWidth + _imageMarginWidth * 2; // 15px de espacio en cada lado
    // 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 386:


    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, without animation
    if (firstNav) {
    if (firstNav) {
    img.css(imgOpt);
    img.css(imgOpt);
    Line 399: Line 400:
    $('#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 417:
    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 427:
    }});
    }});
    }
    }
    // 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 475: Line 476:
    if (_isTag(target,'img')) { // Gallery o thumb
    if (_isTag(target,'img')) { // Gallery o 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,'link-internal')) {
    _hideImgTip();
    _hideImgTip();
    return;
    return;
    }
    }
    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 497:
    },
    },
    _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 507: Line 508:
    display: 'block',
    display: 'block',
    left: of.left + target.width(),
    left: of.left + target.width(),
    top: of.top + target.height()
    top: of.top
    });
    });
    _imgTipVisible = true;
    _imgTipVisible = true;
    Line 534: Line 535:
    $(window.Thickbox.init);
    $(window.Thickbox.init);
    }
    }
    /* </pre> */

    Revision as of 08:56, 18 December 2023

    /*
     * 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);
    }