MediaWiki:Gadget-Merge.js
Revisión del 08:48 9 abr 2014 de Bth0 (discusión | contribuciones) (Página creada con «// ENABLE IT FROM YOUR PREFERENCES: www.wikidata.org/wiki/Special:Preferences#mw-prefsection-gadgets /*! * merge.js - Script to merge Wikidata items * @author User:Ebrami...»)
// ENABLE IT FROM YOUR PREFERENCES: www.wikidata.org/wiki/Special:Preferences#mw-prefsection-gadgets /*! * merge.js - Script to merge Wikidata items * @author User:Ebraminio <ebrahim -at- gnu.org> * @contributors User:Ebraminio, User:Ricordisamoa * @license CC-Zero */ /*jslint browser: true, regexp: true, indent: 2, unparam: true*/ /*jshint unused: false*/ /*global jQuery, mediaWiki, wikibase*/ // See also: MediaWiki:Gadget-EmptyDetect.js and MediaWiki:Gadget-RfDHelper.js //<nowiki> (function ($, mw) { 'use strict'; var messages, itemId = mw.config.get('wbEntityId'); messages = (function () { var translations = { 'en': { close: 'Close', closeDialog: 'Close this dialog without merging the items', confilictMessage: 'A conflict detected on ', confilictWithMessage: 'with', deleteOption: 'Try to automatically delete extra items after merge (only admins)', deleting: 'Deleting...', deletingItem: 'Deleting the item...', itemDeleterAccessError: 'You aren\'t an administrator', itemIdInvalid: 'The item\'s id is not defined', loadingMergeDestination: 'Loading merge destination...', lowestQid: 'Always merge into the item with lowest Qid', merge: 'Merge', mergePendingNotification: 'Merge.js has been started.<br/>Now you can focus your browser on the other item.', mergeProcess: 'Process the merge now', mergeThisItem: 'Merge this item', mergeWithInput: 'Merge it with:', mergeWithProgress: 'Merge it with...', mergeWizard: 'Merge Wizard', mergingClaim: 'Merging claims...', movingClaim: 'Moving claims...', movingSitelink: 'Moving site links...', pleaseWait: 'Please wait...', postpone: 'Postpone', postponeTitle: 'Store this item\'s id and postpone the merge', processPostponed: 'process the postponed merge', requestDeletion: 'Request deletion for extra items on RfD', requestingDeletion: 'Requesting deletion...', requestingStreamDeletion: 'Requesting Stream Deletion...', sendingToRfd: 'Sending to RfD...', streamDelete: 'Request $1StreamDeletion$2 for this item (experimental)', unwatchOption: 'Remove merged items from your watchlist (if watched)', unwatching: 'Removing from watch list...' }, 'cs': { close: 'Zavřít', closeDialog: 'Zavřít toto okno bez sloučení položek', confilictMessage: 'Detekován konflikt v', confilictWithMessage: 's', deleteOption: 'Pokusit se automaticky smazat extra položky po sloučení (pouze správci)', deleting: 'Mažu...', deletingItem: 'Mažu položku...', itemDeleterAccessError: 'Nejste správce', itemIdInvalid: 'Není zadáno id položky', loadingMergeDestination : 'Načítám výsledek sloučení...', lowestQid: 'Vždy sloučit do položky s nižším číslem', merge: 'Sloučit', mergePendingNotification: 'Skript Merge.js byl aktivován.<br/>Nyní můžete ve vašem prohlížeči přejít na jinou položku.', mergeProcess: 'Provést nyní sloučení', mergeThisItem: 'Sloučit položku', mergeWithInput: 'Sloučit s:', mergeWithProgress: 'Sloučit s...', mergeWizard: 'Nástroj pro slučování', mergingClaim: 'Slučuji tvrzení...', movingClaim: 'Přesunuji tvrzení...', movingSitelink: 'Přesunuji odkazy...', pleaseWait: 'Prosím čekejte...', postpone: 'Odložit', postponeTitle: 'Uložit id položky a odložit sloučení', processPostponed: 'provést odložené sloučení', requestDeletion: 'Požádat o smazání extra položek na RfD', requestingDeletion: 'Žádám o smazání...', requestingStreamDeletion: 'Žádám o smazání (StreamDelete)...', sendingToRfd: 'Posílám na RfD...', streamDelete: 'Požádat o $1StreamDelete$2 (experimentální)', unwatchOption: 'Odstranit slučované položky ze sledovaných stránek (jsou-li sledovány)', unwatching: 'Odstraňuji ze sledovaných stránek...' }, 'de': { close: 'Schließen', closeDialog: 'Schließen ohne Änderung', confilictMessage: 'Ein Konflikt wurde erkannt bei ', confilictWithMessage: 'mit', deleteOption: 'Lösche übrige Datenelemente nach dem Zusammenlegen (nur für Admins)', deleting: 'Lösche…', deletingItem: 'Lösche das Datenelement…', itemDeleterAccessError: 'Du musst Administrator sein, um Datenelemente zu löschen.', itemIdInvalid: 'Die Nummer des Datenelementes ist nicht definiert', loadingMergeDestination: 'Lade zusammengelegtes Datenelement…', lowestQid: 'Immer in das Datenelement mit der niedrigeren Q-Nummer zusammenlegen', merge: 'Zusammenlegen', mergePendingNotification: 'Merge.js wurde gestartet.<br/>Jetzt kannst du das andere Datenelement öffnen.', mergeProcess: 'Starte das Zusammenlegen jetzt', mergeThisItem: 'Lege das Datenelement zusammen', mergeWithInput: 'Zusammenlegen mit:', mergeWithProgress: 'Zusammenlegen mit…', mergeWizard: 'Assistent zum Zusammenlegen', mergingClaim: 'Lege Aussagen zusammen…', movingClaim: 'Verschiebe Aussagen…', movingSitelink: 'Verschiebe Wikipedia-Links…', pleaseWait: 'Bitte warte…', postpone: 'Verschieben', postponeTitle: 'Speichere die Nummer des Datenelementes und mach es zum Ziel einer Zusammenlegung', processPostponed: 'Starte das Zusammenlegen in das andere Datenelement', requestDeletion: 'Stelle Löschantrag für übrig gebliebene Datenelemente auf RfD', requestingDeletion: 'Stelle Löschantrag…', requestingStreamDeletion: 'Beantrage die Löschung bei StreamDelete…', sendingToRfd: 'Stelle Löschantrag auf RfD…', streamDelete: 'Beantrage die Löschung bei $1StreamDelete$2 (experimentell)', unwatchOption: 'Entferne zusammengelegte Datenelemente von der Beobachtungsliste (wenn beobachtet)', unwatching: 'Entferne von Beobachtungsliste…' }, 'es': { close: 'Cerrar', closeDialog: 'Cierra este diálogo sin fusionar los elementos', confilictMessage: 'Un conflicto detectado en ', confilictWithMessage: 'con', deleteOption: 'Probar a borrar automáticamente los elementos vacíos después de la fusión (solo administradores)', deleting: 'Borrando...', deletingItem: 'Borrando el elemento...', itemDeleterAccessError: 'No eres administrador/a', itemIdInvalid: 'El id del elemento no está definido', loadingMergeDestination: 'Cargando el destino de la fusión...', lowestQid: 'Fusionar siempre el elemento con el menor número de Qid (identificador de Q)', merge: 'Fusionar', mergePendingNotification: 'Merge.js empezó.<br/>Ahora puedes enfocar tu navegador en el otro elemento', mergeProcess: 'Proceder a la fusión ahora', mergeThisItem: 'Fusionar este elemento', mergeWithInput: 'Fusionarlo con:', mergeWithProgress: 'Fusionarlo con...', mergeWizard: 'Herramienta de fusión', mergingClaim: 'Fusionando las afirmaciones...', movingClaim: 'Moviendo las afirmaciones...', movingSitelink: 'Moviendo los enlaces de sitio...', pleaseWait: 'Por favor, espera...', postpone: 'Posponer', postponeTitle: 'Guardar el id de este elemento y posponer la fusión', processPostponed: 'procesar la fusión aplazada', requestDeletion: 'Solicitar el borrado de los elementos vacíos en RfD (Solicitud de borrador)', requestingDeletion: 'Solicitando eliminación...', requestingStreamDeletion: 'Solicitando la eliminación Stream...', sendingToRfd: 'Enviando a RfD...', streamDelete: 'Solicitar $1StreamDeletion$2 para este elemento (experimental)', unwatchOption: 'Eliminar los elementos fusionados de tu lista de seguimiento (si están)', unwatching: 'Eliminando de la lista de seguimiento...' }, 'fa': { close: 'بستن', closeDialog: 'بستن پنجره بدون ادغام آیتم\u200cها', confilictMessage: 'تداخل در ', confilictWithMessage: 'با', deleteOption: 'آیتم\u200cهای خالی را بعد از ادغام حذف کن (فقط برای مدیران)', deleting: 'در حال حذف\u200cکردن...', deletingItem: 'در حال حذف آیتم ...', itemIdInvalid: 'شناسهٔ آیتم تعریف نشده\u200cاست', loadingMergeDestination: 'بارگیری مقصد ادغام...', lowestQid: 'همیشه ادغام در شماره شناسهٔ کمتر انجام گیرد', merge: 'ادغام', mergePendingNotification: 'ابزار ادغام فعال شد<br/>هم\u200cاکنون می\u200cتوانید به صفحهٔ آیتم دیگر برای ادغام بروید.', mergeProcess: 'انجام دادن ادغام', mergeThisItem: 'ادغام این آیتم', mergeWithInput: 'ادغام\u200cکردن با:', mergeWithProgress: 'ادغام\u200cکردن با...', mergeWizard: 'ابزار ادغام', mergingClaim: 'ادغام اظهارات...', movingClaim: 'انتقال اظهارات...', movingSitelink: 'انتقال پیوند وب\u200cگاه\u200cها...', pleaseWait: 'صبر کنید ...', postpone: 'به تأخیر انداختن', postponeTitle: 'ذخیرهٔ شناسهٔ آیتم و به تاخیر انداختن ادغام', processPostponed: 'عمل به تأخیر انداختن ادغام انجام شد', requestDeletion: 'درخواست حذف برای آیتم\u200cهای خالی شده', requestText: 'درخواست $1', requestingDeletion: 'درحال درخواست حذف ...', requestingStreamDeletion: 'درحال ارسال درخواست حذف نمایشی...', sendingToRfd: 'ارسال برای درخواست حذف...', streamDelete: 'درخواست $1StreamDeletion$2 برای این آیتم (آزمایشی)', unwatchOption: 'حذف آیتم\u200cهای ادغام شده از فهرست پی\u200cگیری\u200cها', unwatching: 'حذف از پیگیری\u200cها...' }, 'fr': { close: 'Fermer', closeDialog: 'Fermer cette fenêtre sans fusionner les éléments', confilictMessage: 'Un conflit a été détecté sur ', confilictWithMessage: 'avec', deleteOption: 'Essayer de supprimer automatiquement les éléments en trop après la fusion (administrateurs seulement)', deleting: 'Suppression...', deletingItem: 'Suppression de l\'entrée...', itemDeleterAccessError: 'Vous n\'êtes pas un administrateur', itemIdInvalid: 'L\'identifiant de l\'élément n\'est pas défini', loadingMergeDestination: 'Chargement de la destination de fusion...', lowestQid: 'Toujours fusionner dans l\'élément avec le plus petit Qid', merge: 'Fusionner', mergePendingNotification: 'Merge.js a commencé.<br/>Vous pouvez maintenant consulter un autre élément.', mergeProcess: 'Procéder à la fusion maintenant', mergeThisItem: 'Fusionner cet élément', mergeWithInput: 'Fusionner avec :', mergeWithProgress: 'Fusionner avec...', mergeWizard: 'Outil de fusion', mergingClaim: 'Fusion des réclamations...', movingClaim: 'Déplacement des réclamations...', movingSitelink: 'Déplacement des liens de site...', pleaseWait: 'Attendez...', postpone: 'Repousser à plus tard', postponeTitle: 'Stocker cet identifiant et repousser à plus tard la fusion', processPostponed: 'procéder à la fusion repoussée', requestDeletion: 'Demander la suppression des éléments en trop dans les demandes de suppression', requestingDeletion: 'Demande de la suppression...', requestingStreamDeletion: 'Demande de la suppression de flux...', sendingToRfd: 'Envoi à RfD...', streamDelete: 'Demander une $1StreamDeletion$2 pour cet élément (expérimental)', unwatchOption: 'Retirer les éléments supprimés de votre liste de suivi (s\'ils étaient suivis)', unwatching: 'Retrait de la liste de suivi...' }, 'gl': { close: 'Pechar', closeDialog: 'Pecha este diálogo sen fusionar os elementos', confilictMessage: 'Un conflito detectado en ', confilictWithMessage: 'con', deleteOption: 'Probar a borrar automaticamente os elementos baleiros despois da fusión (só administradores)', deleting: 'Borrando...', deletingItem: 'Borrando o elemento...', itemDeleterAccessError: 'Non es administrador/a', itemIdInvalid: 'O id do elemento non está definido', loadingMergeDestination: 'Cargando o destino da fusión...', lowestQid: 'Fusionar sempre o elemento co menor número de Qid (identificador de Q)', merge: 'Fusionar', mergePendingNotification: 'Merge.js comezou.<br/>Agora podes enfocar o teu navegador no outro elemento', mergeProcess: 'Proceder á fusión agora', mergeThisItem: 'Fusionar este elemento', mergeWithInput: 'Fusionalo con:', mergeWithProgress: 'Fusionalo con...', mergeWizard: 'Ferramenta de fusión', mergingClaim: 'Fusionando as afirmacións...', movingClaim: 'Movendo as afirmacións...', movingSitelink: 'Movendo as ligazóns de sitio...', pleaseWait: 'Por favor, espera...', postpone: 'Pospoñer', postponeTitle: 'Gardar o id deste elemento e pospor a fusión', processPostponed: 'procesar a fusión aprazada', requestDeletion: 'Solicitar o borrado dos elementos baleiros en RfD (Solicitude de borrador)', requestingDeletion: 'Solicitando eliminación...', requestingStreamDeletion: 'Solicitando a eliminación Stream...', sendingToRfd: 'Enviando a RfD...', streamDelete: 'Solicitar $1StreamDeletion$2 para este elemento (experimental)', unwatchOption: 'Eliminar os elementos fusionados da túa lista de vixilancia (se están)', unwatching: 'Eliminando da lista de vixilancia...' }, 'gu': { close: 'બંધ કરો', closeDialog: 'લેખોને વિલીન કર્યા સિવાય આ સંદેશ બંધ કરો', confilictMessage: 'પર એક અથડામણ મળેલ છે', confilictWithMessage: 'સાથે', deleteOption: 'વિલીન કર્યા બાદ વધારાના લેખો સ્વચલિત રીતે દૂર કરવા પ્રયાસ કરો (ફક્ત પ્રબંધકો)', deleting: 'રદ થઈ રહ્યું છે...', deletingItem: 'લેખ રદ કરાઈ રહ્યો છે...', itemDeleterAccessError: 'તમે પ્રબંધક નથી', itemIdInvalid: 'આ લેખની ઓળખ અપાઈ નથી', loadingMergeDestination: 'વિલિન કરેલ લક્ષ્યાંક લાવાય રહ્યું છે...', lowestQid: 'હંમેશા સૌથી નીચા Q આંકડા સાથે લેખો વિલીન કરો', merge: 'વિલીનMerge', mergePendingNotification: 'Merge.js શરૂ થઈ ગયેલ છે.<br/> હવે તમે તમારું બ્રાઉઝર અન્ય લેખ પર કેન્દ્રિત કરી શકો છો.', mergeProcess: 'હમણા જ વિલિનીકરણની પ્રક્રિયા કરો કરો', mergeThisItem: 'આ લેખ વિલિન કરો', mergeWithInput: 'તેને સાથે વિલિન કરો:', mergeWithProgress: 'તેને સાથે વિલિન કરો...', mergeWizard: 'વિલિન વિઝાર્ડ', mergingClaim: 'દાવાઓ વિલિન કરાય છે...', movingClaim: 'દાવાઓ ખસેડાય છે...', movingSitelink: 'જાળસ્થળની કડીઓ ખસેડાઈ રહી છે...', pleaseWait: 'મહેરબાની કરીને રાહ જુઓ...', postpone: 'મુલતવી રાખોPostpone', postponeTitle: 'આ લેખની ઓળખ સાચવો અને વિલિનીકરણ મુલતવી રાખો', processPostponed: 'મુલતવી રાખેલ વિલિનિકરણ શરૂ કરો', requestDeletion: 'રદ કરવા માટેની વિનંતી ખાતે વધારાના લેખો દૂર કરવા વિનંતી કરો', requestingDeletion: 'રદ કરવા માટે વિનંતી કરાઈ રહી છે...', requestingStreamDeletion: 'સ્ટ્રિમ રદ કરવા વિનંતી કરાઈ રહી છે...', sendingToRfd: 'રદ કરવા માટે વિનંતી ખાતે મોકલાઈ રહ્યું છે...', streamDelete: 'આ લેખ માટે $1StreamDeletion$2 વિનંતી કરો (પ્રાયોગિક)', unwatchOption: 'વિલિન કરેલ લેખો તમારી ધ્યાનસૂચિમાંથી હટાવો (જો ધ્યાનસૂચિમાં હોય તો)', unwatching: 'ધ્યાનસૂચિમાંથી હટાવાય રહ્યું છે...' }, 'id': { close: 'Tutup', closeDialog: 'Tutup dialog ini tanpa menggabungkan item', confilictMessage: 'Ada konflik terdeteksi pada ', confilictWithMessage: 'dengan', deleteOption: 'Secara otomatis menghapus item tambahan setelah penggabungan (hanya admin)', deleting: 'Menghapus...', deletingItem: 'menghapus item...', itemDeleterAccessError: 'Anda bukan pengurus', itemIdInvalid: 'Item belum ditentukan', loadingMergeDestination: 'Loading tujuan penggabungan...', lowestQid: 'Selalu gabungkan dengan Qid item terendah', merge: 'Gabung', mergePendingNotification: 'Merge.js dimulai.<br/>Sekarang Anda dapat fokus pada item lain.', mergeProcess: 'Lakukan penggabungan', mergeThisItem: 'Gabungkan item ini', mergeWithInput: 'Gabung dengan:', mergeWithProgress: 'Gabungkan', mergeWizard: 'Peralatan penggabungan', mergingClaim: 'Gabungkan klaim...', movingClaim: 'Pindahkan klaim...', movingSitelink: 'Pindahkan interwiki...', pleaseWait: 'Mohon tunggu sebentar...', postpone: 'Tunda', postponeTitle: 'Simpan item dan tunda penggabungan', processPostponed: 'proses penggabungan yang ditunda', requestDeletion: 'Minta penghapusan pada item tambahan pada RfD', requestingDeletion: 'Permintaan penghapusan...', requestingStreamDeletion: 'Permintaan Penghapusan Stream...', sendingToRfd: 'Kirim ke RfD...', streamDelete: 'Permintaan $1Penghapusan Stream$2 pada item ini (eksperimental)', unwatchOption: 'Hapus item yang digabung dari pantauan (jika ada)', unwatching: 'Hapus dari daftar pantauan...' }, 'it': { close: 'Chiudi', closeDialog: 'Chiudi questa finestra senza unire gli elementi', confilictMessage: 'Rilevato un conflitto in ', confilictWithMessage: 'con', deleteOption: 'Cancella automaticamente gli elementi svuotati dopo l\'unione (solo amministratori)', deleting: 'Cancellazione...', deletingItem: 'Cancellazione dell\'elemento...', itemDeleterAccessError: 'Non sei un amministratore!', itemIdInvalid: 'Il numero Q dell\'elemento non è definito', loadingMergeDestination: 'Caricamento della destinazione...', lowestQid: 'Unisci sempre con l\'elemento col numero Q più piccolo', merge: 'Unione', mergePendingNotification: 'Merge.js è avviato.<br/>Adesso vai sulla pagina dell\'altro elemento.', mergeProcess: 'Effettua l\'unione adesso', mergeThisItem: 'Unisci questo elemento', mergeWithInput: 'Unisci con:', mergeWithProgress: 'Unione con l\'elemento...', mergeWizard: 'Unione guidata', mergingClaim: 'Unione delle dichiarazioni...', movingClaim: 'Trasferimento delle dichiarazioni...', movingSitelink: 'Trasferimento dei collegamenti linguistici...', pleaseWait: 'Aspetta...', postpone: 'Rimanda a dopo', postponeTitle: 'Memorizza l\'id di questo elemento e rimanda a dopo l\'unione', processPostponed: 'Elabora l\'unione rimandata', requestDeletion: 'Richiedi la cancellazione degli elementi svuotati', requestingDeletion: 'Richiesta di cancellazione...', requestingStreamDeletion: 'Richiesta di cancellazione con Stream...', sendingToRfd: 'Inserimento fra le richieste di cancellazione...', streamDelete: 'Richiedi la $1Cancellazione in Stream$2 per questo elemento (sperimentale)', unwatchOption: 'Rimuovi gli elementi uniti dagli osservati speciali (se presente)', unwatching: 'Rimozione dagli osservati speciali...' }, 'ja': { close: '閉じる', closeDialog: '項目を統合せずにこのダイアログを閉じます', confilictMessage: '衝突が検出されました: ', confilictWithMessage: 'と', deleteOption: '統合後に余分な項目の自動的な削除を試みる(管理者のみ)', deleting: '削除中...', deletingItem: '項目の削除中...', itemDeleterAccessError: 'あなたは管理者ではありません', itemIdInvalid: 'その項目のIDは定義されていません', loadingMergeDestination: '統合先の読込中...', lowestQid: 'Qから始まるIDが小さい方の項目を必ず統合先に選ぶ', merge: '統合', mergePendingNotification: 'Merge.js が動き出しました。<br/>もうブラウザで他の項目に切り替えても大丈夫です。', mergeProcess: '統合をいま実行します', mergeThisItem: 'この項目を統合する', mergeWithInput: '統合相手:', mergeWithProgress: '2つの項目を統合', mergeWizard: '統合ウィザード', mergingClaim: '主張の統合中...', movingClaim: '主張の移動中...', movingSitelink: 'サイトリンクの移動中...', pleaseWait: 'お待ちください...', postpone: '延期', postponeTitle: 'この項目のIDを保存し、統合を延期します', processPostponed: '延期された統合を処理する', requestDeletion: '残った余分な項目を削除依頼に出す', requestingDeletion: '削除依頼中...', requestingStreamDeletion: 'Stream Deletion 依頼中...', sendingToRfd: '削除依頼への送信中...', streamDelete: 'この項目の $1StreamDeletion$2 を依頼する(実験的)', unwatchOption: '統合された項目をウォッチリストから除去する(ウォッチリストにある場合)', unwatching: 'ウォッチリストからの除去中...' }, 'ko': { close: '닫기', closeDialog: '항목을 합치지 않고 항목 병합 마법사를 닫습니다', confilictMessage: '항목 충돌 감지됨: ', confilictWithMessage: '와', deleteOption: '항목 병합을 완료한뒤 다른 항목을 삭제합니다(관리자만 가능)', deleting: '삭제중...', deletingItem: '항목 삭제중...', itemDeleterAccessError: '귀하는 관리자가 아닙니다.', itemIdInvalid: '아이템이 정의되지 않았습니다.', loadingMergeDestination: '병합한 내용을 불러오는 중입니다...', lowestQid: '항상 낮은 Qid를 가진 항목으로 병합합니다.', merge: '병합', mergePendingNotification: 'Merge.js 가 시작되었습니다.<br/>이제 다른 작업을 하셔도 됩니다.', mergeProcess: '병합을 시작합니다.', mergeThisItem: '이 항목을 병합', mergeWithInput: '이 항목과 병합할 다른 항목:', mergeWithProgress: '항목 병합 마법사', mergeWizard: '항목 병합 마법사', mergingClaim: '서술 병합중....', movingClaim: '서술 이동중...', movingSitelink: '사이트링크 이동중...', pleaseWait: '잠시만 기다리세요...', postpone: '연기', postponeTitle: '항목 번호 \'를 기억하고 병합을 일시 정지', processPostponed: '미뤄 둔 병합을 진행중', requestDeletion: '병합 후 자동으로 RFD에 삭제를 요청합니다.', requestingDeletion: '삭제 요청중...', requestingStreamDeletion: 'Stream Deletion 요청중...', sendingToRfd: 'RfD에 요청 중...', streamDelete: '이 항목을 $1StreamDeletion$2 요청합니다. (실험)', unwatchOption: '주시문서 목록에서 제거합니다 (주시중인 문서일 경우)', unwatching: '주시문서 목록에서 제거중...' }, 'lb': { close: 'Zoumaachen', closeDialog: 'Dësen Dialog zoumaachen ouni d\'Elementer ze fusionéieren', confilictMessage: 'Et gouf e Konflikt fonnt op ', confilictWithMessage: 'mat', deleteOption: 'Versiche fir zousätzlech Elementer no der Fusioun automatesch ze läschen (nëmmen Adminen)', deleting: 'Läschen...', deletingItem: 'D\'Element gëtt geläscht...', itemDeleterAccessError: 'Dir sidd keen Administrateur', itemIdInvalid: 'D\'Nummer vum Element ass net definéiert', loadingMergeDestination: 'D\'Zilsäit vun der Fusioun gëtt gelueden...', lowestQid: 'Ëmmer op dat Element fusionéieren dat déi niddregest Q-Nummer huet', merge: 'Fusionéieren', mergePendingNotification: 'Merge.js gouf gestart.<br/>Elo kënnt dir Iech an Ärem Browser op dat anert Element konzentréieren.', mergeProcess: 'Maacht d\'Fusioun elo', mergeThisItem: 'Fusionéiert dêst Element', mergeWithInput: 'Fusionéiert et mat:', mergeWithProgress: 'Fusionéiert et mat...', mergeWizard: 'Fusiouns-Wizard', mergingClaim: 'Reklammatioune fusionéieren...', movingClaim: 'Reklammatioune réckelen...', movingSitelink: 'Linken op site réckelen...', pleaseWait: 'Waard w.e.g....', postpone: 'Spéider maachen', postponeTitle: 'Dësem Element seng Nummer verhalen an d\'Fusioun op méi spéit verleeën', processPostponed: 'déi verluechte Fusioun elo maachen', requestDeletion: 'Läsche vun zousätzlechen Elementer per RfD ufroen', requestingDeletion: 'Läschen ufroen...', requestingStreamDeletion: '\'Stream-Läschen\' ufroen...', sendingToRfd: 'Un RfD schécken...', streamDelete: '$1StreamDeletion$2 firr dëst Element ufroen (experimentell)', unwatchOption: 'Fusionéiert lementer vun Ärer Iwwerwaachungslëscht erofhuelen (wa se iwwerwaacht sinn)', unwatching: 'Vun der Iwwerwaachungslëscht erofhuelen...' }, 'min': { close: 'Tutuik', closeDialog: 'Tutuik dialog ko tanpa manggabuangan item', confilictMessage: 'Ado konflik tadeteksi pado ', confilictWithMessage: 'jo', deleteOption: 'Sacaro otomatih mangapuih item tambahan sasudah panggabuangan (hanyo admin)', deleting: 'Mangapuih...', deletingItem: 'mangapuih item...', itemDeleterAccessError: 'Sanak indak panguruih', itemIdInvalid: 'Item alun ditentuan', loadingMergeDestination: 'Loading tujuan panggabuangan...', lowestQid: 'Salalu gabungan jo Qid item tarandah', merge: 'Gabuang', mergePendingNotification: 'Merge.js dimulai.<br/>Kini Sanak dapek fokus pado item lain.', mergeProcess: 'Lakukan panggabuangan', mergeThisItem: 'Gabuangkan item ko', mergeWithInput: 'Gabuang jo:', mergeWithProgress: 'Gabuangkan', mergeWizard: 'Pakakeh panggabuangan', mergingClaim: 'Gabuangkan klaim...', movingClaim: 'Pindahan klaim...', movingSitelink: 'Pindahan interwiki...', pleaseWait: 'Mohon tunggu sabanta...', postpone: 'Tunda', postponeTitle: 'Simpan item dan tunda panggabuangan', processPostponed: 'proses panggabuangan nan ditunda', requestDeletion: 'Minta pangapuihan pado item tambahan di RfD', requestingDeletion: 'Pamintaan pangapuihan...', requestingStreamDeletion: 'Pamintaan Pangapuihan Stream...', sendingToRfd: 'Kirim ka RfD...', streamDelete: 'Pamintaan $1Pangapuihan Stream$2 pado item ko (eksperimental)', unwatchOption: 'Hapuih item nan digabuang dari pantauan (kok ado)', unwatching: 'Hapuih dari daftar pantauan...' }, 'nl': { close: 'Sluiten', closeDialog: 'Sluit dit venster zonder de items samen te voegens', confilictMessage: 'Een conflict werd gedetecteerd op ', confilictWithMessage: 'met', deleteOption: 'Proberen automatisch de extra items te verwijderen na samenvoegen (alleen moderatoren)', deleting: 'Verwijderen...', deletingItem: 'Item aan het verwijderen...', itemDeleterAccessError: 'Je bent geen moderator', itemIdInvalid: 'ID van het item is niet gedefineerd', loadingMergeDestination: 'Bestemmingspagina samenvoeging laden...', lowestQid: 'Altijd samenvoegen in het item met het laagste Qid', merge: 'Samenvoegen', mergePendingNotification: 'Merge.js is gestart.<br/>Nu kan je jezelf focussen op het andere item.', mergeProcess: 'Samenvoeging nu uitvoeren', mergeThisItem: 'Dit item samenvoegen', mergeWithInput: 'Samenvoegen met:', mergeWithProgress: 'Samenvoegen met...', mergeWizard: 'Samenvoegingsassistent', mergingClaim: 'Claims verplaatsen...', movingClaim: 'Verklaringen verplaatsen...', movingSitelink: 'Siteverwijzingen verplaatsen...', pleaseWait: 'Even wachten...', postpone: 'Uitstellen', postponeTitle: 'Sla het id van het item op en stel de samenvoeging uit', processPostponed: 'Voer de uitgestelde samenvoeging uit', requestDeletion: 'Verzoek verwijdering voor extra items op RfD', requestingDeletion: 'Verwijdering verzoeken...', requestingStreamDeletion: 'Streamverwijdering verzoeken...', sendingToRfd: 'Versturen naar RfD...', streamDelete: 'Verzoek $1StreamDeletion$2 voor dit item (experimenteell)', unwatchOption: 'Verwijder samengevoegde items van volglijst (als deze erop staan)', unwatching: 'Verwijderen van volglijst...' }, 'pl': { close: 'Zamknij', closeDialog: 'Zamknij okno bez łączenia elementów', confilictMessage: 'A conflict detected on ', confilictWithMessage: 'z', deleteOption: 'Spróbuj automatycznie usunąć puste elementy po zakończeniu łączenia (tylko dla administratorów)', deleting: 'Usuwanie...', deletingItem: 'Usuwanie elementu...', itemDeleterAccessError: 'Nie jesteś administratorem', itemIdInvalid: 'The item\'s id is not defined', loadingMergeDestination: 'Loading merge destination...', lowestQid: 'Zawsze łącz z elementem o niższym ID', merge: 'Łącz', mergePendingNotification: 'Merge.js has been started.<br/>Now you can focus your browser on the other item.', mergeProcess: 'Rozpocznij proces łączenia', mergeThisItem: 'Połącz ten element', mergeWithInput: 'Połącz z elementem:', mergeWithProgress: 'Połącz z...', mergeWizard: 'Merge Wizard', mergingClaim: 'Merging claims...', movingClaim: 'Moving claims...', movingSitelink: 'Moving site links...', pleaseWait: 'Czekaj...', postpone: 'Odłóż', postponeTitle: 'Store this item\'s id and postpone the merge', processPostponed: 'process the postponed merge', requestDeletion: 'Zgłoś puste elementy do usunięcia', requestingDeletion: 'Requesting deletion...', requestingStreamDeletion: 'Requesting Stream Deletion...', sendingToRfd: 'Wysyłanie zgłoszenia do usunięcia...', streamDelete: 'Request $1StreamDeletion$2 for this item (experimental)', unwatchOption: 'Usuń łączone elementy ze swojej listy obserwowanych (jeśli na niej były)', unwatching: 'Removing from watch list...' }, 'zh-hans': { close: '关闭', closeDialog: '关闭窗口但不合并数据项', confilictMessage: '存在跨语言冲突:', confilictWithMessage: '和', deleteOption: '尝试直接删除数据项', deleting: '删除中……', deletingItem: '数据项正在删除', itemDeleterAccessError: '您不是管理员', itemIdInvalid: '此数据项不存在', loadingMergeDestination: '加载目标项……', lowestQid: '并入编号较小的项', merge: '合并', mergePendingNotification: 'Merge.js已经运行,请前往其他需要合并的项。', mergeProcess: '开始合并', mergeThisItem: '合并此项', mergeWithInput: '要和此项合并的数据项:', mergeWithProgress: '合并', mergeWizard: '合并数据项', mergingClaim: '声明合并中……', movingClaim: '声明移动中……', movingSitelink: '站点链接移动中……', pleaseWait: '请稍候……', postpone: '和其他项合并', postponeTitle: '储存此项编号以和其他项合并', processPostponed: '和已储存项合并', requestDeletion: '提请删除重复项', requestingDeletion: '提请删除中……', requestingStreamDeletion: '提请StreamDeletion中……', sendingToRfd: '提请删除中……', streamDelete: '(试验中)提请$1StreamDeletion$2', unwatchOption: '若可能,从监视列表移除重复项', unwatching: '正在从监视列表移除重复项……' } }, languageNameParts = mw.config.get('wgUserLanguage').split('-'), lang; translations.no = translations.nb; if (languageNameParts[1] === 'hans' || languageNameParts[1] === 'cn' || languageNameParts[1] === 'sg' || languageNameParts[1] === 'my') { lang = 'zh-hans'; } else if (languageNameParts[1] === 'hant' || languageNameParts[1] === 'hk' || languageNameParts[1] === 'tw' || languageNameParts[1] === 'mo') { lang = 'zh-hant'; } else if (translations[languageNameParts[0]]) { lang = languageNameParts[0]; } else { lang = 'en'; } // return to fill messages, it is an object which is filled with local and en messages as fallback return $.extend(true, translations.en, translations[lang]); }()); /** * Display progress on form dialog */ function displayProgress(message) { if ($('#merge-progress-message').length !== 0) { $('#merge-progress-message').text(message); return; } $('#merge-form > *').hide(); $('#merge-form ~ .ui-dialog-buttonpane').hide(); // hide buttons $('<div />').css({ 'text-align': 'center', 'margin': '3em 0', 'font-size': '120%' }).append( $('<span />', { id: 'merge-progress-message', text: message }), '<br/><br/>', $('<progress />', { id: 'merge-progress' }).css({ 'display': 'block', 'margin': '1em auto 0', 'width': '50%' }) ).appendTo('#merge-form'); } /** * Display error on form dialog */ function displayError(error, hideReportLink) { $('#merge-form > *').hide(); $('#merge-form ~ .ui-dialog-buttonpane').hide(); // hide buttons var reportLink = '<p>Please report above error <a href="//www.wikidata.org/w/index.php?title=MediaWiki_talk:Gadget-Merge.js&action=edit§ion=new">here</a> with source and destination of merge.</p>'; if (hideReportLink === true) { reportLink = ''; } $('#merge-form').append($('<div />', { 'style': 'color: #990000; margin-top: 0.4em;', 'html': '<p>Error while "' + $('#merge-progress-message').text() + '": ' + error + '</p>' + reportLink })); } /** * Check if the user is an admin, and thus can delete items */ function canDelete() { return $.inArray('sysop', mw.config.get('wgUserGroups')) !== -1; } /** * Logger function */ function log(tag, m) { // console.log(tag, m); return; } /** * MediaWiki post request */ function post(data) { log('#post start:', data); return new mw.Api().post(data).always(log); } /** * Retrieve items by id */ function getItems(ids, callback) { post({ action: 'wbgetentities', ids: ids.join('|'), format: 'json' }).done(function (data) { callback($.map(data.entities, function (x) { return x; })); }); } /** * Set a Storage to postpone merge and deletion */ function mergePending(id) { $.jStorage.set('merge-pending-id', id); mw.notify($.parseHTML(messages.mergePendingNotification)); } /** * ...and reset this Storage */ function removePending() { $.jStorage.deleteKey('merge-pending-id'); } /** * Check if items can be merged */ function detectConflicts(items) { var all = {}, conflicts = {}; $.each(items, function (i) { if (items[i].sitelinks !== undefined) { $.each(items[i].sitelinks, function (j) { if (all[j] !== undefined) { if (conflicts[j] === undefined) { conflicts[j] = [all[j]]; } conflicts[j].push(items[i]); } all[j] = items[i]; }); } }); return conflicts; } /** * Sort items by their Q## id. Useful for detecting eligible item to merged into. */ function sortItemsId(items) { return $.map($.map(items, function (item) { return { item: item, id: parseInt(item.id.replace(/^Q/i, ''), 10) }; }).sort(function (x, y) { return x.id - y.id; }), function (item) { return item.item; }); } /** * Edit an item */ function editItem(id, data, summary, callback) { if (id === undefined) { displayError(messages.itemIdInvalid); return; } data.id = undefined; post({ action: 'wbeditentity', id: id, data: JSON.stringify(data), token: mw.user.tokens.get('editToken'), summary: summary }).done(callback).fail(function (message, data) { displayError(message + ', ' + data.error.info); }); } /** * Delete an item */ function deleteItem(id, reason, callback) { if (id === undefined) { displayError(messages.itemIdInvalid); return; } if (canDelete() === false) { displayError(messages.itemDeleterAccessError); return; } post({ action: 'delete', title: id, reason: reason, token: mw.user.tokens.get('editToken') }).done(callback); } /** * Clone just needed things */ function cloneCleanItem(item) { return { id: item.id, aliases: $.extend(true, {}, item.aliases), sitelinks: $.extend(true, {}, item.sitelinks), labels: $.extend(true, {}, item.labels), descriptions: $.extend(true, {}, item.descriptions) }; } /** * Check equality of claims */ function areEqualsClaims(a, b) { if (a.mainsnak === undefined || b.mainsnak === undefined) { return true; } return $.compareObject(a.mainsnak.datavalue, b.mainsnak.datavalue); } /** * Check equality of references */ function areEqualsReferences(a, b) { if (a.snaks === undefined && b.snaks === undefined) { return false; // is really possible? } return $.compareObject(a.snaks, b.snaks); } /** * Check equality of qualifiers */ function areEqualsQualifiers(a, b) { return $.compareObject(a, b); } /** * Abstraction to run actions serially. * @param callback Will be fired when all actions done */ function ActionsQueue(callback) { var index = 0, actions = []; this.add = function (action) { actions.push(action); }; this.start = function () { this.step(); }; this.step = function () { if (actions.length === index) { callback(); } else { index = index + 1; actions[index - 1](); // or index++ can be used instead these two lines } }; } // Test: // var actions = new ActionsQueue(function () { console.log('finished'); }); // actions.add(function () { setTimeout(actions.step, 1000); }); // actions.add(function () { setTimeout(actions.step, 1000); }); // actions.add(function () { actions.step(); }); // actions.start(); /** * <progress /> handler */ function ProgressHandler(actions, progress) { var max = 0, value = 0; this.add = function (x) { actions.add(x); max = max + 1; }; this.start = function () { progress.attr('max', max); actions.start(); }; this.step = function () { value = value + 1; progress.attr('value', value); actions.step(); }; } // var p = $('<progress />'), actions = new ProgressHandler(new ActionsQueue(function () { console.log('finished'); }), p); // p.appendTo('h1'); // actions.add(function () { setTimeout(actions.step, 1000); }); // actions.add(function () { setTimeout(actions.step, 1000); }); // actions.start(); /** * Set reference for claim */ function addReferenceToClaim(claim, reference, callback, mergeSummary) { post({ action: 'wbsetreference', format: 'json', statement: claim.id, snaks: JSON.stringify(reference.snaks), summary: mergeSummary, token: mw.user.tokens.get('editToken') }).done(callback); } /** * Override a claim */ function setClaim(claim, callback, mergeSummary) { post({ action: 'wbsetclaim', format: 'json', claim: JSON.stringify(claim), summary: mergeSummary, token: mw.user.tokens.get('editToken') }).done(callback); } /** * Add a claim */ function addClaim(to, claim, callback, summary) { // if snaktype is "novalue", seems there is no way to move the claim so give up for now if (claim.mainsnak.snaktype === "novalue") { callback(); return; } post({ action: 'wbcreateclaim', entity: to.id, summary: summary, property: claim.mainsnak.property, snaktype: claim.mainsnak.snaktype, value: JSON.stringify(claim.mainsnak.datavalue.value), token: mw.user.tokens.get('editToken') }).done(function (data) { var actions = new ActionsQueue(callback); if (claim.qualifiers !== undefined || claim.rank !== data.claim.rank) { actions.add(function () { var newClaim = $.extend(true, {}, data.claim); newClaim.qualifiers = claim.qualifiers; newClaim.rank = claim.rank; setClaim(newClaim, actions.step, summary); }); } if (claim.references !== undefined) { $.each(claim.references, function (i) { actions.add(function () { addReferenceToClaim(data.claim, claim.references[i], actions.step, summary); }); }); } actions.start(); }); } /** * Claim and references moving logic */ function moveClaims(from, to, actions, mergeSummary) { var claimsToBeAdd = [], claimsToBeMerged = [], claims = from.claims; if (claims !== undefined) { $.each(claims, function (name) { $.each(from.claims[name], function (i) { var claim = from.claims[name][i], available = false; if (to.claims !== undefined && to.claims[name] !== undefined) { $.each(to.claims[name], function (j) { if (areEqualsClaims(claim, to.claims[name][j])) { claimsToBeMerged.push({ to: to.claims[name][j], from: claim }); available = true; } }); } if (!available) { claimsToBeAdd.push(claim); } }); }); } log('Claims to be added: ', claimsToBeAdd); $.each(claimsToBeAdd, function (i) { actions.add(function () { displayProgress(messages.movingClaim); addClaim(to, claimsToBeAdd[i], actions.step, 'Added by [[MediaWiki:Gadget-Merge.js]], from [[' + from.id.toUpperCase() + ']]' + mergeSummary); }); }); log('Claims to be merged: ', claimsToBeMerged); $.each(claimsToBeMerged, function (i) { var mergeCase = claimsToBeMerged[i], qualifiersCount = 0, newTo = $.extend(true, {}, claimsToBeMerged[i].to); // Merge qualifiers logic if (mergeCase.from.qualifiers !== undefined) { $.each(mergeCase.from.qualifiers, function (i) { $.each(mergeCase.from.qualifiers[i], function (j) { var available = false, qualifier = mergeCase.from.qualifiers[i][j]; if (mergeCase.to.qualifiers !== undefined && mergeCase.to.qualifiers[i] !== undefined) { $.each(mergeCase.to.qualifiers[i], function (k) { if (areEqualsQualifiers(qualifier, mergeCase.to.qualifiers[i][k])) { available = true; } }); } if (!available) { qualifiersCount = qualifiersCount + 1; if (newTo.qualifiers === undefined) { newTo.qualifiers = {}; } if (newTo.qualifiers[i] === undefined) { newTo.qualifiers[i] = []; } newTo.qualifiers[i].push(qualifier); } }); }); if (qualifiersCount !== 0) { actions.add(function () { displayProgress(messages.mergingClaim); setClaim(newTo, actions.step, mergeSummary); }); } } // Merge references logic if (mergeCase.from.references !== undefined) { $.each(mergeCase.from.references, function (j) { var reference = mergeCase.from.references[j], available = false; if (claimsToBeMerged[i].to.references !== undefined) { $.each(mergeCase.to.references, function (k) { var toReference = mergeCase.to.references[k]; if (areEqualsReferences(reference, toReference)) { available = true; } }); } if (!available) { actions.add(function () { displayProgress(messages.mergingClaim); addReferenceToClaim(claimsToBeMerged[i].to, reference, actions.step, 'Added by [[MediaWiki:Gadget-Merge.js]], from [[' + from.id.toUpperCase() + ']]' + mergeSummary); }); } }); } }); } /** * Moving logic */ function moveItemContent(from, to, actions, mergeSummary) { var newFrom = cloneCleanItem(from), // clone newTo = cloneCleanItem(to); newTo.sitelinks = {}; // clean available, it could make problem if there is a invalid sitelinks available on the page $.each(newFrom.sitelinks, function (x) { newTo.sitelinks[x] = $.extend(true, {}, newFrom.sitelinks[x]); newFrom.sitelinks[x].title = ''; }); $.each(newFrom.aliases, function (x) { if (newTo.aliases[x] === undefined) { newTo.aliases[x] = []; } $.each(newFrom.aliases[x], function (y) { newTo.aliases[x].push(newFrom.aliases[x][y]); }); }); $.each(newFrom.labels, function (x) { newTo.labels[x] = $.extend(true, {}, newFrom.labels[x]); newFrom.labels[x].value = ''; }); $.each(newFrom.descriptions, function (x) { newTo.descriptions[x] = $.extend(true, {}, newFrom.descriptions[x]); newFrom.descriptions[x].value = ''; }); actions.add(function () { displayProgress(messages.movingSitelink); editItem(from.id, newFrom, 'Removed by [[MediaWiki:Gadget-Merge.js|merge.js]], moving to [[' + to.id.toUpperCase() + ']]' + mergeSummary, actions.step); }); actions.add(function () { editItem(to.id, newTo, 'Added by [[MediaWiki:Gadget-Merge.js|merge.js]], moving from [[' + from.id.toUpperCase() + ']]' + mergeSummary, actions.step); }); moveClaims(from, to, actions, mergeSummary); // Original from and to objects, not new cleaned ones } // Copy edited [[MediaWiki:Gadget-RequestDeletion.js]] function requestDeletion(entity, success, reason, triesCount) { var MAXRETRY = 10; displayProgress(messages.requestingDeletion); post({ 'format': 'json', 'action': 'edit', 'title': 'Wikidata:Requests for deletions', 'watchlist': 'nochange', 'section': 'new', 'sectiontitle': '[[' + entity + ']]', 'summary': '/* ' + entity + ' */ requested deletion ([[MediaWiki:Gadget-Merge.js|merge.js]])', 'text': '{{subst:Request for deletion|itemid=' + entity + '|reason=' + reason + '|header=no}} ~~' + '~~\n', 'token': mw.user.tokens.get('editToken') }).done(function (data) { if (data.error && data.error.info) { // may an edit conflict happened? retry ten times with 3 second interval if (triesCount === MAXRETRY) { displayError(data.error.info, true); return; } if (triesCount === undefined) { triesCount = 0; } triesCount = triesCount + 1; displayProgress(messages.requestingDeletion + ' ' + triesCount + ' / ' + MAXRETRY); setTimeout(function () { requestDeletion(entity, success, reason, triesCount); }, 3000); } else { success(); } }).fail(function (data) { displayError(data); }); } function requestStreamDeletion(entity, success, mergedTo) { post({ 'action': 'edit', 'appendtext': '\n{{/row|' + entity.replace(/^Q/i, '') + '|to=' + mergedTo.replace(/^Q/i, '') + '}}', 'title': 'User:Ricordisamoa/StreamDelete', 'watchlist': 'nochange', 'summary': '[[' + entity + ']]: requested StreamDeletion ([[MediaWiki:Gadget-Merge.js|merge.js]])', 'token': mw.user.tokens.get('editToken') }).done(function (data) { if (data.error && data.error.info) { displayError(data.error.info); } else { success(); } }).fail(function (data) { displayError(data); }); } /** * Remove a page from watchlist */ function unwatch(page, callback) { post({ action: 'watch', title: page, unwatch: '', token: mw.user.tokens.get('watchToken') }).done(callback); } /** * Move a batch of items */ function batchMover(items, mergeSummary) { displayProgress(messages.pleaseWait); var actions = new ProgressHandler(new ActionsQueue(function () { displayProgress(messages.loadingMergeDestination); window.location = mw.util.getUrl(items.to.id) + '?action=purge'; }), $('#merge-progress')); $.each(items.from, function (i) { var x = items.from[i]; moveItemContent(x, items.to, actions, mergeSummary); if ($('#merge-unwatch').is(':checked')) { actions.add(function () { displayProgress(messages.unwatching); unwatch(x.id, actions.step); }); } if (canDelete() && $('#merge-delete').is(':checked')) { actions.add(function () { displayProgress(messages.deleting); displayProgress(messages.deletingItem); // FIXME: Why? deleteItem( x.id, 'Merged with [[' + items.to.id.toUpperCase() + ']] ([[MediaWiki:Gadget-Merge.js|merge.js]])' + mergeSummary, actions.step ); }); } else if ($('#merge-send-to-rfd').is(':checked')) { actions.add(function () { displayProgress(messages.sendingToRfd); requestDeletion(x.id.toUpperCase(), actions.step, '[[MediaWiki:Gadget-Merge.js|Merged]] with [[' + items.to.id.toUpperCase() + ']]' + mergeSummary); }); } else if ($('#merge-streamdelete').is(':checked')) { actions.add(function () { displayProgress(messages.requestingStreamDeletion); requestStreamDeletion(x.id, actions.step, items.to.id); }); } }); actions.start(); } /** * Merge button action */ function merge() { var itemsNames = [$('#merge-items').val(), itemId.toUpperCase()], isValid = true, mergeSummary = $('#merge-summary').val(); if (/^\w/.test(mergeSummary)) { mergeSummary = ' ' + mergeSummary; } $.each(itemsNames, function (i) { if (!/^Q\d*$/i.test(itemsNames[i])) { isValid = false; } }); if (isValid === false) { $('#merge-input-validation-message').text(' Currently only "Qid" is a valid input'); return; } displayProgress(''); getItems(itemsNames, 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 ($.map(conflicts, function (x) { return x; }).length === 0) { if ($('#merge-always-lowest-id').is(':checked')) { items = sortItemsId(items); // sort by Qid _only_if_specified_ } batchMover({ from: items.slice(1), to: items[0] }, mergeSummary); } else { message = $.map(conflicts, function (x, i) { return '<br />' + messages.confilictMessage + i + ':' + $.map(x, function (y, j) { return ' [[' + x[j].id.toUpperCase() + ']] ' + messages.confilictWithMessage + ' [[' + i + ':' + y.sitelinks[i].title + ']]'; }).join(','); }).join('').replace(/\[\[([^\]\:]*?)\:([^\]]*?)\]\]/g, function (x, y, z) { return '<a href="' + wikibase.getSite(y).getUrlTo(z) + '">' + y + ':' + z + '</a>'; }); displayError(message, true); } }); } /** * Create checkbox html */ function createCheckbox(id, text) { return $('<label />', { 'for': id }).css('display', 'block').append($('<input />', { 'id': id, 'name': id, 'type': 'checkbox', 'checked': $.jStorage.get(id) === true ? 'checked' : undefined }), text); } /** * Save options in storage */ function saveOptions() { $('#merge-form input:checkbox').each(function (i, x) { $.jStorage.set(x.id, x.checked); }); } /** * Dialog creator and launcher */ function launchDialog(id) { if (typeof id !== 'string') { id = ''; } var dialog = { width: 500, autoOpen: false, title: messages.mergeWizard, modal: true, buttons: [{ text: messages.close, title: messages.closeDialog, specialButton: 'cancel', click: function () { saveOptions(); removePending(); $(this).dialog('close'); $(this).remove(); } }, id === '' ? { text: messages.postpone, title: messages.postponeTitle, click: function () { saveOptions(); mergePending(itemId.toUpperCase()); $(this).dialog('close'); $(this).remove(); } } : { style: 'display:none' }, { text: messages.merge, title: messages.mergeProcess, specialButton: 'proceed', click: function () { saveOptions(); removePending(); merge(); } }] }; $('<div />', { 'id': 'merge-form', 'style': 'position: relative;' }).append( $('<div />', { 'style': 'margin-top: 0.4em;', 'html': messages.mergeWithInput }), $('<input />', { 'id': 'merge-items', 'style': 'padding: 1px; vertical-align: baseline;' }).val(id), $('<label />', { 'for': id }).css('display', 'block').append('merge summary: will be prepended by an auto-generated summary', $('<input />', { 'id': 'merge-summary', 'style': 'padding: 1px; vertical-align: baseline;' })), $('<span />', { 'id': 'merge-input-validation-message' }).css('color', 'red'), createCheckbox('merge-always-lowest-id', messages.lowestQid), createCheckbox('merge-send-to-rfd', messages.requestDeletion), createCheckbox( 'merge-streamdelete', messages.streamDelete .replace(/\$1([\S\s]*)\$2/, '<u><a href="' + mw.util.getUrl('User:Ricordisamoa/StreamDelete') + '">$1</a></u>') ), canDelete() ? createCheckbox('merge-delete', messages.deleteOption) : '', createCheckbox('merge-unwatch', messages.unwatchOption) ).dialog(dialog).dialog('open').parent('.ui-dialog').attr('lang', $(document.documentElement).attr('lang')); } // Initialization if (itemId !== null && mw.config.get('wgNamespaceNumber') === 0 && mw.config.get('wgAction') === 'view') { $(window).on('focus storage', function () { $('#merge-queue-process').remove(); if ($.jStorage.get('merge-pending-id') !== null && $.jStorage.get('merge-pending-id') !== '' && $.jStorage.get('merge-pending-id').toLowerCase() !== itemId.toLowerCase()) { $('<img>') .attr({ 'src': '//upload.wikimedia.org/wikipedia/commons/thumb/1/10/Pictogram_voting_merge.svg/26px-Pictogram_voting_merge.svg.png', 'alt': 'merge icon' }) .wrap('<a>').parent() .attr({ 'href': '#', 'title': 'process the postponed merge' }) .click(function (event) { event.preventDefault(); launchDialog($.jStorage.get('merge-pending-id')); }) .wrap('<li>').parent() .attr('id', 'merge-queue-process') .prependTo('#p-views ul'); } }); $(function () { $('#merge-queue-process').remove(); $('#merge-form').remove(); $('#ca-merge').remove(); $(mw.util.addPortletLink('p-cactions', '#', messages.mergeWithProgress, 'ca-merge', messages.mergeThisItem)) .click(function (event) { event.preventDefault(); launchDialog(); }); }); } // Export section // currently just for [[MediaWiki:Gadget-EmptyDetect.js]], just launchDialog is exposed window.mergeTool = { launchDialog: launchDialog }; }(jQuery, mediaWiki));