/*global mw, jQuery, GallerySlide, alert, prompt */
/*jshint bitwise: false, laxbreak: true, browser: true, onevar: false, nomen: false, smarttabs: true */
/**
* This is a derivative work of:
*/
/**
* jQuery Galleriffic plugin
*
* Copyright (c) 2008 Trent Foley (http://trentacular.com)
* Licensed under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* Much thanks to primary contributer Ponticlaro (http://www.ponticlaro.com)
*
*/
/**
* Rewritten for commons by [[User:DieBuche]],
* additional features by [[User:Rillke]]
* jshint valid
*/
(function($) {
if (typeof window.GallerySlide !== 'undefined' || mw.config.get('wgNamespaceNumber') < 0) {
return;
}
// Declare global variable so that it is no longer undefined,
// will be populated later from the document ready hook
window.GallerySlide = null;
// Globally keep track of all images by their unique hash. Each item is an image data object.
var isCategory = (mw.config.get('wgNamespaceNumber') === 14);
var isRtl = $('body').hasClass('rtl');
var allImages = {};
var imageCounter = 0;
// Galleriffic static class
$.galleriffic = {
version: '2.2',
// Strips invalid characters and any leading # characters
normalizeHash: function(hash) {
return hash.replace('#', '');
},
getImage: function(hash) {
if (!hash) {
return;
}
hash = $.galleriffic.normalizeHash(hash);
return allImages[hash];
},
// Global function that looks up an image by its hash and displays the image.
// Returns false when an image is not found for the specified hash.
// @param {String} hash This is the unique hash value assigned to an image.
gotoImage: function(hash) {
var imageData = $.galleriffic.getImage(hash);
if (!imageData) {
return false;
}
var gallery = imageData.gallery;
gallery.gotoImage(imageData);
return true;
}
};
var i18n;
var i18nStore = {
bn: {
delayInsertBtn: 'মিলিসেকেন্ডে বিলম্ব নির্ধারন করুন',
delayInsert: 'একটি নতুন চিত্রের জন্য কত মিলিসেকেন্ড অপেক্ষা করতে চান?',
delayInvalid: 'অকার্যকর ইনপুট। শুধুমাত্র 1500 থেকে বড় সংখ্যা গৃহীত হয়।',
playLinkText: 'চালান',
pauseLinkText: 'বিরতি',
prevLinkText: 'পূর্ববর্তী',
nextLinkText: 'পরবর্তী',
hideText: 'স্লাইডশো বন্ধ করুন',
continueKeyHowTo: 'অবিরত-চাবি - আপনি যদি পরে এই অবস্থান থেকে আরম্ভ করতে চান তাহলে, আপনি এই চাবি সংরক্ষণ বা লিঙ্ক বুকমার্ক করতে পারেন।',
continueKeyInsert: 'দয়া করে অবিরত-চাবি প্রবেশ করান। প্রভাব দেখতে আপনাকে স্লাইডশোতে এগিয়ে যেতে হবে।',
continueKeyInsertBtn: 'অবিরত-চাবি প্রবেশ করান',
continueKeyInvalid: 'অকার্যকর চাবি।',
licenseLabel: 'উপলভ্য লাইসেন্স: ',
uploaderLabel: 'আপলোডকারী ',
helpLinkTitle: 'এই সরঞ্জামের জন্য সাহায্য এবং নথিপত্র',
descriptionLoadText: 'বিবরণ লোড হচ্ছে ...'
},
ca: {
delayInsertBtn: 'Canvia el temps de demora',
delayInsert: 'Demora en milisegons entre cada imatge',
delayInvalid: 'Entrada no vàlida. Només s’accepten números superiors a 1500.',
playLinkText: 'Reprodueix',
pauseLinkText: 'Pausa',
prevLinkText: 'Anterior',
nextLinkText: 'Següent',
hideText: 'Tanca la presentació',
continueKeyHowTo: 'Clau de represa - Podeu desar aquesta clau o afegir l’enllaç en les adreces d’interès si més endavant voleu començar des d’aquesta posició.',
continueKeyInsert: 'Afegiu la clau de represa. Heu d’anar endavant en la presentació per constatar el canvi.',
continueKeyInsertBtn: 'Afegeix la clau de represa',
continueKeyInvalid: 'Clau invàlida.',
licenseLabel: 'Llicències disponibles: ',
uploaderLabel: 'Usuari ',
helpLinkTitle: 'Ajuda i documentació d’aquesta eina',
descriptionLoadText: 'Carregant la descripció ...'
},
cs: {
delayInsertBtn: 'Nastavit prodlevu v ms',
delayInsert: 'Kolik milisekund se má čekat na další obrázek?',
delayInvalid: 'Chybné zadání. Povolena jsou pouze čísla větší než 1500.',
playLinkText: 'Spustit',
pauseLinkText: 'Pozastavit',
prevLinkText: 'Předchozí',
nextLinkText: 'Následující',
hideText: 'Zavřít prezentaci',
continueKeyHowTo: 'Klíč pro pokračování – můžete si uschovat tento klíč nebo si do oblíbených uložit odkaz, pokud budete později pokračovat od této pozice.',
continueKeyInsert: 'Vložte prosím klíč pro pokračování. Abyste viděli výsledek, musíte pak v prezentaci přejít na další snímek.',
continueKeyInsertBtn: 'Vložte klíč pro pokračování',
continueKeyInvalid: 'Neplatný klíč.',
licenseLabel: 'Dostupné licence: ',
uploaderLabel: 'Načetl(a) ',
helpLinkTitle: 'Nápověda a dokumentace k tomuto nástroji',
descriptionLoadText: 'Načítá se popis'
},
en: {
delayInsertBtn: 'Set delay in ms',
delayInsert: 'How many ms to wait for a new image?',
delayInvalid: 'Invalid input. Only numbers greater than 1500 are accepted.',
playLinkText: 'Play',
pauseLinkText: 'Pause',
prevLinkText: 'Previous',
nextLinkText: 'Next',
hideText: 'Close slideshow',
continueKeyHowTo: 'Continue Key - You can save this key or bookmark the link if you\'d like to start at this position later.',
continueKeyInsert: 'Please insert the continue-key. You have to go forward in the slideshow to see effect.',
continueKeyInsertBtn: 'Insert continue-key',
continueKeyInvalid: 'Invalid key.',
licenseLabel: 'Available Licenses: ',
uploaderLabel: 'Uploader ',
helpLinkTitle: 'Help and documentation for this tool',
descriptionLoadText: 'Loading description ...'
},
es: {
delayInsertBtn: 'Fijar el atraso en milisegundos',
delayInsert: '¿Cuántos milisegundos queres esperar hasta que aparezca la nueva imagen?',
delayInvalid: 'Entrada no válida. Solo se aceptan los números mayores que 1500.',
playLinkText: 'Reproducir',
pauseLinkText: 'Pausar',
prevLinkText: 'Anterior',
nextLinkText: 'Siguiente',
hideText: 'Cerrar la presentación',
continueKeyHowTo: 'Clave de continuación: Puedes guardar esta clave o añadir el enlace a los favoritos si quieres empezar la presentación desde este punto en otro momento.',
continueKeyInsert: 'Agregue la clave para reiniciar. Tienes que seguir la presentación para comprobar los cambios.',
continueKeyInsertBtn: 'Introducir una clave de continuación',
continueKeyInvalid: 'Clave no válida.',
licenseLabel: 'Licencias disponibles: ',
uploaderLabel: 'Persona que subió la foto',
helpLinkTitle: 'Ayuda y documentación de esta herramienta',
descriptionLoadText: 'Cargando la descripción...'
},
fa: {
delayInsertBtn: 'تنظیم تأخیر در میلی\u200cثانیه',
delayInsert: 'چقدر میلی\u200cثانیه تأخبر برای تصویر جدید؟',
delayInvalid: 'ورودی نادرست. فقط اعداد بزرگتر از ۱۵۰۰ قبول هستند.',
playLinkText: 'پخش',
pauseLinkText: 'توقف',
prevLinkText: 'قبلی',
nextLinkText: 'بعدی',
hideText: 'بستن اسلایدشو',
continueKeyHowTo: 'کلید ادامه - شما می\u200cتوانید این کلید را ذخیره یا بوک\u200cمارک کنید پیوندش را اگر می\u200cخواهید بعداً از این مکان شروع کنید.',
continueKeyInsert: 'لطفاً کلید ادامه را فشار دهید. شما باید در اسلایدشو جلو بروید یا اثرش را ببینید.',
continueKeyInsertBtn: 'قراردادن کلید ادامه',
continueKeyInvalid: 'کلید نادرست.',
licenseLabel: 'مجوزهای موجود: ',
uploaderLabel: 'بارگذار ',
helpLinkTitle: 'کمک و مستندات این ابزار',
descriptionLoadText: 'بارگیری توضیحات ...'
},
fr: {
delayInsertBtn: 'Définir l’intervalle de temps',
delayInsert: 'Combien de millisecondes entre chaque image ?',
delayInvalid: 'Entrée invalide. Seuls les nombres supérieurs à 1500 sont acceptés.',
playLinkText: 'Lire',
pauseLinkText: 'Pause',
prevLinkText: 'Précédent',
nextLinkText: 'Suivant',
hideText: 'Quitter le diaporama',
continueKeyHowTo: 'Clé de départ - Vous pouvez sauvegarder cette clé ou mettre en marque-page le lien si vous souhaitez commencer à cette position plus tard.',
continueKeyInsert: 'Veuillez insérer la clé de départ. Vous devez faire défiler le diaporama pour constater un changement.',
continueKeyInsertBtn: 'Insérer la clé de départ',
continueKeyInvalid: 'Clé invalide',
licenseLabel: 'Licences disponibles : ',
uploaderLabel: 'La personne qui a téléversé le fichier sur le serveur ',
helpLinkTitle: 'Aide et documentation de cet outil',
descriptionLoadText: 'Chargement de la description ...'
},
gl: {
delayInsertBtn: 'Fixar o atraso en milisegundos',
delayInsert: 'Cantos milisegundos queres agardar ata que apareza unha nova imaxe?',
delayInvalid: 'Entrada non válida. Só se aceptan os números maiores que 1500.',
playLinkText: 'Reproducir',
pauseLinkText: 'Pausar',
prevLinkText: 'Anterior',
nextLinkText: 'Seguinte',
hideText: 'Pechar a presentación',
continueKeyHowTo: 'Clave de continuación: Podes gardar esta clave ou engadir a ligazón aos marcadores se queres comezar a presentación desde este punto noutro momento.',
continueKeyInsert: 'Escribe a clave de continuación. Tes que avanzar na presentación para comprobar os cambios.',
continueKeyInsertBtn: 'Inserir unha clave de continuación',
continueKeyInvalid: 'Clave non válida.',
licenseLabel: 'Licenzas dispoñibles: ',
uploaderLabel: 'Persoa que cargou a imaxe ',
helpLinkTitle: 'Axuda e documentación desta ferramenta',
descriptionLoadText: 'Cargando a descrición...'
},
hr: {
delayInsertBtn: 'Kašnjenje u milisekundama',
delayInsert: 'Čekanje u milisekundama na novu sliku.',
delayInvalid: 'Krivi unos. Broj mora biti veći od 1500.',
playLinkText: 'Pokreni',
pauseLinkText: 'Stanka',
prevLinkText: 'Prethodna',
nextLinkText: 'Sljedeća',
hideText: 'Zatvori prezentaciju',
continueKeyHowTo: 'Ključ za nastavak: možete ga spremiti ili zabilježiti poveznicu da biste naknadno nastavili prezentaciju od ove slike.',
continueKeyInsert: 'Unesite ključ za nastavak. Da biste vidjeli promjenu, morate nastaviti s prezentacijom.',
continueKeyInsertBtn: 'Unesite ključ za nastavak',
continueKeyInvalid: 'Nevaljali ključ.',
licenseLabel: 'Dostupne licencije: ',
uploaderLabel: 'Postavio ',
helpLinkTitle: 'Pomoć i dokumentacija ovog alata',
descriptionLoadText: 'Učitavanje opisa ...'
},
it: {
delayInsertBtn: 'Imposta l\'intervallo di tempo (in millisecondi)',
delayInsert: 'Quanti millisecondi bisogna attendere prima che appaia una nuova immagine?',
delayInvalid: 'Inserimento non valido. Solo i numeri maggiori di 1500 sono accettati.',
playLinkText: 'Riproduci',
pauseLinkText: 'Pausa',
prevLinkText: 'Precedente',
nextLinkText: 'Successiva',
hideText: 'Chiudi presentazione',
licenseLabel: 'Licenze disponibili: ',
uploaderLabel: 'Caricatore ',
helpLinkTitle: 'Aiuto e documentazione per questo strumento',
descriptionLoadText: 'Caricamento descrizione...'
},
mk: {
delayInsertBtn: 'Задај задршка во милисек.',
delayInsert: 'Колку милисек. да се чека за нова слика?',
delayInvalid: 'Погрешен внос. Се допуштаат само броеви поголеми од 1500.',
playLinkText: 'Пушти',
pauseLinkText: 'Запри',
prevLinkText: 'Претходна',
nextLinkText: 'Следна',
hideText: 'Затвори',
continueKeyHowTo: 'Клуч за продолжување — Можете да го зачувате овој клуч или да ја ставите врската во одбележани доколку сакате подоцна да продолжите од ова исто место.',
continueKeyInsert: 'Внесете го клучот за продолжување. Ќе треба да отидете напред во сликоредот за да го видите ефектот.',
continueKeyInsertBtn: 'Внесете клуч за продолжување',
continueKeyInvalid: 'Погрешен клуч.',
licenseLabel: 'Расположливи лиценци: ',
uploaderLabel: 'Подигач ',
helpLinkTitle: 'Помош и документација за алаткава',
descriptionLoadText: 'Го вчитувам описот ...'
},
ml: {
delayInsertBtn: 'കാലതാമസം മില്ലിസെക്കന്റിൽ',
delayInsert: 'പുതിയ ചിത്രത്തിനായി എത്ര മില്ലിസെക്കന്റുകൾ കാത്തിരിക്കേണ്ടതുണ്ട്?',
delayInvalid: 'നൽകിയ വില അസാധുവാണ്. 1500-നു മുകളിലുള്ള സംഖ്യകൾ മാത്രമേ സ്വീകരിക്കാനാകൂ.',
playLinkText: 'പ്രവർത്തിപ്പിക്കുക',
pauseLinkText: 'ഇടയ്ക്കുനിർത്തുക',
prevLinkText: 'മുൻപത്തേത്',
nextLinkText: 'അടുത്തത്',
hideText: 'സ്ലൈഡ്ഷോ അടയ്ക്കുക',
continueKeyHowTo: 'തുടർച്ചാ ചാവി - ഈ സ്ഥാനത്തുനിന്ന് പിന്നീട് തുടങ്ങണമെന്നുണ്ടെങ്കിൽ താങ്കൾക്ക് ഈ ചാവി സൂക്ഷിച്ചുവെയ്ക്കുകയോ, ഈ കണ്ണി ബുക്ക്\u200cമാർക്ക് ചെയ്യുകയോ ചെയ്യാവുന്നതാണ്.',
continueKeyInsert: 'ദയവായി തുടർച്ചാ-ചാവി നൽകുക. ഫലത്തിനായി സ്ലൈഡ്\u200cഷോയിൽ മുന്നോട്ട് പോകേണ്ടതാണ്.',
continueKeyInsertBtn: 'തുടർച്ചാ-ചാവി നൽകുക',
continueKeyInvalid: 'ചാവി അസാധുവാണ്.',
licenseLabel: 'ലഭ്യമായ അനുമതികൾ: ',
uploaderLabel: 'അപ്\u200cലോഡ് ചെയ്തയാൾ ',
helpLinkTitle: 'ഈ ഉപകരണത്തിനുള്ള സഹായവും വിവരണവും',
descriptionLoadText: 'വിവരണം ശേഖരിക്കുന്നു...'
},
ms: {
delayInsertBtn: 'Tetapkan selang masa dalam milisaat',
delayInsert: 'Berapa milisaat perlu ditunggu untuk ke imej baru?',
delayInvalid: 'Input tidak sah. Hanya nombor lebih daripada 1500 diterima.',
playLinkText: 'Main',
pauseLinkText: 'Jeda',
prevLinkText: 'Sebelumnya',
nextLinkText: 'Selepasnya',
hideText: 'Tutup tayangan slaid',
continueKeyHowTo: 'Kekunci Sambungan - Anda boleh menyimpan kekunci ini atau tandakan pautan jika anda ingin bermula pada kedudukan ini nanti.',
continueKeyInsert: 'Sila masukkan kekunci untuk bermula. Anda mesti menatal melalui tayangan slaid untuk melihat perubahan.',
continueKeyInsertBtn: 'Masukkan kekunci',
continueKeyInvalid: 'Kekunci tidak sah.',
licenseLabel: 'Lesen yang disediakan: ',
uploaderLabel: 'Pemuat naik ',
helpLinkTitle: 'Bantuan dan pendokumenan alatan ini',
descriptionLoadText: 'Penerangan sedang dimuatkan ...'
},
pl: {
delayInsertBtn: 'Ustaw opóźnienie w ms',
delayInsert: 'Ile milisekund czekać przed pokazaniem następnej grafiki?',
delayInvalid: 'Nieprawidłowe opóźnienie. Tylko liczby większe niż 1500 są akceptowane.',
playLinkText: 'Odtwórz',
pauseLinkText: 'Pauza',
prevLinkText: 'Wstecz',
nextLinkText: 'Dalej',
hideText: 'Zamknij pokaz slajdów',
continueKeyHowTo: 'Klucz wznowienia - możesz zapisać ten klucz lub dodać go do zakładek, jeśli chcesz później wznowić przeglądanie od obecnej pozycji.',
continueKeyInsert: 'Proszę wpisać klucz wznowienia. Aby ujrzeć efekt, musisz przejść do następnej grafiki.',
continueKeyInsertBtn: 'Wpisz klucz wznowienia',
continueKeyInvalid: 'Nieprawidłowy klucz.',
licenseLabel: 'Dostępne licencje: ',
uploaderLabel: 'Przesłane przez ',
helpLinkTitle: 'Pomoc i dokumentacja dla tego narzędzia',
descriptionLoadText: 'Pobieranie opisu ...'
},
pt: {
delayInsertBtn: 'Alterar o tempo de atraso',
delayInsert: 'Atraso em milissegundos entre cada imagem',
delayInvalid: 'Entrada inválida. Somente números maiores que 1500 são aceitos.',
playLinkText: 'Reproduzir',
pauseLinkText: 'Pausa',
prevLinkText: 'Anterior',
nextLinkText: 'Seguinte',
hideText: 'Fechar a apresentação',
continueKeyHowTo: 'Continuação de Chave - Você pode salvar esta chave e adicionar a ligação para os seus favoritos, se mais tarde quiser começar a partir dessa posição.',
continueKeyInsert: 'Adicione a chave para reiniciar. Você tem que continuar a apresentação para verificar as alterações.',
continueKeyInsertBtn: 'Insira a chave',
continueKeyInvalid: 'Chave inválida.',
licenseLabel: 'Licenças disponíveis: ',
uploaderLabel: 'Utilizador(a) ',
helpLinkTitle: 'Ajuda e documentação desta ferramenta',
descriptionLoadText: 'A carregar descrição ...'
},
'pt-br': {
delayInsertBtn: 'Alterar o tempo de atraso',
delayInsert: 'Atraso em milissegundos entre cada imagem',
delayInvalid: 'Entrada inválida. São aceitos somente números maiores que 1500.',
playLinkText: 'Reproduzir',
pauseLinkText: 'Pausa',
prevLinkText: 'Anterior',
nextLinkText: 'Seguinte',
hideText: 'Fechar a apresentação',
continueKeyHowTo: 'Chave de Continuação - Você pode salvar esta chave e adicionar o link aos seus favoritos, se mais tarde quiser iniciar a partir dessa posição.',
continueKeyInsert: 'Adicione a chave para reiniciar. Você tem que continuar a apresentação para verificar as alterações.',
continueKeyInsertBtn: 'Insira a chave',
continueKeyInvalid: 'Chave inválida.',
licenseLabel: 'Licenças disponíveis: ',
uploaderLabel: 'Utilizador(a) ',
helpLinkTitle: 'Ajuda e documentação desta ferramenta',
descriptionLoadText: 'Carregando descrição ...'
},
ru: {
delayInsertBtn: 'Установить задержку в милисек.',
delayInsert: 'Сколько милисек. ждать до смены изображения?',
delayInvalid: 'Неправильный ввод. Разрешены только числа больше 1500.',
playLinkText: 'Запуск',
pauseLinkText: 'Пауза',
prevLinkText: 'Предыдущее',
nextLinkText: 'Следующее',
hideText: 'Закрыть слайдшоу',
continueKeyHowTo: 'Ключ продолжения — вы можете сохранить этот ключ или добавить ссылку в закладки, если хотите начать с этого места позже.',
continueKeyInsert: 'Вставьте, пожалуйста, ключ продолжения. Вам нужно вернуться обратно в слайдшоу, чтобы увидеть эффект.',
continueKeyInsertBtn: 'Вставьте ключ продолжения',
continueKeyInvalid: 'Неверный ключ',
licenseLabel: 'Доступные лицензии: ',
uploaderLabel: 'Загрузивший ',
helpLinkTitle: 'Справка и документация для этого инструмента',
descriptionLoadText: 'Загрузка описания ...'
},
sl: {
delayInsertBtn: 'Zakasnitev v milisekundah',
delayInsert: 'Čakanje na novo sliko v milisekundah.',
delayInvalid: 'Neveljaven vnos. Številka mora biti večja od 1500.',
playLinkText: 'Predvajaj',
pauseLinkText: 'Premor',
prevLinkText: 'Prejšnja',
nextLinkText: 'Naslednja',
hideText: 'Zapri predstavitev',
continueKeyHowTo: 'Ključ za nadaljevanje: Lahko ga spremenite ali povezavo zaznamčite za poznejše nadaljevanje predstavitve od te slike naprej.',
continueKeyInsert: 'Vnesite ključ za nadaljevanje. Za prikaz spremembe morate nadaljevati prezentacijo.',
continueKeyInsertBtn: 'Vnesite ključ za nadaljevanje',
continueKeyInvalid: 'Neveljaven ključ.',
licenseLabel: 'Razpoložljive licence: ',
uploaderLabel: 'Naložnik ',
helpLinkTitle: 'Pomoč in dokumentacija orodja',
descriptionLoadText: 'Nalaganje opisa ...'
},
sv: {
delayInsertBtn: 'Ställ in fördröjning i ms',
delayInsert: 'Hur många ms det ska dröja innan nästa bild visas?',
delayInvalid: 'Ogiltig indata. Endast nummer större än 1500 accepteras.',
playLinkText: 'Spela',
pauseLinkText: 'Pausa',
prevLinkText: 'Föregående',
nextLinkText: 'Nästa',
hideText: 'Stäng bildspel',
continueKeyHowTo: 'Fortsättningsnyckel - Du kan spara denna nyckel eller lägga ett bokmärke på länken om du vill börja på denna plats senare.',
continueKeyInsert: 'Var god ange fortsättningsnyckeln. Du måste gå framåt i bildspelet för att det ska träda i kraft.',
continueKeyInsertBtn: 'Ange fortsättningsnyckel',
continueKeyInvalid: 'Ogiltig nyckel.',
licenseLabel: 'Tillgängliga licenser: ',
uploaderLabel: 'Uppladdare ',
helpLinkTitle: 'Hjälp och dokumentation för detta verktyg',
descriptionLoadText: 'Läser in beskrivning ...'
}
};
i18n = $.extend({}, i18nStore.en, i18nStore[mw.config.get('wgUserLanguage').split('-')[0]], i18nStore[mw.config.get('wgUserLanguage')]);
var defaults = {
delay: 7000,
preloadAhead: 25,
enableKeyboardNavigation: true,
autoPlay: false,
defaultTransitionDuration: 700,
defaultSizes: [{
w: 1500,
h: 1500
}, {
w: 1280,
h: 1024
}, {
w: 1024,
h: 768
}, {
w: 800,
h: 600
}, {
w: 640,
h: 480
}, {
w: 320,
h: 240
}, {
w: 220,
h: 240
}],
// The maximum image heigh (window's height - space - thumbbar)
maxImageHeight: $(window).height() - 125,
// The maximum image width (window's width - navi-controls - space - caption bar)
maxImageWidth: $(window).width() - 50 - Math.max(Math.min($(window).width() * 0.2, 320), 180),
actualMaxSize: {
w: 640,
h: 480
},
cmdir: 'asc',
continueKey: '',
continueKeyPattern: isCategory ? /^file\|[\da-fA-F]+\|\d+$/ : /\d+\|.+/,
lastPositionExpiry: 2,
readFromScreen: false,
readFromScreenSmallImages: false,
licenseRecognization: [
// RegExp for the tag note to add to the thumb-page
[/Category:CC[\- _]BY-SA.*/i, 'CC-By-SA'],
[/Category:CC[\- _]BY.*/i, 'CC-By'],
[/Category:CC[\- _]Zero.*/i, 'CC0'],
[/Category:GFDL.*/i, 'GFDL'],
[/Category:PD[\- _]Old.*/i, 'PD-old'],
[/Category:PD[\- _]self.*/i, 'PD-self'],
[/Category:PD[\- _]author.*/i, 'PD-author'],
[/Category:PD.*/i, 'PDx'],
[/Category:FAL/i, 'Art Libre - Free Art'],
[/Category:Images requiring attribution/i, 'Attribution'],
[/Category:Copyrighted free use.*/i, 'Copyrighted FreeUse'],
[/Category:Mozilla Public License/i, 'MPL'],
[/Category:GPL/i, 'GPL'],
[/Category:LGPL/i, 'LGPL'],
[/Category:Copyright by Wikimedia.*/i, '(c)WMF'],
[/Category:Free screenshot.*/i, 'free-Screenshot']
],
onSlideChange: function(prevIndex, nextIndex) {
var current, offset;
var displayed = Math.floor(this.$thumbsUl.parent().width() / 81);
var spaceRight = displayed - (nextIndex - this.hiddenLeft);
var spaceLeft = (1 + nextIndex - this.hiddenLeft);
if (spaceRight < 3) {
// Time to slide viewport
current = this.$thumbsUl.css('left').replace('px', '');
offset = (parseFloat(current) - (3 - spaceRight) * 81);
this.$thumbsUl.animate({
left: offset
}, 'fast');
this.hiddenLeft = this.hiddenLeft + (3 - spaceRight);
}
if (spaceLeft < 3 && nextIndex > 1) {
current = this.$thumbsUl.css('left').replace('px', '');
offset = (parseFloat(current) + (3 - spaceLeft) * 81);
this.$thumbsUl.animate({
left: offset
}, 'fast');
this.hiddenLeft = this.hiddenLeft - (3 - spaceLeft);
}
if (nextIndex === 0) {
this.$thumbsUl.animate({
left: 0
}, 'fast');
this.hiddenLeft = 0;
}
if (this.data.length - 5 < nextIndex) {
// Time to fetch more
this.queryApi();
}
},
// accepts a delegate like such: function(prevIndex, nextIndex) { ... }
onTransitionOut: undefined,
// accepts a delegate like such: function(slide, caption, isSync, callback) { ... }
onTransitionIn: undefined
};
// Primary Galleriffic initialization function that should be called on the thumbnail container.
$.fn.galleriffic = function(settings) {
// Extend Gallery Object
$.extend(this, {
// Returns the version of the script
version: $.galleriffic.version,
// Current state of the slideshow
isSlideshowRunning: false,
slideshowTimeout: undefined,
hiddenLeft: 0,
apiURL: mw.util.wikiScript('api'),
indexURL: mw.util.wikiScript('index'),
initial: true,
data: [],
// This function is attached to the click event of generated hyperlinks within the gallery
clickHandler: function(e, link) {
this.pause();
// The href attribute holds the unique hash for an image
var hash = $.galleriffic.normalizeHash($(link).attr('href'));
$.galleriffic.gotoImage(hash);
e.preventDefault();
},
createContainer: function() {
var gallery = this;
this.$slideshowContainer = $('<div class="slideshow-container"></div>');
this.$imageContainer = $('<div id="slideshow" class="slideshow"></div>');
this.$captionContainer = $('<div id="caption" class="caption-container"></div>');
this.$loadingContainer = $('<div id="loading" class="loader"></div>');
this.$controlsContainer = $('<div id="controls" class="controls"></div>');
// Gray lines for navigation
this.$ctrBack = $('<div>', {
'class': 'bar-bwd'
}).append($('<div>', {
'class': 'bar-btn-bwd'
}).text('<')).click(function(e) {
gallery.previous();
e.preventDefault();
}).mouseenter(function() {
$(this).find('div').fadeIn('fast');
}).mouseleave(function() {
$(this).find('div').fadeOut('fast');
});
this.$ctrFwd = $('<div>', {
'class': 'bar-fwd'
}).append($('<div>', {
'class': 'bar-btn-fwd'
}).text('>')).click(function(e) {
gallery.next();
e.preventDefault();
}).mouseenter(function() {
$(this).find('div').last().fadeIn('fast');
}).mouseleave(function() {
$(this).find('div').last().fadeOut('fast');
});
this.$closeButton = $('<div>', {
'class': 'slideshow-close-button',
'title': this.hideText
}).text('×').click(function(e) {
gallery.pause();
gallery.toggleVisibility();
// stop propagation & prevent default
return false;
});
this.append('<div id="com-gs-thumbs" class="navigation"><ul class="com-gs-thumbs"></ul></div>');
this.append(this.$controlsContainer).append(this.$slideshowContainer);
this.$slideshowContainer.append(this.$loadingContainer).append(this.$captionContainer).append(this.$imageContainer);
this.append(this.$ctrBack).append(this.$ctrFwd.prepend(this.$closeButton));
this.$thumbsUl = this.find('ul.com-gs-thumbs');
},
// Scrapes the thumbnail container for thumbs and adds each to the gallery
initializeThumbs: function() {
var data = this.passedData;
var gallery = this;
$.each(data, function(i, imageData) {
var hash;
imageData.index = hash = imageCounter;
imageData.gallery = gallery;
var aspect = (imageData.width / imageData.height);
var size = (aspect > 1) ? 'height' : 'width';
var $thumb = $('<li><a class="com-gs-thumb"><img ' + size + '=75px src="' + (imageData.slideThumb || imageData.slideUrl) + '" /></a></li>');
$thumb.css('opacity', 0.67).hover(function() {
$(this).not('.selected').fadeTo('fast', 1);
}, function() {
$(this).not('.selected').fadeTo('fast', 0.67);
});
gallery.$thumbsUl.append($thumb);
imageData.caption = $('<div>').append(
$('<a>', {
href: imageData.link,
text: imageData.title.replace('File:', '').replace(/\.[\w]{3,4}$/, '')
})).html();
// Register the image globally
allImages['' + hash] = imageData;
// Setup attributes and click handler
$thumb.find('a').attr('href', '#' + hash).removeAttr('name').click(function(e) {
gallery.clickHandler(e, this);
});
imageCounter++;
});
this.data = this.data.concat(data);
return this;
},
isPreloadComplete: false,
// Initalizes the image preloader
preloadInit: function() {
if (this.preloadAhead === 0) {
return this;
}
this.preloadStartIndex = this.currentImage.index;
var nextIndex = this.getNextIndex(this.preloadStartIndex);
return this.preloadRecursive(this.preloadStartIndex, nextIndex);
},
// Changes the location in the gallery the preloader should work
// @param {Integer} index The index of the image where the preloader should restart at.
preloadRelocate: function(index) {
// By changing this startIndex, the current preload script will restart
this.preloadStartIndex = index;
return this;
},
// Recursive function that performs the image preloading
// @param {Integer} startIndex The index of the first image the current preloader started on.
// @param {Integer} currentIndex The index of the current image to preload.
preloadRecursive: function(startIndex, currentIndex) {
// Check if startIndex has been relocated
if (startIndex !== this.preloadStartIndex) {
var nextIndex = this.getNextIndex(this.preloadStartIndex);
return this.preloadRecursive(this.preloadStartIndex, nextIndex);
}
var gallery = this;
// Now check for preloadAhead count
var preloadCount = currentIndex - startIndex;
if (preloadCount < 0) {
preloadCount = this.data.length - 1 - startIndex + currentIndex;
}
if (this.preloadAhead >= 0 && preloadCount > this.preloadAhead) {
// Do this in order to keep checking for relocated start index
setTimeout(function() {
gallery.preloadRecursive(startIndex, currentIndex);
}, 500);
return this;
}
var imageData = this.data[currentIndex];
if (!imageData) {
return this;
}
// If already loaded, continue
if (imageData.image) {
return this.preloadNext(startIndex, currentIndex);
}
// Preload the image
var image = new Image();
image.onload = function() {
imageData.image = this;
gallery.preloadNext(startIndex, currentIndex);
};
image.alt = imageData.title;
image.src = imageData.slideUrl;
return this;
},
// Called by preloadRecursive in order to preload the next image after the previous has loaded.
// @param {Integer} startIndex The index of the first image the current preloader started on.
// @param {Integer} currentIndex The index of the current image to preload.
preloadNext: function(startIndex, currentIndex) {
var nextIndex = this.getNextIndex(currentIndex);
if (nextIndex === startIndex) {
this.isPreloadComplete = true;
} else {
// Use setTimeout to free up thread
var gallery = this;
setTimeout(function() {
gallery.preloadRecursive(startIndex, nextIndex);
}, 100);
}
return this;
},
// Safe way to get the next image index relative to the current image.
// If the current image is the last, returns 0
getNextIndex: function(index) {
var nextIndex = index + 1;
if (nextIndex >= this.data.length) {
nextIndex = 0;
}
return nextIndex;
},
// Safe way to get the previous image index relative to the current image.
// If the current image is the first, return the index of the last image in the gallery.
getPrevIndex: function(index) {
var prevIndex = index - 1;
if (prevIndex < 0) {
prevIndex = this.data.length - 1;
}
return prevIndex;
},
// Pauses the slideshow
pause: function() {
this.isSlideshowRunning = false;
$(document).triggerHandler('slideshow', ['actionPause', this]); // For external scripts
if (this.slideshowTimeout) {
clearTimeout(this.slideshowTimeout);
this.slideshowTimeout = undefined;
}
if (this.$controlsContainer) {
this.$controlsContainer.find('div.nav-controls a.gs-play-pause').removeClass('gs-play-pause').addClass('gs-play-play').attr('title', this.playLinkText).attr('href', '#play');
}
return this;
},
// Plays the slideshow
play: function() {
this.isSlideshowRunning = true;
$(document).triggerHandler('slideshow', ['actionPlay', this]); // For external scripts
if (this.$controlsContainer) {
this.$controlsContainer.find('div.nav-controls a.gs-play-play').removeClass('gs-play-play').addClass('gs-play-pause').attr('title', this.pauseLinkText).attr('href', '#pause');
}
if (!this.slideshowTimeout) {
var gallery = this;
this.slideshowTimeout = setTimeout(function() {
gallery.next(true);
}, this.delay);
}
return this;
},
// Toggles the state of the slideshow (playing/paused)
toggleSlideshow: function() {
if (this.isSlideshowRunning) {
this.pause();
} else {
this.play();
}
return this;
},
// Advances the gallery to the next image.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
next: function(dontPause) {
this.gotoIndex(this.getNextIndex(this.currentImage.index), dontPause);
return this;
},
// Navigates to the previous image in the gallery.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
previous: function(dontPause) {
this.gotoIndex(this.getPrevIndex(this.currentImage.index), dontPause);
return this;
},
// Navigates to the image at the specified index in the gallery
// @param {Integer} index The index of the image in the gallery to display.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
gotoIndex: function(index, dontPause) {
if (!dontPause) {
this.pause();
}
if (index < 0) {
index = 0;
} else if (index >= this.data.length) {
index = this.data.length - 1;
}
var imageData = this.data[index];
this.gotoImage(imageData);
return this;
},
// This function is guaranteed to be called anytime a gallery slide changes.
// @param {Object} imageData An object holding the image metadata of the image to navigate to.
gotoImage: function(imageData) {
var index = imageData.index;
if (this.onSlideChange) {
this.onSlideChange(this.currentImage.index, index);
}
this.currentImage = imageData;
this.preloadRelocate(index);
this.refresh();
return this;
},
// Returns the default transition duration value. The value is halved when not
// performing a synchronized transition.
// @param {Boolean} isSync Specifies whether the transitions are synchronized.
getDefaultTransitionDuration: function(isSync) {
if (isSync) {
return this.defaultTransitionDuration;
}
return this.defaultTransitionDuration / 2;
},
// Rebuilds the slideshow image and controls and performs transitions
refresh: function() {
var imageData = this.currentImage;
if (!imageData) {
return this;
}
var previousSlide = this.$imageContainer.find('span.current').addClass('previous').removeClass('current');
var previousCaption = 0;
if (this.$captionContainer) {
previousCaption = this.$captionContainer.find('span.current').addClass('previous').removeClass('current');
}
// Perform transitions simultaneously if the next image is already preloaded
var isSync = imageData.image;
// Flag we are transitioning
var isTransitioning = true;
var gallery = this;
var transitionOutCallback = function() {
// Flag that the transition has completed
isTransitioning = false;
// Remove the old slide
previousSlide.remove();
// Remove old caption
if (previousCaption) {
previousCaption.remove();
}
if (!isSync) {
if (imageData.image && imageData.index === gallery.data[gallery.currentImage.index].index) {
gallery.buildImage(imageData, isSync);
} else {
// Show loading container
if (gallery.$loadingContainer) {
gallery.$loadingContainer.show();
}
}
}
};
if (previousSlide.length === 0) {
// For the first slide, the previous slide will be empty, so we will call the callback immediately
transitionOutCallback();
} else {
previousSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0, transitionOutCallback);
if (previousCaption) {
previousCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0);
}
}
// Go ahead and begin transitioning in of next image
if (isSync) {
this.buildImage(imageData, isSync);
}
if (!imageData.image) {
var image = new Image();
// Wire up mainImage onload event
image.onload = function() {
imageData.image = this;
// Only build image if the out transition has completed and we are still on the same image hash
if (!isTransitioning && imageData.index === gallery.data[gallery.currentImage.index].index) {
gallery.buildImage(imageData, isSync);
}
};
// set alt and src
image.alt = imageData.title;
image.src = imageData.slideUrl;
}
// This causes the preloader (if still running) to relocate out from the currentIndex
this.relocatePreload = true;
return this.syncThumbs();
},
// Shrinking The Tower of Babel
// Hide other languages, if script is available
shrinkTowerOfBabel: function($node) {
if (window.multilingual) {
var ml = window.multilingual;
ml.langCountThreshold = 2;
ml.method = 'prepend';
ml.$p = ml.$OuterContainer = $node;
ml.init();
}
},
// Called by the refresh method after the previous image has been transitioned out or at the same time
// as the out transition when performing a synchronous transition.
// @param {Object} imageData An object holding the image metadata of the image to build.
// @param {Boolean} isSync Specifies whether the transitions are synchronized.
buildImage: function(imageData, isSync) {
var gallery = this;
var nextIndex = this.getNextIndex(imageData.index);
// We have loaded bigger images, size them down, now; 1 prevents upscaling (looks ugly)
var scaleRatio = Math.max(
imageData.width / this.maxImageWidth,
imageData.height / (this.maxImageHeight - 20),
1);
var imgWidth = Math.floor(imageData.width / scaleRatio);
var imgHeight = Math.floor(imageData.height / scaleRatio);
// computing the "center-position of the space"
var hSpace = isRtl ? (this.$captionContainer.position().left - 2 * this.$imageContainer.position().left) : (this.$imageContainer.width() - this.$captionContainer.position().left - this.$captionContainer.width());
var hPos = isRtl ? (this.$imageContainer.width() - this.$captionContainer.position().left + 2 * this.$imageContainer.position().left + (hSpace - imgWidth) / 2) : (this.$captionContainer.position().left + this.$captionContainer.width() + (hSpace - imgWidth) / 2);
var vSpace = this.$imageContainer.height() - 130;
var top = (vSpace - imgHeight) / 2;
// Send a XHrequest in case of unknown description
if (typeof imageData.description !== 'string') {
this.queryFile(imageData.title);
}
if (typeof this.data[nextIndex].description !== 'string') {
this.queryFile(this.data[nextIndex].title);
}
// Construct new hidden span for the image
var newSlide = this.$imageContainer.append(
$('<span>', {
'class': 'image-wrapper current'
}).css(isRtl ? 'right' : 'left', hPos).css('top', top).append(
$('<a>', {
'class': 'advance-link',
href: imageData.link,
title: imageData.title,
target: '_blank',
css: {
width: imgWidth
}
}))).find('span.current').css('opacity', '0');
newSlide.find('a').append(imageData.image);
var descript = imageData.description || $('<span>').append($.createSpinner(), mw.html.escape(this.descriptionLoadText));
var newCaption = 0;
var extraParams = '&gsDir=' + this.cmdir + '&gsAutoStart=1' + (mw.util.getParamValue('withJS') ? ('&withJS=' + mw.util.getParamValue('withJS')) : '') + (mw.util.getParamValue('withCSS') ? ('&withCSS=' + mw.util.getParamValue('withCSS')) : '');
if (this.$captionContainer) {
// Construct new hidden caption for the image
newCaption = this.$captionContainer.append(
$('<span>', {
'class': 'image-caption current',
style: 'height:' + (this.maxImageHeight - 30) + 'px;'
})).find('span.current').css('opacity', '0').append(imageData.caption, $('<br>')).append(
$('<div>', {
'class': 'gs-img-description',
id: 'desc' + imageData.index,
append: descript
})).append(
$('<div>', {
'class': 'gs-img-uploader'
}).append(imageData.$user.clone())).append(
imageData.$cats,
imageData.$licenses).append(
$('<div>', {
'class': 'gs-img-metrics',
html: imageData.oWidth + ' × ' + imageData.oHeight + ' / ' + imageData.oSize
})).append(imageData.contKey ? $('<div>', {
'class': 'cont-key-container gs-icon',
title: this.continueKeyHowTo,
append: $('<a>', {
href: mw.util.getUrl(mw.config.get('wgPageName')) + '?gsContinue=' + imageData.contKey + extraParams,
target: '_blank',
text: imageData.contKey
})
}) : '');
}
this.shrinkTowerOfBabel(newCaption.find('.gs-img-description'));
// Hide the loading conatiner
if (this.$loadingContainer) {
this.$loadingContainer.hide();
}
// Transition in the new image
if (this.onTransitionIn) {
this.onTransitionIn(newSlide, newCaption, isSync);
} else {
newSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0);
if (newCaption) {
newCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0);
}
}
if (this.isSlideshowRunning) {
if (this.slideshowTimeout) {
clearTimeout(this.slideshowTimeout);
}
this.slideshowTimeout = setTimeout(function() {
gallery.next(true);
}, this.delay);
}
// Save the current position in a cookie or delete the cookie
if (imageData.contKey) {
this.saveContinueKey(imageData.contKey);
} else {
this.saveContinueKey(null);
}
$(document).triggerHandler('slideshow', ['newSlide', this]); // For external scripts
return this;
},
saveContinueKey: function(key) {
// Breaks some clients! Needs investigation and migration to jStorage.
return;
/*if (this.remoteUse) {
return;
}
mw.cookie.get('gs' + mw.config.get('wgPageName').replace('Category:', '1:').replace('Commons:', '2:'),
key, {
expires: this.lastPositionExpiry
});*/
},
getContinueKey: function() {
return mw.cookie.get('gs' + mw.config.get('wgPageName').replace('Category:', '1:').replace('Commons:', '2:'));
},
// Applies the selected class to the current image's corresponding thumbnail.
// Also checks if the current page has changed and updates the displayed page of thumbnails if necessary.
syncThumbs: function() {
// Remove existing selected class and add selected class to new thumb
var $thumbs = this.$thumbsUl.children();
$thumbs.filter('.selected').removeClass('selected').fadeTo('fast', 0.67);
$thumbs.eq(this.currentImage.index).addClass('selected').fadeTo('fast', 1);
return this;
},
findImageSize: function(h, w) {
var that = this,
sOld = this.defaultSizes[0];
$.each(this.defaultSizes, function(i, s) {
if (s.w > w || s.h > h) {
sOld = s;
return;
} else {
that.actualMaxSize = sOld;
return false;
}
});
},
init: function() {
var $navCont, $playBtn, $prevBtn, $nextBtn;
this.createContainer();
var gallery = this;
$(window).resize(function() {
gallery.maxImageHeight = $(window).height() - gallery.$thumbsUl.height() - gallery.$controlsContainer.height();
gallery.maxImageWidth = gallery.$slideshowContainer.width() - gallery.$captionContainer.width() - 16;
gallery.findImageSize(gallery.maxImageHeight, gallery.maxImageWidth);
gallery.css('height', $(window).height());
}).resize();
// Initialize the thumbails
this.initializeThumbs();
this.currentImage = this.data[0];
// Hide the loadingContainer
this.$loadingContainer.hide();
this.gotoIndex(0);
// Setup controls
if (this.autoPlay) {
$playBtn = $('<a>').attr({
'class': 'gs-play gs-play-pause',
title: this.pauseLinkText,
href: '#pause'
});
} else {
$playBtn = $('<a>').attr({
'class': 'gs-play gs-play-play',
title: this.playLinkText,
href: '#play'
});
}
$playBtn.click(function(e) {
gallery.toggleSlideshow();
e.preventDefault();
});
$prevBtn = $('<a>').attr({
'class': 'gs-play gs-play-bwd',
title: this.prevLinkText,
href: '#previous'
}).click(function(e) {
gallery.previous();
e.preventDefault();
});
$nextBtn = $('<a>').attr({
'class': 'gs-play gs-play-fwd',
title: this.nextLinkText,
href: '#next'
}).click(function(e) {
gallery.next();
e.preventDefault();
});
$navCont = $('<div class="nav-controls">');
$navCont.hover(function() {
$(this).fadeTo('fast', 0.75);
}, function() {
$(this).fadeTo('fast', 0.4);
});
this.$controlsContainer.append(
$navCont.append($prevBtn, $playBtn, $nextBtn));
// Option icons
if (!this.remoteUse) {
this.$continueKey = $('<a>', {
'class': 'continue-key-insert gs-icon gs-icon-keyGo',
href: '#',
title: gallery.continueKeyInsertBtn,
click: function(e) {
e.preventDefault();
var ckey = prompt(gallery.continueKeyInsert, gallery.cont ? gallery.cont : '');
ckey = $.trim(ckey);
if (gallery.continueKeyPattern.test(ckey)) {
gallery.cont = ckey;
} else {
alert(gallery.continueKeyInvalid);
}
}
});
}
var $setDelay = $('<a>', {
'class': 'delay-insert gs-icon gs-icon-clock',
href: '#',
title: gallery.delayInsertBtn,
click: function(e) {
e.preventDefault();
var delay = prompt(gallery.delayInsert, gallery.delay ? gallery.delay : '');
if (!delay) {
return;
}
delay = $.trim(delay.replace(/ms|s/, ''));
if (/^\d+$/.test(delay)) {
if (delay > 1000) {
gallery.delay = delay;
} else if ((0.9 < delay) && (delay < 61)) {
gallery.delay = delay * 1000;
} else {
alert(gallery.delayInvalid);
}
// Set cookie
mw.cookie.set('slideshow-delay', gallery.delay, {
expires: 100,
path: '/'
});
} else {
alert(gallery.delayInvalid);
}
}
});
var $helpLink = $('<a>', {
'class': 'gs-help-link gs-icon gs-icon-help',
href: mw.util.getUrl('Help:Slideshow'),
title: gallery.helpLinkTitle,
target: '_blank'
});
var otherCont = $('<div>', {
'class': 'other-controls'
});
this.$controlsContainer.append(
otherCont.append(
(this.$continueKey || ' '),
$setDelay,
$helpLink));
otherCont.hover(function() {
$(this).fadeTo('fast', 1);
}, function() {
$(this).fadeTo('fast', 0.6);
});
// Setup Keyboard Navigation
if (this.enableKeyboardNavigation) {
$(document).keydown(function(e) {
if (!$('#SlideContainer').is(':visible')) {
return;
}
var key = e.charCode || e.keyCode || 0;
switch (key) {
case 32:
// space
gallery.next();
e.preventDefault();
break;
case 35:
// End
gallery.gotoIndex(gallery.data.length - 1);
e.preventDefault();
break;
case 37:
// left arrow
gallery.previous();
e.preventDefault();
break;
case 39:
// right arrow
gallery.next();
e.preventDefault();
break;
case 19:
// break
gallery.toggleSlideshow();
e.preventDefault();
break;
}
});
$(document).keyup(function(e) {
var key = e.charCode || e.keyCode || 0;
//Toggle on escape
if ($('#SlideContainer').height() && key === 27) {
gallery.pause();
gallery.toggleVisibility();
}
});
}
// Auto start the slideshow
if (this.autoPlay) {
this.play();
}
// Kickoff Image Preloader after 1 second
setTimeout(function() {
gallery.preloadInit();
}, 1000);
$(document).triggerHandler('slideshow', ['shown', this]); // For external scripts
},
start: function() {
$(document).triggerHandler('slideshow', ['starting', this]); // For external scripts
$('#GallerySlideStartButtons').find('button').hide();
$('#SlideContainer').animate({
height: $(window).height()
});
// Once done, hide scrollbar
// disabled for IE 6/7
if ('\v' !== 'v') {
$('body').css('overflow', 'hidden');
}
// Settings from URL
var autoPlay = mw.util.getParamValue('gsAutoPlay');
if (autoPlay) {
if ('1' === autoPlay || 'true' === autoPlay || 'yes' === autoPlay || '-1' === autoPlay) {
this.autoPlay = true;
} else {
this.autoPlay = false;
}
}
var delay = mw.util.getParamValue('gsDelay') || mw.cookie.get('slideshow-delay');
if (delay) {
if (/^\d+$/.test(delay)) {
if (delay > 1999) {
this.delay = delay;
} else if ((1 < delay) && (delay < 61)) {
this.delay = delay * 1000;
}
}
}
var cmdir = mw.util.getParamValue('gsDir');
if (cmdir) {
if ('climbing' === cmdir || 'ascending' === cmdir || 'asc' === cmdir || '123' === cmdir || 'rising' === cmdir) {
this.cmdir = 'asc';
} else {
this.cmdir = 'desc';
}
}
var cmcontinue = mw.util.getParamValue('gsContinue');
if (cmcontinue) {
if (this.continueKeyPattern.test(cmcontinue)) {
this.cont = cmcontinue;
} else {
this.cont = '';
}
}
var readFromScreen = mw.util.getParamValue('gsReadFromScreen');
if (readFromScreen) {
this.readFromScreen = true;
this.remoteUse = true;
}
this.findImageSize(this.maxImageHeight, this.maxImageWidth);
this.queryApi();
// For IE 6
if ('\v' === 'v') {
setTimeout(function() {
window.location.hash = '#SlideContainer';
}, 2000);
}
// Display dynamic help from Help:Gadget-GallerySlideshow/OSDHelp
var _this = this;
var showHelpSplash = function(result) {
if (!result) {
return;
}
result = $(result);
result.find('.editsection').remove();
var $slideC = $('#SlideContainer');
var helpSplash = $('<div id="GallerySlideHelpSplash"></div>').append(result);
setTimeout(function() {
helpSplash.fadeOut();
}, 15000);
helpSplash.css('right', 0);
helpSplash.css('bottom', 0);
$slideC.prepend(helpSplash.hide().fadeTo(400, 0.7));
helpSplash.click(function() {
$(this).fadeOut();
});
};
$.get(this.indexURL, {
title: 'Help:Gadget-GallerySlideshow/OSDHelp',
action: 'render',
uselang: mw.config.get('wgUserLanguage')
}, showHelpSplash);
},
toggleVisibility: function() {
$('#GallerySlidestart').toggle().off('click').click(GallerySlide.toggleVisibility);
$('#GallerySlideStartButtons').buttonset();
$('#SlideContainer').slideToggle(function() {
$(document).triggerHandler('slideshow', ['visibility', GallerySlide]);
});
$('body').css('overflow', 'visible');
// For external scripts
},
queryFile: function(title) {
var _this = this;
var params = {
action: 'render',
title: title
};
$.ajax({
url: this.indexURL,
cache: true,
dataType: 'html',
data: params,
type: 'GET',
success: function(result) {
_this.processDetails(result, title);
}
});
},
processDetails: function(result, title) {
if (typeof result !== 'string') {
return;
}
var i,
dItem,
dDescription,
$node,
parsedDOM = $(result),
$author;
parsedDOM.find('table, div').attr('style', '');
parsedDOM.find('table').attr('cellspacing', 1).attr('cellpadding', 0);
// Clean up author field. Some users are very important and therefore designed logos etc. for themselves
// But they are not really important and possibly distract the slideviewer
$author = $('#fileinfotpl_aut', parsedDOM).siblings().eq(0).contents().clone();
$author.find('img').remove();
$author.find('*').removeAttr('style');
$author.find('font').contents().unwrap();
$author.find('b').contents().unwrap();
dDescription = $('<div>').append(
$('<div>').addClass('gs-img-description-desc').append(
$('#fileinfotpl_desc', parsedDOM).siblings().eq(0).contents()),
$('<div>').addClass('gs-img-description-aut').append($author).prepend(
$('<span>', {
'class': 'gs-author-label'
}).text($(parsedDOM).find('#fileinfotpl_aut').text())),
$('<div>').addClass('gs-img-description-date').append(
$(parsedDOM).find('#fileinfotpl_date').siblings().eq(0).contents().clone()).prepend(
$('<span>', {
'class': 'gs-date-label'
}).text($('#fileinfotpl_date', parsedDOM).text()))).html();
if (!dDescription) {
dDescription = result;
}
for (i in this.data) {
dItem = this.data[i];
if (dItem.title === title) {
dItem.description = dDescription;
$node = $('#desc' + i);
if ($node.length !== 0) {
$node.html(dDescription);
this.shrinkTowerOfBabel($node);
}
}
}
},
queryApi: function() {
var _this = this;
var params = {};
if (_this.queryRunning || (_this.cont === false && !_this.readFromScreen)) {
return;
}
$(document).triggerHandler('slideshow', ['beforeQuery', this]); // For external scripts
// New restrictions in image info API
var limit = Math.min(Math.floor($('#SlideContainer').width() / 81) + 1, 50);
if (_this.readFromScreen) {
_this.qFiles = [];
if (!_this.$galleryBoxes) {
_this.$galleryBoxes = $('.gallerybox');
_this.queryImageId = -1;
}
if (_this.queryImageId === (_this.$galleryBoxes.length - 1)) {
return; // All images loaded
}
_this.$galleryBoxes.each(function(i, e) {
if (_this.queryImageId >= i) {
return;
}
if (_this.qFiles.length === limit) {
return;
}
_this.queryImageId = i;
_this.qFiles.push('File:' + mw.libs.commons.titleFromImgSrc($(e).find('.thumb').find('img').attr('src')));
});
}
if (_this.readFromScreen) {
params = {
format: 'json',
action: 'query',
titles: _this.qFiles.join('|'),
rawcontinue: 1,
prop: 'imageinfo|categories',
clprop: 'hidden',
cllimit: 500,
iiprop: 'url|user|size',
iilimit: 1,
iiurlwidth: this.actualMaxSize.w,
iiurlheight: this.actualMaxSize.h,
indexpageids: 1
};
} else if (isCategory) {
params = {
format: 'json',
action: 'query',
generator: 'categorymembers',
rawcontinue: 1,
gcmtitle: mw.config.get('wgPageName'),
gcmlimit: limit,
gcmtype: 'file',
gcmdir: this.cmdir,
prop: 'imageinfo|categories',
clprop: 'sortkey|hidden',
cllimit: 500,
iiprop: 'url|user|size',
iilimit: 1,
iiurlwidth: this.actualMaxSize.w,
iiurlheight: this.actualMaxSize.h,
indexpageids: 1
};
if (this.cont) {
params.gcmcontinue = this.cont;
}
} else {
params = {
action: 'query',
generator: 'images',
rawcontinue: 1,
titles: mw.config.get('wgPageName'),
gimlimit: limit,
prop: 'imageinfo|categories',
clprop: 'hidden',
cllimit: 500,
iiprop: 'url|user|size',
iilimit: 1,
iiurlwidth: this.actualMaxSize.w,
iiurlheight: this.actualMaxSize.h,
format: 'json',
indexpageids: 1
};
if (this.cont) {
params.gimcontinue = this.cont;
}
}
if (!this.initial && !this.cont && !this.readFromScreen) {
return;
}
_this.queryRunning = true;
$.ajax({
url: this.apiURL,
cache: false,
dataType: 'json',
data: params,
type: 'POST',
success: function(result) {
_this.queryRunning = false;
_this.processReturn(result);
},
error: function() {
_this.queryRunning = false;
}
});
},
processReturn: function(result) {
$(document).triggerHandler('slideshow', ['afterQuery', this]); // For external scripts
var pages = result.query.pages,
pages2 = [],
data = [],
i = 0, j = 0;
if (result['query-continue'] && (result['query-continue'].categorymembers || result['query-continue'].images)) {
if (typeof this.cont !== 'undefined') {
this.contOld = this.cont;
}
this.cont = isCategory ? result['query-continue'].categorymembers.gcmcontinue : result['query-continue'].images.gimcontinue;
} else {
this.cont = false;
}
// Fromatt a number
var fm = function(iNr) {
iNr += '';
var rx = /(\d+)(\d{3})/;
while (rx.test(iNr)) {
iNr = iNr.replace(rx, '$1' + '<span class="digit-separator"> </span>' + '$2');
}
return iNr;
};
if (this.readFromScreen) {
// sorting the mess, the API has created to fit the page-diplay
var qFilesL = this.qFiles.length,
qFilesTitle,
qfi,
p, pg;
sreenreadorderloop: for (qfi = 0; qfi !== qFilesL; qfi++) {
qFilesTitle = this.qFiles[qfi];
for (p in pages) {
pg = pages[p];
if (pg.title === qFilesTitle) {
pages2.push(pg);
continue sreenreadorderloop;
}
}
}
pages = pages2;
} else {
// This is for Chrome: https://bugs.chromium.org/p/v8/issues/detail?id=164
// and Opera and InternetExplorer
var pgIds = result.query.pageids;
for (j = 0; j < pgIds.length; j++) {
pages2.push(pages[pgIds[j]]);
}
pages = pages2;
}
for (j = 0; j < pages.length; j++) {
var v = pages[j];
if ('undefined' !== typeof v.missing || !v.imageinfo) {
continue;
}
var r = v.imageinfo[v.imageinfo.length - 1],
rc = v.imageinfo[0],
n = data[i] = {},
sortkey = '',
$cats = $('<div>', {
'class': 'cat-wrap'
}),
$licenses = $('<div>', {
'class': 'license-wrap'
}).append($('<span>', {
style: 'display:inline-block;'
}).text(this.licenseLabel));
// Process categories; Extract visible cats, sortkey for current cat, licenses
if (v.categories) {
var c, clen = v.categories.length;
processCats: for (c = 0; c < clen; c++) {
var tCat = v.categories[c];
if (isCategory && tCat.title === mw.config.get('wgPageName').replace(/_/g, ' ')) {
sortkey = 'file' + '|' + tCat.sortkey + '|' + v.pageid;
}
if (typeof tCat.hidden === 'undefined') {
$cats.append(
$('<a>', {
'class': 'cat-label',
href: mw.util.getUrl(tCat.title),
target: '_blank',
text: tCat.title.replace('Category:', '')
}), ' ');
} else {
var recogID, recogLen = this.licenseRecognization.length;
for (recogID = 0; recogID < recogLen; recogID++) {
if (this.licenseRecognization[recogID][0].test(tCat.title)) {
$licenses.append(
$('<span>', {
'class': 'license-label',
title: tCat.title.replace('Category:', ''),
html: this.licenseRecognization[recogID][1]
}), ' ');
continue processCats;
}
}
}
}
}
if (!isCategory) {
sortkey = mw.config.get('wgArticleId') + '|' + v.title.replace('File:', '');
}
n.title = v.title;
n.link = rc.descriptionurl;
n.slideUrl = rc.thumburl;
n.width = rc.thumbwidth;
n.height = rc.thumbheight;
n.oWidth = fm(r.width);
n.oHeight = fm(r.height);
n.oSize = fm(r.size >> 10) + ' <abbr title="1 KibiByte= 1024 Bytes">KiB</abbr>';
n.$user = $('<span>').append(
$('<span>', {
'class': 'gs-uploader-label'
}).text(this.uploaderLabel)).append(
$('<span>').css({
direction: 'ltr',
display: 'inline-block'
}).append(
$('<a>', {
href: mw.util.getUrl(mw.config.get('wgFormattedNamespaces')[2] + ':' + r.user),
target: '_blank',
text: r.user
}), ' (',
$('<a>', {
href: mw.util.getUrl(mw.config.get('wgFormattedNamespaces')[3] + ':' + r.user),
target: '_blank',
text: 'talk'
}), ')'));
n.$cats = $cats;
n.$licenses = $licenses;
n.contKey = (sortkey || this.contOld);
// reset to empty string when using screen-read-mode (too instable to rely on it)
if (this.readFromScreen) {
n.contKey = '';
}
i++;
}
this.passedData = data;
if (this.initial) {
this.init();
} else {
this.initializeThumbs();
}
this.initial = false;
}
});
// Now initialize the gallery
$.extend(this, defaults, i18n, settings);
return this;
};
$(document).ready(function() {
if ($('.gallery li').length < 2) {
// no need for a gallery with a few images
return;
}
mw.loader.using(['mediawiki.cookie', 'mediawiki.util', 'jquery.ui', 'jquery.spinner'], function() {
$('body').append('<div id="SlideContainer"></div>');
window.GallerySlide = $('#SlideContainer').galleriffic();
$(document).triggerHandler('slideshow', ['codeLoaded', window.GallerySlide]); // For external scripts
});
});
// When this script is loaded, someone started the slideshow gadget
// To prepare un-defaulting, set a user preference and count usage
if (mw.user.isAnon()) return;
mw.loader.using('ext.gadget.SettingsManager', function() {
mw.libs.settingsManager.fetchGadgetSetting('slideshow-usage').done(function(o, v) {
v = Number(v) || 0;
v++;
if (v > 9) return;
mw.libs.settingsManager.switchGadgetPref('slideshow-usage', v);
});
});
})(jQuery);