User:Genferei/Gadget-Merge.js

From Wikibase Personal data
Jump to navigation Jump to search

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

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
/*global jQuery, mediaWiki, OO, wikibase*/
/*!
 * merge.js - Script to merge Wikidata items
 * @authors User:Ebrahim, User:Ricordisamoa, User:Fomafix, User:Bene*, User:Petr Matas, User:Matěj Suchánek
 * @license CC-Zero
 */
// See also: MediaWiki:Gadget-EmptyDetect.js and MediaWiki:Gadget-RfDHelper.js



(function ($, mw, OO) {

  'use strict';
  var messages, entityId = mw.config.get('wbEntityId'), api = new mw.Api();
  messages = (function () {
    var translations = {
      en: {
        conflictMessage: 'A conflict detected on ',
        conflictWithMessage: 'with',
        createRedirect: 'Create a redirect',
        creatingRedirect: 'Creating redirect...',
        errorWhile: 'Error while "$1":',
        invalidInput: 'Currently only Qid/Lid is a valid input',
        loadMergeDestination: 'Load merge destination on success',
        loadingMergeDestination: 'Loading merge destination...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "Merge with" entity)',
        merge: 'Merge',
        mergePendingNotification: 'Merge.js has been started.<br>Now you can focus your browser on the other entity.',
        mergeProcess: 'Process the merge now',
        mergeSummary: 'Append the following text to the auto-generated edit summary:',
        mergeThisEntity: 'Merge this entity',
        mergeWithInput: 'Merge with:',
        mergeWithProgress: 'Merge with...',
        mergeWizard: 'Merge Wizard',
        pleaseWait: 'Please wait...',
        postpone: 'Postpone',
        postponeTitle: 'Store this entity\'s id and postpone the merge',
        reportError: 'If you believe it\'s an error, please report it [[here]] with source and destination of merge.',
        selectForMerging: 'Select for merging',
        selectForMergingTitle: 'Remember this entity as the second one of the two entities to be merged',
        unwatchOption: 'Remove merged entity from your watchlist (if watched)',
        unwatching: 'Removing from watch list...'
      },
      ar: {
        conflictMessage: 'ثمة خطب في ',
        conflictWithMessage: 'مع',
        loadingMergeDestination: 'تحميل وجهة الدمج...',
        lowestEntityId: 'دائما ادمج إلى المادة الأقدم (لا تعلم للدمج مع مادة "ادمج مع")',
        merge: 'دمج',
        mergePendingNotification: 'أداة الدمج تعمل.<br>يمكنك الآن الاطلاع على المادة الأخرى.',
        mergeProcess: 'ادمج الآن',
        mergeThisEntity: 'ادمج هذه المادة',
        mergeWithInput: 'ادمج مع:',
        mergeWithProgress: 'يدمج مع...',
        mergeWizard: 'أداة الدمج',
        pleaseWait: 'انتظار...',
        postpone: 'تأجيل',
        postponeTitle: 'خزن معرف هذه المادة وأجل الدمج',
        unwatchOption: 'حذف المادة المدمجة من قائمة المراقبة (إن كان فيها)',
        unwatching: 'يحذف من القائمة...'
      },
      cs: {
        conflictMessage: 'Detekován konflikt v ',
        conflictWithMessage: 's',
        createRedirect: 'Vytvořit přesměrování',
        creatingRedirect: 'Vytvářím přesměrování',
        errorWhile: 'Chyba při „$1“:',
        invalidInput: 'Platný vstup je zatím pouze identifikátor entity',
        loadMergeDestination: 'Po provedení načíst výsledek sloučení',
        loadingMergeDestination: 'Načítám výsledek sloučení...',
        lowestEntityId: 'Vždy sloučit do starší z entit (vypněte pro sloučení do entity uvedené v poli "Sloučit s")',
        merge: 'Sloučit',
        mergePendingNotification: 'Skript Merge.js byl aktivován.<br>Nyní můžete ve svém prohlížeči přejít na jinou entitu.',
        mergeProcess: 'Provést nyní sloučení',
        mergeSummary: 'K automaticky generovanému shrnutí editace připojit tento text:',
        mergeThisEntity: 'Sloučit entitu',
        mergeWithInput: 'Sloučit s:',
        mergeWithProgress: 'Sloučit s...',
        mergeWizard: 'Nástroj pro slučování',
        pleaseWait: 'Prosím čekejte...',
        postpone: 'Odložit',
        postponeTitle: 'Uložit id entity a odložit sloučení',
        reportError: 'Pokud si myslíte, že je to chyba, prosíme nahlaste ji [[zde]] s původní a cílovou entitou ke sloučení.',
        selectForMerging: 'Vybrat ke sloučení',
        selectForMergingTitle: 'Zapamatovat si tuto entitu jako druhou ze dvou entit ke sloučení',
        unwatchOption: 'Odstranit vyprázdněnou entitu z vašich sledovaných stránek (je-li sledována)',
        unwatching: 'Odstraňuji ze sledovaných stránek...'
      },
      de: {
        conflictMessage: 'Ein Konflikt wurde erkannt bei ',
        conflictWithMessage: 'mit',
        createRedirect: 'Erstelle Weiterleitung',
        creatingRedirect: 'Erstelle Weiterleitung...',
        errorWhile: 'Fehler während „$1“:',
        loadingMergeDestination: 'Lade zusammengelegtes Datenelement…',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "Zusammenlegen mit" entity)',
        merge: 'Zusammenlegen',
        mergePendingNotification: 'Merge.js wurde gestartet.<br>Jetzt kannst du das andere Datenelement öffnen.',
        mergeProcess: 'Starte das Zusammenlegen jetzt',
        mergeThisEntity: 'Lege das Datenelement zusammen',
        mergeWithInput: 'Zusammenlegen mit:',
        mergeWithProgress: 'Zusammenlegen mit…',
        mergeWizard: 'Assistent zum Zusammenlegen',
        pleaseWait: 'Bitte warte…',
        postpone: 'Verschieben',
        postponeTitle: 'Speichere die Nummer des Datenelementes und mach es zum Ziel einer Zusammenlegung',
        //reportError: 'Bitte melde diesen Fehler [[hier]] mit Quelle und Ziel der Zusammenlegung.',
        unwatchOption: 'Entferne zusammengelegte Datenelemente von der Beobachtungsliste (wenn beobachtet)',
        unwatching: 'Entferne von Beobachtungsliste…'
      },
      'de-formal': {
        mergePendingNotification: 'Merge.js wurde gestartet.<br>Jetzt können Sie das andere Datenelement öffnen.'
      },
      el: {
        conflictMessage: 'Ανιχνεύθηκε διένεξη',
        conflictWithMessage: 'με',
        createRedirect: 'Δημιουργία ανακατεύθυνσης',
        creatingRedirect: 'Δημιουργείται ανακατεύθυνση...',
        loadingMergeDestination: ' Ανανέωση σελίδας προς το αντικείμενο έγινε η συγχώνευση ...',
        lowestEntityId: 'Πάντα να γίνεται συγχώνευση στο παλαιότερο αντικείμενο (καταργήστε την επιλογή για να συγχωνευθεί με το αντικείμενο "Συγχώνευση με")',
        merge: 'Συγχώνευση',
        mergePendingNotification: 'Η εφαρμογή Merge.js ξεκίνησε.<br>Τώρα μπορείτε να εστιάσετε το πρόγραμμα περιήγησης στο άλλο αντικέιμενο.',
        mergeProcess: 'Άμεση συγχώνευση',
        mergeThisEntity: 'Συγχώνευση αυτού του αντικειμένου ',
        mergeWithInput: 'Συγχώνευση με:',
        mergeWithProgress: 'Συγχώνευση με...',
        mergeWizard: 'Οδηγός συγχώνευσης',
        pleaseWait: 'Παρακαλώ περιμένετε...',
        postpone: 'Αναβολή',
        postponeTitle: 'Αποθήκευση αυτού του κωδικού αντικειμένου/αντικειμένων και αναβολή της συγχώνευσης',
        selectForMerging: 'Επιλέξτε για συγχώνευση',
        selectForMergingTitle: 'Να θυμάσαι αυτό το αντικείμενο σαν το δεύτερο από τα δύο αντικείμενο που θα συγχωνευθούν',
        unwatchOption: 'Αφαιρέστε το συγχωνευμένο αντικείμενο από την σελίδα παρακολούθησής σας (εάν ήδη το παρακολουθείτε)',
        unwatching: 'Αφαίρεση από τη σελίδα παρακολούθησης...'
      },
      es: {
        conflictMessage: 'Un conflicto detectado en ',
        conflictWithMessage: 'con',
        loadingMergeDestination: 'Cargando el destino de la fusión...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "Fusionarlo con" entity)',
        merge: 'Fusionar',
        mergePendingNotification: 'Merge.js empezó.<br>Ahora puedes enfocar tu navegador en el otro elemento',
        mergeProcess: 'Proceder a la fusión ahora',
        mergeThisEntity: 'Fusionar este elemento',
        mergeWithInput: 'Fusionarlo con:',
        mergeWithProgress: 'Fusionarlo con...',
        mergeWizard: 'Herramienta de fusión',
        pleaseWait: 'Por favor, espera...',
        postpone: 'Posponer',
        postponeTitle: 'Guardar el id de este elemento y posponer la fusión',
        unwatchOption: 'Eliminar los elementos fusionados de tu lista de seguimiento (si están)',
        unwatching: 'Eliminando de la lista de seguimiento...'
      },
      fa: {
        conflictMessage: 'تداخل در ',
        conflictWithMessage: 'با',
        createRedirect: 'ایجاد یک تغییر مسیر',
        creatingRedirect: 'ایجاد تغییر مسیر...',
        loadingMergeDestination: 'بارگیری مقصد ادغام...',
        lowestEntityId: 'همیشه به آیتم قدیمی\u200cتر ادغام کن (برای خاموش کردن "ادغام\u200cکردن با" کنیک کنید)',
        merge: 'ادغام',
        mergePendingNotification: 'ابزار ادغام فعال شد<br>هم\u200cاکنون می\u200cتوانید به صفحهٔ آیتم دیگر برای ادغام بروید.',
        mergeProcess: 'انجام دادن ادغام',
        mergeThisEntity: 'ادغام این آیتم',
        mergeWithInput: 'ادغام\u200cکردن با:',
        mergeWithProgress: 'ادغام\u200cکردن با...',
        mergeWizard: 'ابزار ادغام',
        pleaseWait: 'صبر کنید...',
        postpone: 'به تأخیر انداختن',
        postponeTitle: 'ذخیرهٔ شناسهٔ آیتم و به تاخیر انداختن ادغام',
        unwatchOption: 'حذف آیتم\u200cهای ادغام شده از فهرست پی\u200cگیری\u200cها',
        unwatching: 'حذف از پیگیری\u200cها...'
      },
      fr: {
        conflictMessage: 'Un conflit a été détecté sur ',
        conflictWithMessage: 'avec',
        createRedirect: 'Créer une redirection',
        creatingRedirect: 'Création de la redirection ...',
        errorWhile: 'Erreur durant "$1" :',
        invalidInput: 'Actuellement, seul Qid est une entrée valide',
        loadMergeDestination: 'Charger la destination de fusion en cas de succès',
        loadingMergeDestination: 'Chargement de la destination de fusion ...',
        lowestEntityId: 'Toujours fusionner dans l’élément le plus vieux (décocher pour fusionner avec l’élément indiqué dans « Fusionner avec »)',
        merge: 'Fusionner',
        mergePendingNotification: 'Merge.js a commencé.<br>Vous pouvez maintenant consulter un autre élément.',
        mergeProcess: 'Procéder à la fusion maintenant',
        mergeSummary: 'Ajouter le texte suivant en tant que résumé de modification :',
        mergeThisEntity: 'Fusionner cet élément',
        mergeWithInput: 'Fusionner avec :',
        mergeWithProgress: 'Fusionner avec ...',
        mergeWizard: 'Outil de fusion',
        pleaseWait: 'Attendez ...',
        postpone: 'Repousser à plus tard',
        postponeTitle: 'Stocker cet identifiant et repousser à plus tard la fusion',
        //reportError: 'Rapportez l’erreur ci-dessus [[ici]] avec la source et la destination à fusionner.',
        selectForMerging: 'Selectionner pour une fusion',
        selectForMergingTitle: 'Rappeler cet élément comme le second parmi les deux éléments à fusionner',
        unwatchOption: 'Retirer les éléments supprimés de votre liste de suivi (s’ils étaient suivis)',
        unwatching: 'Retrait de la liste de suivi ...'
      },
      gl: {
        conflictMessage: 'Detectouse un conflito en ',
        conflictWithMessage: 'con',
        createRedirect: 'Crear unha redirección',
        creatingRedirect: 'Creando a redirección...',
        errorWhile: 'Produciuse un erro ao "$1":',
        invalidInput: 'Actualmente, as únicas entradas válidas son os identificadores Q dos elementos',
        loadMergeDestination: 'Cargar o destino da fusión ao rematar',
        loadingMergeDestination: 'Cargando o destino da fusión...',
        lowestEntityId: 'Fusionar sempre no elemento máis vello (desmarca a opción para fusionar no elemento do campo "Fusionar con")',
        merge: 'Fusionar',
        mergePendingNotification: 'Merge.js iniciouse.<br>Xa podes ir co navegador ao outro elemento.',
        mergeProcess: 'Proceder agora á fusión',
        mergeSummary: 'Engadir o seguinte texto ao resumo de edición automático:',
        mergeThisEntity: 'Fusionar este elemento',
        mergeWithInput: 'Fusionar con:',
        mergeWithProgress: 'Fusionar con...',
        mergeWizard: 'Ferramenta de fusións',
        pleaseWait: 'Por favor, espera...',
        postpone: 'Pospoñer',
        postponeTitle: 'Gardar o identificador deste elemento e pospor a fusión',
        //reportError: 'Informa do erro anterior [[aquí]] coa orixe e mais o destino da fusión.',
        selectForMerging: 'Seleccionar para a súa fusión',
        selectForMergingTitle: 'Lembrar este elemento como o segundo dos dous a fusionar',
        unwatchOption: 'Eliminar o elemento fusionado da túa lista de vixilancia (se está nela)',
        unwatching: 'Eliminando da lista de vixilancia...'
      },
      gu: {
        conflictMessage: 'પર એક અથડામણ મળેલ છે',
        conflictWithMessage: 'સાથે',
        loadingMergeDestination: 'વિલિન કરેલ લક્ષ્યાંક લાવાય રહ્યું છે...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "તેને સાથે વિલિન કરો" entity)',
        merge: 'વિલીનMerge',
        mergePendingNotification: 'Merge.js શરૂ થઈ ગયેલ છે.<br> હવે તમે તમારું બ્રાઉઝર અન્ય લેખ પર કેન્દ્રિત કરી શકો છો.',
        mergeProcess: 'હમણા જ વિલિનીકરણની પ્રક્રિયા કરો કરો',
        mergeThisEntity: 'આ લેખ વિલિન કરો',
        mergeWithInput: 'તેને સાથે વિલિન કરો:',
        mergeWithProgress: 'તેને સાથે વિલિન કરો...',
        mergeWizard: 'વિલિન વિઝાર્ડ',
        pleaseWait: 'મહેરબાની કરીને રાહ જુઓ...',
        postpone: 'મુલતવી રાખોPostpone',
        postponeTitle: 'આ લેખની ઓળખ સાચવો અને વિલિનીકરણ મુલતવી રાખો',
        unwatchOption: 'વિલિન કરેલ લેખો તમારી ધ્યાનસૂચિમાંથી હટાવો (જો ધ્યાનસૂચિમાં હોય તો)',
        unwatching: 'ધ્યાનસૂચિમાંથી હટાવાય રહ્યું છે...'
      },
      hr: {
        conflictMessage: 'Otkriven je sukob ',
        conflictWithMessage: 's',
        createRedirect: 'Napravi preusmjeravanje',
        creatingRedirect: 'Stvaram preusmjeravanje...',
        errorWhile: 'Pogrješka za vrijeme "$1":',
        invalidInput: 'Trenutačno se može unijeti samo Qid',
        loadMergeDestination: 'Po završetku učitaj završnu stavku',
        loadingMergeDestination: 'Učitavam završnu stavku...',
        lowestEntityId: 'Uvijek spoji sa starijom stavkom (odznačite ako želite spojiti sa stavkom navedenom u polju "Spoji s")',
        merge: 'Spoji',
        mergePendingNotification: 'Merge.js je pokrenut.<br>Možete nastaviti raditi na drugim stavkama.',
        mergeProcess: 'Spoji stavku sada',
        mergeSummary: 'Automatski stvorenom sažetku uređivanja dodaj sljedeći tekst :',
        mergeThisEntity: 'Spoji ovu stavku',
        mergeWithInput: 'Spoji s:',
        mergeWithProgress: 'Spoji s...', 
        mergeWizard: 'Čarobnjak za spajanje',
        pleaseWait: 'Molimo pričekajte...',
        postpone: 'Spoji kasnije',
        postponeTitle: 'Spremi ovu stavku i spoji kasnije',
        //reportError: 'Molimo prijavite gornju pogrješku [[ovdje]] s početnom i završnom stavkom spajanja.',
        selectForMerging: 'Označi za spajanje',
        selectForMergingTitle: 'Upamti ovu stavku kao drugu od dvije za spajanje',
        unwatchOption: 'Ukloni spojenu stavku s popisa praćenja (ako je bila na njemu)',
        unwatching: 'Uklanjam s popisa praćenja...'
      },
      hu: {
        conflictMessage: 'Ütközés észlelve ezen: ',
        conflictWithMessage: 'ezzel:',
        createRedirect: 'Átirányítás létrehozása',
        creatingRedirect: 'Átirányítás létrehozása…',
        errorWhile: 'Hiba miközben „$1”:',
        invalidInput: 'Jelenleg csak a Wikidata-azonosító (Qid) elfogadott érték',
        loadMergeDestination: 'Célelem betöltése sikeres összevonás esetén',
        loadingMergeDestination: 'Összevonás céljának betöltése…',
        lowestEntityId: 'Mindig a régebbi elembe vonjon össze (ajánlott; ha kiveszed a pipát, az „Összevonás a következővel”-nél megjelölt elembe von össze)',
        merge: 'Összevonás',
        mergePendingNotification: 'A Merge.js elindult.<br>Most menj a böngésződdel a másik elemre!',
        mergeProcess: 'Összevonás indítása',
        mergeSummary: 'Az automatikusan generált összefoglaló kiegészítése a következő szöveggel:',
        mergeThisEntity: 'Elem összevonása',
        mergeWithInput: 'Összevonás a következővel:',
        mergeWithProgress: 'Összevonás…',
        mergeWizard: 'Összevonás-varázsló',
        pleaseWait: 'Kérjük, várj…',
        postpone: 'Később',
        postponeTitle: 'Elem azonosítójának megjegyzése, és az összevonás elhalasztása',
        reportError: 'Ha úgy gondolod, hogy ez a varázsló hibája, kérjük, jelezd [[itt]] a forrás- és a célelemmel együtt!',
        selectForMerging: 'Kiválasztás összevonáshoz',
        selectForMergingTitle: 'Elem megjegyzése mint második a két összevonandó elemből',
        unwatchOption: 'Összevont elem eltávolítása a figyelőlistádról (ha figyeled)',
        unwatching: 'Eltávolítás a figyelőlistádról…'
      },
      id: {
        conflictMessage: 'Ada konflik terdeteksi pada ',
        conflictWithMessage: 'dengan',
        loadingMergeDestination: 'Loading tujuan penggabungan...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "Gabung dengan" entity)',
        merge: 'Gabung',
        mergePendingNotification: 'Merge.js dimulai.<br>Sekarang Anda dapat fokus pada item lain.',
        mergeProcess: 'Lakukan penggabungan',
        mergeThisEntity: 'Gabungkan item ini',
        mergeWithInput: 'Gabung dengan:',
        mergeWithProgress: 'Gabungkan',
        mergeWizard: 'Peralatan penggabungan',
        pleaseWait: 'Mohon tunggu sebentar...',
        postpone: 'Tunda',
        postponeTitle: 'Simpan item dan tunda penggabungan',
        unwatchOption: 'Hapus item yang digabung dari pantauan (jika ada)',
        unwatching: 'Hapus dari daftar pantauan...'
      },
      it: {
        conflictMessage: 'Rilevato un conflitto in ',
        conflictWithMessage: 'con',
        createRedirect: 'Crea un redirect',
        creatingRedirect: 'Creazione del redirect...',
        errorWhile: 'Errore durante "$1":',
        invalidInput: 'Attualmente solo Qid è un input valido',
        loadMergeDestination: 'Carica la destinazione dell\'unione in caso di successo',
        loadingMergeDestination: 'Caricamento della destinazione...',
        lowestEntityId: 'Unisci sempre nell\'elemento più vecchio (deselezione per unire nell\'elemento "Unisci con")',
        merge: 'Unione',
        mergePendingNotification: 'Merge.js è stato avviato.<br>Adesso vai sulla pagina dell\'altro elemento.',
        mergeProcess: 'Effettua l\'unione adesso',
        mergeSummary: 'Aggiungi il seguente testo all\'oggetto della modifica auto-generato:',
        mergeThisEntity: 'Unisci questo elemento',
        mergeWithInput: 'Unisci con:',
        mergeWithProgress: 'Unione con l\'elemento...',
        mergeWizard: 'Unione guidata',
        pleaseWait: 'Attendi...',
        postpone: 'Rimanda a dopo',
        postponeTitle: 'Memorizza l\'ID di questo elemento e rimanda a dopo l\'unione',
        //reportError: 'Riporta l\'errore sopra [[qui]] con l\'elemento di origine e destinazione dell\'unione.',
        selectForMerging: 'Seleziona per l\'unione',
        selectForMergingTitle: 'Ricorda questo elemento come il secondo dei due elementi da unire',
        unwatchOption: 'Rimuovi gli elementi uniti dagli osservati speciali (se presenti)',
        unwatching: 'Rimozione dagli osservati speciali...'
      },
      ja: {
        conflictMessage: '衝突が検出されました: ',
        conflictWithMessage: 'と',
        loadingMergeDestination: '統合先の読込中...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "統合相手" entity)',
        merge: '統合',
        mergePendingNotification: 'Merge.js が動き出しました。<br>もうブラウザで他の項目に切り替えても大丈夫です。',
        mergeProcess: '統合をいま実行します',
        mergeThisEntity: 'この項目を統合する',
        mergeWithInput: '統合相手:',
        mergeWithProgress: '2つの項目を統合',
        mergeWizard: '統合ウィザード',
        pleaseWait: 'お待ちください...',
        postpone: '延期',
        postponeTitle: 'この項目のIDを保存し、統合を延期します',
        unwatchOption: '統合された項目をウォッチリストから除去する(ウォッチリストにある場合)',
        unwatching: 'ウォッチリストからの除去中...'
      },
      ko: {
        conflictMessage: '항목 충돌 감지됨: ',
        conflictWithMessage: '와',
        createRedirect: '넘겨주기를 만들기',
        creatingRedirect: '넘겨주기 생성중...',
        loadingMergeDestination: '병합한 내용을 불러오는 중입니다...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "이 항목과 병합할 다른 항목" entity)',
        merge: '병합',
        mergePendingNotification: 'Merge.js 가 시작되었습니다.<br>이제 다른 작업을 하셔도 됩니다.',
        mergeProcess: '병합을 시작합니다.',
        mergeThisEntity: '이 항목을 병합',
        mergeWithInput: '이 항목과 병합할 다른 항목:',
        mergeWithProgress: '항목 병합 마법사',
        mergeWizard: '항목 병합 마법사',
        pleaseWait: '잠시만 기다리세요...',
        postpone: '연기',
        postponeTitle: '항목 번호 \'를 기억하고 병합을 일시 정지',
        unwatchOption: '주시문서 목록에서 제거합니다 (주시중인 문서일 경우)',
        unwatching: '주시문서 목록에서 제거중...'
      },
      lb: {
       conflictMessage: 'Et gouf e Konflikt fonnt op ',
       conflictWithMessage: 'mat',
       createRedirect: 'Eng Viruleedung uleeën ',
       creatingRedirect: 'Eng Viruleedung gëtt ugeluecht...',
       errorWhile: 'Feeler bei "$1":',
       invalidInput: 'Aktuell ass nëmme d\'Qid e valabele Wäert.',
       loadMergeDestination: 'D\'Zilsäit vun der Fusioun luede wann et funktionéiert',
       loadingMergeDestination: 'D\'Zilsäit vun der Fusioun gëtt gelueden...',
       lowestEntityId: 'Ëmmer an dat méi aalt Element fusionéieren (net uklicke fir et an d\'Element "Fusionéiert et mat" ze fusionéieren)',
       merge: 'Fusionéieren',
       mergePendingNotification: 'Merge.js gouf gestart. Elo kënnt Dir Iech an Ärem Browser op dat anert Element konzentréieren.',
       mergeProcess: 'Maacht d\'Fusioun elo',
       mergeSummary: 'Setzt dësen Text hannert den automatesch generéierte Resumé vun der Ännerung derbäi:',
       mergeThisEntity: 'Fusionéiert dëst Element',
       mergeWithInput: 'Fusionéiert et mat:',
       mergeWithProgress: 'Fusionéiert et mat...',
       mergeWizard: 'Fusiouns-Wizard',
       pleaseWait: 'Waart w.e.g....',
       postpone: 'Spéider maachen',
       postponeTitle: 'Dësem Element seng Nummer verhalen an d\'Fusioun op méi spéit verleeën',
       //reportError: 'Mellt de Feeler hei driwwer w.e.g. [[hei]] mat der Quell an dem Zil vun der Fusioun.',
       selectForMerging: 'Eraussiche fir ze fusionéieren',
       selectForMergingTitle: 'Dëst Element verhalen als dat zweet vun den Elementer déi fusionéiert gi sollen',
       unwatchOption: 'Fusionéiert Elementer vun Ärer Iwwerwaachungslëscht erofhuelen (wa se iwwerwaacht sinn)',
       unwatching: 'Vun der Iwwerwaachungslëscht erofhuelen...'
      },
      min: {
        conflictMessage: 'Ado konflik tadeteksi pado ',
        conflictWithMessage: 'jo',
        loadingMergeDestination: 'Loading tujuan panggabuangan...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "Gabuang jo" entity)',
        merge: 'Gabuang',
        mergePendingNotification: 'Merge.js dimulai.<br>Kini Sanak dapek fokus pado item lain.',
        mergeProcess: 'Lakukan panggabuangan',
        mergeThisEntity: 'Gabuangkan item ko',
        mergeWithInput: 'Gabuang jo:',
        mergeWithProgress: 'Gabuangkan',
        mergeWizard: 'Pakakeh panggabuangan',
        pleaseWait: 'Mohon tunggu sabanta...',
        postpone: 'Tunda',
        postponeTitle: 'Simpan item dan tunda panggabuangan',
        unwatchOption: 'Hapuih item nan digabuang dari pantauan (kok ado)',
        unwatching: 'Hapuih dari daftar pantauan...'
      },
      mk: {
        conflictMessage: 'Утврдена спротиставеност во ',
        conflictWithMessage: 'со',
        createRedirect: 'Направи пренасочување',
        creatingRedirect: 'Правам пренасочување...',
        errorWhile: 'Грешка при „$1“:',
        invalidInput: 'Во мигов може да се внесе само Qid',
        loadMergeDestination: 'Вчитај ја целната страница при успешно спојување',
        loadingMergeDestination: 'Ја вчитувам целната страница на спојувањето...',
        lowestEntityId: 'Секогаш припојувај кон постариот предмет (отштиклирајте за да припоите во предметот „Спој со“)',
        merge: 'Спој',
        mergePendingNotification: 'Merge.js е започнат.<br>Сега можете да го отворите другиот предмет.',
        mergeProcess: 'Спроведи го спојувањето сега',
        mergeSummary: 'Придодај го следниов текст кон самосоздадениот опис на дејството:',
        mergeThisEntity: 'Спој го предметов',
        mergeWithInput: 'Спој со:',
        mergeWithProgress: 'Спој со...',
        mergeWizard: 'Спојувач',
        pleaseWait: 'Почекајте...',
        postpone: 'Одложи',
        postponeTitle: 'Зачувај ги предметните назнаки и одложи го спојувањето',
        //reportError: 'Пријавете ја грешката [[тука]] со изворната и целната страница на спојувањето.',
        selectForMerging: 'Избери за спојување',
        selectForMergingTitle: 'Запомни го предметов како втор од двата што се спојуваат',
        unwatchOption: 'Отстрани ја споената страница од набљудуваните (ако е таму)',
        unwatching: 'Отстранувам од набљудуваните...'
      },
      nb: {
        conflictMessage: 'En konflikt ble oppdaget i ',
        conflictWithMessage: 'med',
        createRedirect: 'Opprett omdirigering',
        creatingRedirect: 'Oppretter omdirigering...',
        errorWhile: 'Feil mens «$1»:',
        invalidInput: 'Kun Qid er gyldig innputt for øyeblikket',
        loadingMergeDestination: 'Laster flettemål...',
        lowestEntityId: 'Flett alltid inn i det gamle elementet (fjern merking for å flette til elementet i «Flett med»)',
        merge: 'Flett',
        mergePendingNotification: 'Merge.js har startet.<br>Du kan nå endre vindu til det andre elementet.',
        mergeProcess: 'Gjennomfør flettingen nå',
        mergeSummary: 'Legg til følgende tekst til det automatiske redigeringssammendraget:',
        mergeThisEntity: 'Flett elementet',
        mergeWithInput: 'Flett med:',
        mergeWithProgress: 'Flett med...',
        mergeWizard: 'Fletteveileder',
        pleaseWait: 'Vent...',
        postpone: 'Utsett',
        postponeTitle: 'Lagre elementets ID og utsett flettingen',
        //reportError: 'Rapporter feilen ovenfor [[her]] med kilde og mål for flettingen.',
        selectForMerging: 'Velg for fletting',
        selectForMergingTitle: 'Husk dette elementet som element nr. 2 av de som skal flettes',
        unwatchOption: 'Fjern flettet element fra overvåkningslista di',
        unwatching: 'Fjerner fra overvåkningsliste...'
      },
      nl: {
        conflictMessage: 'Een conflict werd gedetecteerd op ',
        conflictWithMessage: 'met',
        createRedirect: 'Maak een redirect aan',
        creatingRedirect: 'Redirect wordt aangemaakt...',
        errorWhile: 'Fout tijdens "$1":',
        invalidInput: 'Op dit moment kan alleen een Q-id worden opgegeven',
        loadMergeDestination: 'Bestemmingspagina van samenvoeging laden',
        loadingMergeDestination: 'Bestemmingspagina samenvoeging aan het laden...',
        lowestEntityId: 'Altijd samenvoegen naar het oudste item (het vinkje weghalen indien je samen wilt voegen naar het "Samenvoegen met"-item)',
        merge: 'Samenvoegen',
        mergePendingNotification: 'Merge.js is gestart.<br>Nu kunt u zich focussen op het andere item.',
        mergeProcess: 'Samenvoeging nu uitvoeren',
        mergeSummary: 'Voeg de volgende tekst toe aan de automatisch gegenereerde bewerkingssamenvatting:',
        mergeThisEntity: 'Dit item samenvoegen',
        mergeWithInput: 'Samenvoegen met:',
        mergeWithProgress: 'Samenvoegen',
        mergeWizard: 'Samenvoegingsassistent',
        pleaseWait: 'Even wachten...',
        postpone: 'Uitstellen',
        postponeTitle: 'Sla het id van het item op en stel de samenvoeging uit',
        //reportError: 'Rapporteer bovenstaande foutmelding [[hier]] met de oorsprong en bestemming van de samenvoeging.',
        selectForMerging: 'Selecteer voor samenvoegen',
        selectForMergingTitle: 'Onthoud dit item als de tweede van de twee items die samengevoegd moeten gaan worden',
        unwatchOption: 'Verwijder samengevoegde items van volglijst (als deze erop staan)',
        unwatching: 'Verwijderen van volglijst...'
      },
      pl: {
        conflictMessage: 'Wykryto konflikt ',
        conflictWithMessage: 'z',
        createRedirect: 'Utwórz przekierowanie',
        creatingRedirect: 'Tworzenie przekierowania...',
        loadingMergeDestination: 'Ładowanie łączonego elementu...',
        loadMergeDestination: 'Załaduj połączony element',
        lowestEntityId: 'Zawsze łącz ze starszym elementem',
        merge: 'Połącz',
        mergePendingNotification: 'Merge.js zostało uruchomione.<br>Możesz teraz przejść do innego elementu.',
        mergeProcess: 'Rozpocznij proces łączenia',
        mergeThisEntity: 'Połącz ten element',
        mergeWithInput: 'Połącz z elementem:',
        mergeWithProgress: 'Łączę z...',
        mergeWizard: 'Kreator łączenia',
        pleaseWait: 'Czekaj...',
        postpone: 'Odłóż na później',
        postponeTitle: 'Zapamiętaj identyfikator tego elementu i odłóż łączenie na później',
        selectForMerging: 'Zaznacz do połączenia',
        selectForMergingTitle: 'Zapamiętaj ten element jako drugi do połączenia dwóch elementów',
        unwatchOption: 'Usuń łączone elementy z mojej listy obserwowanych (jeśli na niej były)',
        unwatching: 'Usuwanie z listy obserwowanych...'
      },
      'pt-br': {
        conflictMessage: 'Um conflito detectado em ',
        conflictWithMessage: 'com',
        createRedirect: 'Criar um redirecionamento',
        creatingRedirect: 'Criando um redirecionamento...',
        errorWhile: 'Erro enquanto "$1":',
        invalidInput: 'Atualmente somente Qid é uma entrada válida',
        loadingMergeDestination: 'Carregando o destino da fusão...',
        lowestEntityId: 'Sempre faça a fusão no item mais antigo (desmarque para fundir no item "Fundir com")',
        merge: 'Fundir',
        mergePendingNotification: 'Merge.js foi iniciado.<br>Agora você pode focar o seu navegador no outro item.',
        mergeProcess: 'Processar a fusão agora',
        mergeSummary: 'Acrescentar o seguinte texto ao sumário de edição gerado automaticamente:',
        mergeThisEntity: 'Fundir este item',
        mergeWithInput: 'Fundir com:',
        mergeWithProgress: 'Fundir com...',
        mergeWizard: 'Assistente de fusões',
        pleaseWait: 'Por favor espere...',
        postpone: 'Adiar',
        postponeTitle: 'Armazenar o identificador deste item e adiar a fusão',
        //reportError: 'Favor reportar sobre o erro [[aqui]] com fonte e destinação da fusão.',
        selectForMerging: 'Selecionar para fusão',
        selectForMergingTitle: 'Memorizar esse item como o segundo de dois itens a serem fundidos',
        unwatchOption: 'Remover item fundido de sua lista de páginas vigiadas (se estiver vigiando)',
        unwatching: 'Removendo da lista de páginas vigiadas...'
      },
      sk: {
        conflictMessage: 'Detekovaný konflikt v ',
        conflictWithMessage: 's',
        createRedirect: 'Vytvoriť presmerovanie',
        creatingRedirect: 'Vytváram presmerovanie',
        loadingMergeDestination : 'Načítam výsledok spojenia...',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "Spojiť s" entity)',
        merge: 'Spojiť',
        mergePendingNotification: 'Skript Merge.js bol aktivovaný.<br>Teraz môžete vo vašom prehliadači prejsť na inú položku.',
        mergeProcess: 'Vykonať teraz spojenie',
        mergeThisEntity: 'Spojiť položku',
        mergeWithInput: 'Spojiť s:',
        mergeWithProgress: 'Spojiť s...',
        mergeWizard: 'Nástroj na spájanie',
        pleaseWait: 'Prosím čakajte...',
        postpone: 'Odložiť',
        postponeTitle: 'Uložiť id položky a odložiť spojenie',
        unwatchOption: 'Odstrániť spájané položky zo sledovaných stránok (ak sú sledované)',
        unwatching: 'Odstraňujem zo sledovaných stránok...'
      },
      uk: {
        conflictMessage: 'Виявлено конфлікт у ',
        conflictWithMessage: 'з',
        createRedirect: 'Створити перенаправлення',
        creatingRedirect: 'Створення перенаправлення...',
        errorWhile: 'Помилка при «$1»:',
        invalidInput: 'Наразі лише ідентифікатор (Qid) може бути валідними вхідними даними',
        loadingMergeDestination: 'Завантаження цільової сторінки до об\'єднання...',
        lowestEntityId: 'Завжди приєднувати до старішого елемента (зніміть позначку, щоб приєднати до елемента, вказаного в «Об\'єднати з»)',
        merge: 'Об\'єднати',
        mergePendingNotification: 'Merge.js було запущено.<br>Тепер Ви можете перемкнути свій браузер на інший елемент.',
        mergeProcess: 'Виконати об\'єднання зараз же',
        mergeSummary: 'Додати цей текст до автоматичного опису редагування:',
        mergeThisEntity: 'Приєднати цей елемент',
        mergeWithInput: 'Об\'єднати з:',
        mergeWithProgress: 'Об\'єднати з...',
        mergeWizard: 'Майстер об\'єднання',
        pleaseWait: 'Зачекайте, будь ласка...',
        postpone: 'Відкласти',
        postponeTitle: 'Збережіть ідентифікатор цього елемента та відкладіть об\'єднання на пізніше',
        //reportError: 'Будь ласка, повідомте про помилку [[отут]], вказавши вихідний та цільовий елементи до об\'єднання.',
        selectForMerging: 'Вибрати для об\'єднання',
        selectForMergingTitle: 'Запам\'ятати цей елемент як другий з тих, котрі треба об\'єднати',
        unwatchOption: 'Вилучити приєднаний елемент з Вашого списку спостереження (якщо він був у ньому)',
        unwatching: 'Вилучення зі списку спостереження...'
      },
      'zh-hans': {
        conflictMessage: '存在跨语言冲突:',
        conflictWithMessage: '和',
        createRedirect: '创建重定向',
        creatingRedirect: '创建重定向中…',
        errorWhile: '"$1"时出错:',
        invalidInput: '目前只有一个Qid是有效的',
        loadMergeDestination: '成功加载目标项',
        loadingMergeDestination: '正在加载目标项……',
        lowestEntityId: 'Always merge into the older entity (uncheck to merge into the "要和此项合并的数据项" entity)',
        merge: '合并',
        mergePendingNotification: 'Merge.js已经运行,请前往其他需要合并的项。',
        mergeProcess: '开始合并',
        mergeSummary: '将以下文本添加到自动生成的编辑摘要中:',
        mergeThisEntity: '合并此项',
        mergeWithInput: '要和此项合并的数据项:',
        mergeWithProgress: '合并',
        mergeWizard: '合并数据项',
        pleaseWait: '请稍候……',
        postpone: '和其他项合并',
        postponeTitle: '储存此项编号以和其他项合并',
        //reportError: '请将上述错误报告到[[这里]],包括合并的来源及目的地',
        selectForMerging: '选择合并项',
        selectForMergingTitle: '记住这个项目是要合并的两个项目中的第二个项目。',
        unwatchOption: '若可能,从监视列表移除重复项',
        unwatching: '正在从监视列表移除重复项……',
      }
    },
      chain = mw.language.getFallbackLanguageChain(),
      len = chain.length,
      ret = {},
      i = len - 1;
    while (i >= 0) {
      if (translations.hasOwnProperty(chain[i])) {
        $.extend(ret, translations[chain[i]]);
      }
      i = i - 1;
    }
    return ret;
  }());

  /**
   * Retrieve items by id
   */
  function getItems(ids) {
    return api.get({
      action: 'wbgetentities',
      ids: ids.join('|')
    }).then(function (data) {
      return Object.keys(data.entities).map(function (x) { return data.entities[x]; });
    });
  }

  /**
   * Set a Storage to postpone merge and deletion
   */
  function mergePending(id) {
    mw.storage.set('merge-pending-id', id);
    mw.notify($.parseHTML(messages.mergePendingNotification));
  }

  /**
   * ...and reset this Storage
   */
  function removePending() {
    mw.storage.remove('merge-pending-id');
  }


  /**
   * Check if items can be merged
   */
  function detectConflicts(items) {
    var all = {},
      conflicts = {};
    items.forEach(function (item) {
      if (!item.sitelinks) { return; }
      Object.keys(item.sitelinks).forEach(function (dbName) {
        if (all[dbName] && all[dbName].sitelinks[dbName].title !== item.sitelinks[dbName].title) {
          if (!conflicts[dbName]) {
            conflicts[dbName] = [all[dbName]];
          }
          conflicts[dbName].push(item);
        }
        all[dbName] = item;
      });
    });
    return conflicts;
  }

  /**
   * Create a redirect
   */
  function createRedirect(fromId, toId) {
    // ugly hack, we have to clear the entity first before creating the redirect...
    return api.postWithEditToken({
      action: 'wbeditentity',
      id: fromId,
      clear: true,
      summary: 'Clearing item to prepare for redirect',
      data: '{}'
    }).then(function () {
      return api.postWithEditToken({
        action: 'wbcreateredirect',
        from: fromId,
        to: toId
      });
    });
  }


  /**
   * Moving logic
   */
  function mergeApi(from, to, mergeSummary) {
    var data;
    if (from.indexOf('L') === 0) {
      data = {
        action: 'wblmergelexemes',
        source: from,
        target: to,
      };
    } else {
      data = {
        action: 'wbmergeitems',
        fromid: from,
        toid: to,
        ignoreconflicts: 'description', // ignore descriptions conflicts as old version of merge did
      };
    }
    data.summary = '[[MediaWiki:Gadget-Merge.js|merge.js]] ' + mergeSummary;
    return api.postWithEditToken(data);
  }

  /**
   * @class Merger
   * @mixins OO.EventEmitter
   *
   * @constructor
   */
  function Merger(mergeItems, mergeSummary, alwaysLowestId, unwatch, mergeCreateRedirect, loadMergeDestination) {
    OO.EventEmitter.call(this);
    this.mergeItems = mergeItems;
    this.mergeSummary = mergeSummary;
    if (/^\w/.test(this.mergeSummary)) {
      this.mergeSummary = ' ' + this.mergeSummary;
    }
    this.alwaysLowestId = alwaysLowestId;
    this.unwatch = unwatch;
    this.mergeCreateRedirect = mergeCreateRedirect;
    this.loadMergeDestination = loadMergeDestination;
  }
  OO.mixinClass(Merger, OO.EventEmitter);

  /**
   * Merge process
   */
  Merger.prototype.merger = function (from, to) {
    var self = this;
    self.emit('progress', messages.mergeWithInput + ' ' + to);
    var redirected;
    var deferred = mergeApi(from, to, self.mergeSummary)
        .then(function (data) {
            redirected = data.redirected;
            return $.Deferred().resolve();
        });

    if (self.unwatch) {
      deferred = deferred.then(function () {
        self.emit('progress', messages.unwatching);
        return api.unwatch(from);
      });
    }

    if (self.mergeCreateRedirect) {
      deferred = deferred.then(function () {
        if (redirected) { // don't create redirect if already redirected
          return $.Deferred().resolve();
        }
        self.emit('progress', messages.creatingRedirect);
        return createRedirect(from, to);
      });
    }

    deferred.then(function () {
      if (self.loadMergeDestination) {
        self.emit('progress', messages.loadingMergeDestination);
        var target = mw.config.get('wgPageName').replace(from, to);
        // Purge (via API), then reload.
        // XXX: Do we even need to purge? Why?
        api.post({
          action: 'purge',
          titles: target
        }).then(function () {
          window.location = mw.util.getUrl(target);
        });
      } else {
        self.emit('success');
      }
    }, function (code, result) {
      self.emit('error', result.error.extradata[0] || result.error.info);
    });
  };


  /**
   * Merge button action, pre-merge checks
   */
  Merger.prototype.merge = function () {
    var self = this,
      itemsNames = [$.trim(self.mergeItems).toUpperCase(), entityId],
      isAllQ = itemsNames.every(function (x) { return /^Q\d*$/i.test(x); }),
      isAllL = itemsNames.every(function (x) { return /^L\d*$/i.test(x); });
    if (!(isAllQ || isAllL)) {
      $('#merge-input-validation-message').text(messages.invalidInput);
      return;
    }
    self.emit('progress', messages.pleaseWait);
    getItems(itemsNames).then(function (items) {
      // duplicate item if just an item is returned
      // if item was being merged to itself this could conflict error that also useful for debugging conflict detector
      if (items.length === 1) {
        items = items.concat(items);
      }

      var conflicts = detectConflicts(items),
        message;
      if (Object.keys(conflicts).length === 0) {
        if (self.alwaysLowestId) {
          items.sort(function (x, y) { return +x.id.replace(/^[QL]/i, '') - y.id.replace(/^[QL]/i, ''); }); // sort by Qid _only_if_specified_
        }
        self.merger(items[1].id, items[0].id);
      } else {
        message = Object.keys(conflicts).map(function (i) {
          var x = conflicts[i];
          return '<br>' + messages.conflictMessage + i + ':' + x.map(function (y, j) {
            return ' [[' + x[j].id + ']] ' + messages.conflictWithMessage +
              ' [[' + i + ':' + y.sitelinks[i].title + ']]';
          }).join(',');
        }).join('').replace(/\[\[([^\]\:]*?)\:([^\]]*?)\]\]/g, function (x, y, z) {
          return mw.html.element( 'a', { href: wikibase.sites.getSite(y).getUrlTo(z) }, y + ':' + z );
        });
        self.emit('error', message, true);
      }
    });
  };

  /**
   * @class MergeDialog
   * @extends OO.ui.ProcessDialog
   *
   * @constructor
   * @param {Object} config Configuration options
   * @cfg {string} entityId Entity ID
   */
  function MergeDialog(config) {
    MergeDialog.parent.call(this, config);
    this.entityId = config.entityId;
  }
  OO.inheritClass(MergeDialog, OO.ui.ProcessDialog);
  
  MergeDialog.static.name = 'mergeDialog';
  MergeDialog.static.title = messages.mergeWizard;
  MergeDialog.static.size = 'medium';
  MergeDialog.static.actions = [
    {
      action: 'postpone',
      label: messages.postpone,
      title: messages.postponeTitle,
      flags: 'progressive'
    },
    {
      action: 'merge',
      label: messages.merge,
      title: messages.mergeProcess,
      flags: ['primary', 'constructive']
    },
    {
      action: 'cancel',
      label: mw.msg('ooui-dialog-message-reject'),
      flags: 'safe'
    }
  ];
  
  /**
   * @inheritdoc
   */
  MergeDialog.prototype.initialize = function () {
    MergeDialog.parent.prototype.initialize.apply(this, arguments);
    var fieldset = new OO.ui.FieldsetLayout({});
    this.entitySelector = new OO.ui.TextInputWidget({
      value: this.entityId
    });
    fieldset.addItems([
      new OO.ui.FieldLayout(
        this.entitySelector,
        {
          align: 'left',
          label: messages.mergeWithInput
        }
      )
    ]);
    fieldset.$element.append($('<span>', {
      id: 'merge-input-validation-message',
      style: 'color: red;'
    }));
    this.mergeSummary = new OO.ui.TextInputWidget({});
    fieldset.addItems([
      new OO.ui.FieldLayout(
        this.mergeSummary,
        {
          align: 'left',
          label: messages.mergeSummary
        }
      )
    ]);
    this.mergeAlwaysLowestId = new OO.ui.CheckboxInputWidget({
      selected: true
    });
    fieldset.addItems([
      new OO.ui.FieldLayout(
        this.mergeAlwaysLowestId,
        {
          align: 'inline',
          label: messages.lowestEntityId
        }
      )
    ]);
    this.mergeCreateRedirect = new OO.ui.CheckboxInputWidget({
      selected: true,
      disabled: true
    });
    fieldset.addItems([
      new OO.ui.FieldLayout(
        this.mergeCreateRedirect,
        {
          align: 'inline',
          label: messages.createRedirect
        }
      )
    ]);
    this.mergeUnwatch = new OO.ui.CheckboxInputWidget({
      selected: mw.storage.get('merge-unwatch') === true
    });
    fieldset.addItems([
      new OO.ui.FieldLayout(
        this.mergeUnwatch,
        {
          align: 'inline',
          label: messages.unwatchOption
        }
      )
    ]);
    this.loadMergeDestination = new OO.ui.CheckboxInputWidget({
      selected: mw.storage.get('merge-load-destination') !== false
    });
    fieldset.addItems([
      new OO.ui.FieldLayout(
        this.loadMergeDestination,
        {
          align: 'inline',
          label: messages.loadMergeDestination
        }
      )
    ]);
    var content = new OO.ui.PanelLayout({
      padded: true,
      expanded: false
    });
    content.$element.append(fieldset.$element);
    this.$body.append(content.$element);
    var self = this;
    this.actions.once('add', function () {
      self.actions.setAbilities({ postpone: self.entityId === '' });
    });
    this.$element.prop('lang', $('html').prop('lang'));
  };

  /**
   * @inheritdoc
   */
  MergeDialog.prototype.getReadyProcess = function (data) {
    return MergeDialog.parent.prototype.getReadyProcess.call(this, data)
      .next(function () {
        // focus "Merge with" field:
        // https://www.wikidata.org/wiki/?oldid=333747825#Request:_Improvements_for_keyboard_navigation
        this.entitySelector.focus();
      }, this);
  };

  /**
   * Save options in storage
   */
  MergeDialog.prototype.saveOptions = function () {
    mw.storage.set('merge-always-lowest-id', this.mergeAlwaysLowestId.isSelected());
    mw.storage.set('merge-unwatch', this.mergeUnwatch.isSelected());
    mw.storage.set('merge-create-redirect', this.mergeCreateRedirect.isSelected());
    mw.storage.set('merge-load-destination', this.loadMergeDestination.isSelected());
  };

  MergeDialog.prototype.merge = function () {
    var self = this;
    this.saveOptions();
    removePending();
    var merger = new Merger(
      this.entitySelector.getValue(),
      this.mergeSummary.getValue(),
      this.mergeAlwaysLowestId.isSelected(),
      this.mergeUnwatch.isSelected(),
      this.mergeCreateRedirect.isSelected(),
      this.loadMergeDestination.isSelected()
    );
    merger.on('progress', function () {
      self.displayProgress.apply(self, arguments);
    });
    merger.on('error', function () {
      self.displayError.apply(self, arguments);
    });
    merger.on('success', function () {
      self.close();
      $('#ca-merge-queue-process, #ca-merge, #ca-merge-select').remove();
    });
    merger.merge();
  };

  MergeDialog.prototype.postpone = function () {
    this.saveOptions();
    mergePending(entityId);
    this.close();
  };

  /**
   * @inheritdoc
   */
  MergeDialog.prototype.getActionProcess = function (action) {
    if (action === 'merge') {
      return new OO.ui.Process(this.merge, this);
    }
    if (action === 'postpone') {
      return new OO.ui.Process(this.postpone, this);
    }
    if (action === 'cancel') {
      return new OO.ui.Process(this.close, this);
    }
    return MergeDialog.parent.prototype.getActionProcess.call(this, action);
  };

  /**
   * Display progress on form dialog
   */
  MergeDialog.prototype.displayProgress = function (message) {
    if (this.$progressMessage) {
      this.$progressMessage.text(message);
      this.updateSize();
      return;
    }
    this.$body.children().hide();
    this.actions.forEach(null, function (action) {
      action.setDisabled(true); // disable buttons
    });
    this.$progressMessage = $('<span>').text(message);
    this.pushPending();
    $('<div>').css({
      'text-align': 'center',
      'margin': '3em 0',
      'font-size': '120%'
    }).append(
      this.$progressMessage
    ).appendTo(this.$body);
    this.updateSize();
  };

  /**
   * Display error on form dialog
   */
  MergeDialog.prototype.displayError = function (error, hideReportLink) {
    var reportLink;
    this.$body.children().hide();
    while (this.isPending()) {
      this.popPending();
    }
    this.actions.forEach(null, function (action) {
      // reenable 'cancel' button, disable all other buttons
      // https://www.wikidata.org/wiki/?oldid=323115101#Close.2FCancel
      action.setDisabled(action.getAction() !== 'cancel');
    });
    if (hideReportLink === true) {
      reportLink = '';
    } else {
      reportLink = '<p>' + messages.reportError.replace(/\[\[(.*)\]\]/, '<a href="//wiki.personaldata.io/w/index.php?title=MediaWiki_talk:Gadget-Merge.js&action=edit&section=new" target="_blank">$1</a>') + '</p>';
    }
    this.$body.append($('<div>', {
      style: 'color: #990000; margin-top: 0.4em;',
      html: '<p>' + messages.errorWhile.replace(/\$1/, this.$progressMessage.text()) + ' ' + error + '</p>' + reportLink
    }));
    this.updateSize();
  };

  /**
   * Dialog creator and launcher
   */
  function launchDialog(id) {
    if (typeof id !== 'string') {
      id = '';
    }
    var dialog = new MergeDialog({
      entityId: id
    });
    var windowManager = new OO.ui.WindowManager();
    $('body').append(windowManager.$element);
    windowManager.addWindows([dialog]);
    windowManager.openWindow(dialog);
  }
  
  // Initialization
  if (entityId !== null &&
      [120, 146].indexOf(mw.config.get('wgNamespaceNumber')) !== -1 &&
      mw.config.get('wgAction') === 'view') {
    $(window).on('focus storage', function () {
      $('#ca-merge-queue-process').remove();
      if (mw.storage.get('merge-pending-id') !== null &&
          mw.storage.get('merge-pending-id') !== '' &&
          mw.storage.get('merge-pending-id') !== entityId) {
        $('#p-views ul')[$(document).prop('dir') === 'rtl' ? 'append' : 'prepend']($('<li>', {
          id: 'ca-merge-queue-process'
        }).append($('<a>', {
          href: '#',
          title: 'process the postponed merge'
        }).append($('<img>', {
          src: '//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Pictogram_voting_merge.svg/26px-Pictogram_voting_merge.svg.png',
          alt: 'merge icon'
        }))).click(function (event) {
          event.preventDefault();
          launchDialog(mw.storage.get('merge-pending-id'));
        }));
      }
    });
    $(function () {
      $('#ca-merge-queue-process, #ca-merge, #ca-merge-select').remove();
      $(mw.util.addPortletLink(
        'p-cactions',
        '#',
        messages.mergeWithProgress,
        'ca-merge',
        messages.mergeThisEntity
      )).click(function (event) {
        event.preventDefault();
        launchDialog();
      });

      $(mw.util.addPortletLink(
        'p-cactions',
        '#',
        messages.selectForMerging,
        'ca-merge-select',
        messages.selectForMergingTitle
      )).click(function (event) {
        event.preventDefault();
        mergePending(entityId);
      });
    });
  }

  // Export section
  // currently just for [[MediaWiki:Gadget-EmptyDetect.js]], just launchDialog is exposed
  window.mergeTool = {
    launchDialog: launchDialog
  };

}(jQuery, mediaWiki, OO));