/**************************************************
== Français ==
Gadget pour éditer les balises « templatedata » de l’extension « TemplateData » de MediaWiki sans avoir à manipuler le JSON.
Un lien « TDE » est ajouté dans la boîte à outils d’édition.
Il ouvre une fenêtre de modification permettant toutes les modifications autorisées.
* Auteurs : Ltrlg (TDE) & Salix alba (TDS)
* Dernière mise à jour : 19 août 2013
== English ==
Gadget to edit “templatedata” tags for the MediaWiki extension TemplateData without having to edit JSON.
A “TDE” link is added in the edition toolbox when editing a template.
It opens a window allowing all modifications to the template data.
* Authors: Ltrlg (TDE) & Salix alba (TDS)
* Last update: 2013-08-19
== Limitation ==
MediaWiki _allows_ using parameters like '{' (yes, really!)
But here, you can’t use it:
* TDS does not see these parameters
* The default name for a parameter matches /\{+\}/ and TDE does not save if if there is any parameter containing '{'.
Of course, I don’t think anybody uses a '{' parameter. So this is not blocking in many cases.
== Translations ==
* el: Xaris333, Geraki
* en: NicoV
* it: Jacopo Werther
* gl: Elisardojm
* ja: Shirayuki
* ko: Kwj2772
* nl: Wolf Lambert
== Source ==
<syntaxhighlight lang="javascript">
**************************************************/
function TemplateDataEditor($) {
var
/* global objects */
ui, // The interface (instance of Interface)
td, // The current (or last) editor (instance of TemplateData)
/* unique identifiers (see trait UniqueElement) */
uniq = 0,
/* traits */
UniqueElement, DataForm,
/* tde regexps */
regExpTwoTags = /<templatedata*>(*)<\/templatedata>/,
regExpOneTag = /<templatedata*\/>/,
matchType = 0,
/* indntation */
defaultIndent = '\t',
indent = defaultIndent,
/* languages */
userLanguage = mw.config.get('wgUserLanguage'),
contentLanguage = mw.config.get('wgContentLanguage'),
/* translations */
messages = {
"el": {
"apply": "Εφαρμογή",
"cancel": "Ακύρωση",
"close": "Κλείσιμο",
"collapse": "Κατάρρευση",
"colon": ": ",
"description": "Περιγραφή προτύπου",
"description-placeholder": "Τοποθετείστε μια περιγραφή του προτύπου",
"error-description": "Συνέβη κάποιο σφάλμα$2:\n\n$1",
"error-it-lang-inexistent": "Αυτή η γλώσσα ($1) δεν μπορεί να μετακινηθεί επειδή ο TDE δεν μπορεί να την εντοπίσει", // $1 είναι ο κωδικός της γλώσσας
"error-name-already-used": "Δεν μπορείτε να μετονομάσετε το στοιχείο επειδή το νέο όνομα χρησιμοποιείται ήδη",
"error-name-inexistent": "Αυτό το στοιχείο ($1) δεν μπορεί να μετακινηθεί επειδή ο TDE δεν μπορεί να το εντοπίσει.", // $1 είναι η ονομασία
"error-report": " (Αναφορά σφάλματος)",
"error-set-inexistent": "Αυτό το σύνολο ($1) δεν μπορεί να μετακινηθεί επειδή ο TDE δεν μπορεί να το εντοπίσει", // $1 είναι το id του συνόλου
"error-tds-not-loaded": "Η σελίδα δεν έχει φορτώσει",
"expand": "Ανάπτυξη",
"invalid-name": "“$1” δεν είναι κατάλληλο κλειδί",
"it-add": "Προσθέστε μια γλώσσα",
"it-otherlanguages-show": "Δείξτε τις γλώσσες ($1)", // $1 είναι η ονομασία της ξένης γλώσσας
"it-otherlanguages-hide": "Αποκρύψτε τις γλώσσες", // $1 είναι ο αριθμός των ξένων γλωσσών
"it-remove": "Αφαίρεση γλώσσας",
"param-add": "Προσθήκη παραμέτρου",
"param-aliases": "Άλλες ονομασίες",
"param-default": "Προεπιλεγμένη τιμή: ",
"param-deprecated": "Καταργημένη",
"param-deprecated-tooltip": "Λεπτομέρειες",
"param-description": "Περιγραφή",
"param-inherits": "Μεταβιβάζει",
"param-label": "Εμφανιζόμενο όνομα",
"param-name": "Πραγματικό όνομα",
"param-remove": "Αφαίρεση αυτής της παραμέτρου",
"param-required": "Απαιτείται",
"param-type": "Είδος: ",
"param-type-number": "Αριθμός",
"param-type-string": "Κείμενο",
"param-type-string/line": "Κείμενο (μία γραμμή)",
"param-type-string/wiki-page-name": "Τίτλος σελίδας",
"param-type-string/wiki-user-name": "Όνομα χρήστη",
"param-type-unknown": "Άγνωστο",
"parse-error": "Το δεδομένο δεν μπορεί να αναλυθεί. Αυτό προκαλείται σε γενικές γραμμές από ένα συντακτικό σφάλμα στην JSON ή από την παρουσία των δύο συνόλων δεδομένων.",
"preload-data": "Προσυμπληρώστε τα δεδομένα",
"preload-load": "Εκτέλεση",
"preload-none": "Μην προσυμπληρώσετε",
"preload-running": "Εκτελείται…",
"preload-select": "Προσυμπληρώστε από",
"no-data": "Δεν έχουν βρεθεί δεδομένα. Παρακαλώ προσθέστε μια ετικέτα <templatedata /> ώστε να μπορείτε να την επεξεργαστείτε.",
"section-description": "Περιγραφή",
"section-params": "Παράμετροι",
"section-sets": "Σύνολα",
"set-add": "Πρόσθεση συνόλου",
"set-label": "Όνομα: ",
"set-params": "Παράμετροι",
"set-remove": "Αφαίρεση αυτού του συνόλου",
"title": "Τροποποίηση δεδομένων προτύπου",
"title-documentation": "Τεκμηρίωση",
"start-tde": "Επεξεργασία δεδομένων προτύπου",
"use-pipes": " (να διαχωρίζονται με “|”)"
},
"en": {
"apply": "Apply",
"cancel": "Cancel",
"close": "Close",
"collapse": "Collapse",
"colon": ": ",
"description": "Description of this template",
"description-placeholder": "Enter a description of this template here",
"error-description": "An error happened$2:\n\n$1", // $2 is message(error-report) or '' ; $1 is the error
"error-it-lang-inexistent": "This language ($1) can’t be removed because TDE can’t find it anymore", // $1 is the language code
"error-name-already-used": "You can’t rename this element because the new name is already used",
"error-name-inexistent": "This element ($1) can’t be removed because TDE can’t find it anymore", // $1 is the name
"error-report": " (report it)",
"error-set-inexistent": "This set ($1) can’t be removed because TDE can’t find it anymore", // $1 is the id of the set
"error-tds-not-loaded": "The page hasn’t been loaded",
"expand": "Expand",
"invalid-name": "“$1” is not a valid key",
"it-add": "Add a language",
"it-otherlanguages-show": "Show the languages ($1)", // $1 is the number of foreign languages
"it-otherlanguages-hide": "Hide the languages", // $1 is the number of foreign languages
"it-remove": "Remove this language",
"param-add": "Add a parameter",
"param-aliases": "Other names",
"param-default": "Default value",
"param-deprecated": "Deprecated",
"param-description": "Description",
"param-description-placeholder": "Insert a description of this parameter here",
"param-inherits": "Documentation inherits from",
"param-label": "Displayed name",
"param-label-placeholder": "Enter name here",
"param-name": "Real name",
"param-remove": "Remove this parameter",
"param-required": "Required",
"param-type": "Type",
"param-type-number": "Number",
"param-type-string": "Text",
"param-type-string/line": "Text (one line)",
"param-type-string/wiki-page-name": "Page title",
"param-type-string/wiki-user-name": "User name",
"param-type-unknown": "Unknown",
"parse-error": "The data can’t be parsed. This is caused in general by a syntax error in the JSON or by the presence of two datasets.",
"preload-data": "Prefill the data",
"preload-load": "Run",
"preload-none": "Do not prefill",
"preload-running": "Running…",
"preload-select": "Prefill from",
"no-data": "No data has been found. Please, add a <templatedata /> tag to be able to edit it.",
"section-description": "Description",
"section-params": "Parameters",
"section-sets": "Sets",
"set-add": "Add a set",
"set-label": "Name",
"set-params": "Parameters",
"set-remove": "Remove this set",
"start-tde": "Modify template data",
"title": "Modify template data",
"title-documentation": "documentation",
"use-pipes": " (separated by pipes “|”)"
},
"fr": {
"apply": "Appliquer",
"cancel": "Annuler",
"close": "Fermer",
"collapse": "Fermer",
"colon": "\xA0: ",
"description": "Description de ce modèle",
"description-placeholder": "Entrez une description de ce modèle",
"error-description": "Une erreur est survenue$2\xA0:\n\n$1",
"error-invalid-name": "L’identifiant «\xA0$1\xA0» n’est pas valide",
"error-it-lang-inexistent": "Cette traduction ($1) ne peut être supprimée car TDE ne la trouve plus",
"error-name-already-used": "Vous ne pouvez pas renommer cet élément car le nom donné est déjà utilisé",
"error-name-inexistent": "Cet élément ($1) ne peut être supprimé car TDE ne le trouve plus",
"error-report": " (signalez-la)",
"error-set-inexistent": "Cet ensemble ($1) ne peut être supprimé car TDE ne le trouve plus",
"error-tds-not-loaded": "La page n’a pas pu être chargée",
"expand": "Ouvrir",
"it-add": "Ajouter une langue",
"it-no-language": "Pas de code de langue ($1)",
"it-otherlanguages-show": "Afficher les traductions ($1)",
"it-otherlanguages-hide": "Cacher les traductions",
"it-remove": "Retirer cette langue",
"param-add": "Ajouter un paramètre",
"param-aliases": "Autre noms",
"param-default": "Valeur par défaut",
"param-deprecated": "Obsolète",
"param-description": "Description",
"param-description-placeholder": "Entrez une description de ce paramètre",
"param-inherits": "Documentation héritée de",
"param-label": "Nom affiché",
"param-label-placeholder": "Ajoutez un nom",
"param-name": "Nom réel",
"param-remove": "Retirer ce paramètre",
"param-required": "Obligatoire",
"param-type": "Type",
"param-type-number": "Nombre",
"param-type-string": "Texte",
"param-type-string/line": "Texte (une ligne)",
"param-type-string/wiki-page-name": "Titre de page",
"param-type-string/wiki-user-name": "Nom d’utilisateur",
"param-type-unknown": "Inconnu",
"parse-error": "Les données ne peuvent pas être interprétées. Cela arrive généralement lorsqu’il y a une erreur de syntaxe dans le JSON ou lorsqu’il y a deux ensembles de données dans la page.",
"preload-data": "Pré-remplir les données du modèle",
"preload-load": "Exécuter",
"preload-none": "Ne pas pré-remplir",
"preload-running": "Chargement en cours…",
"preload-select": "Pré-remplir depuis",
"no-data": "Aucune donnée n’a été trouvée. Veuillez ajouter une balise <templatedata /> pour pouvoir l’éditer.",
"section-description": "Description",
"section-params": "Paramètres",
"section-sets": "Ensembles",
"set-add": "Ajouter un ensemble",
"set-label": "Nom",
"set-label-placeholder": "Ajoutez un nom",
"set-params": "Paramètres",
"set-remove": "Retirer cet ensemble",
"start-tde": "Modifier les données du modèle",
"title": "Modifier les données du modèle",
"title-documentation": "documentation",
"use-pipes": " (séparés par des tubes «\xA0|\xA0»)"
},
"gl": {
"apply": "Aplicar",
"cancel": "Cancelar",
"close": "Pechar",
"collapse": "Pregar",
"colon": ": ",
"description": "Descrición deste modelo",
"description-placeholder": "Indique aquí unha descrición deste modelo",
"error-description": "Ocorreu un erro$2:\n\n$1", // $2 é a mensaxe(erro-aviso) ou '' ; $1 é o erro
"error-it-lang-inexistent": "Este idioma ($1) non pode eliminarse porque TDE non a pode atopar", // $1 é o código do idioma
"error-name-already-used": "Non pode renomear este elemento porque o novo nome xa se está usando",
"error-name-inexistent": "Este elemento ($1) non pode eliminarse porque TDE non o pode atopar", // $1 é o nome
"error-report": " (informar)",
"error-set-inexistent": "Este conxunto ($1) non pode eliminarse porque TDE non o pode atopar", // $1 é o id do conxunto
"error-tds-not-loaded": "A páxina non foi cargada",
"expand": "Expandir",
"invalid-name": "“$1” non é unha chave válida",
"it-add": "Engadir un idioma",
"it-otherlanguages-show": "Mostrar os idiomas ($1)", // $1 é o número de idiomas estranxeiros
"it-otherlanguages-hide": "Ocultar os idiomas",
"it-remove": "Eliminar este idioma",
"param-add": "Engadir un parámetro",
"param-aliases": "Outros nomes",
"param-default": "Valor por defecto",
"param-deprecated": "Desprezar",
"param-description": "Descrición",
"param-description-placeholder": "Inserir aquí a descrición para este parámetro",
"param-inherits": "Documentación herdada de",
"param-label": "Nome visualizado",
"param-label-placeholder": "Engada o nome aquí",
"param-name": "Nome real",
"param-remove": "Eliminar este parámetro",
"param-required": "Requirido",
"param-type": "Tipo",
"param-type-number": "Número",
"param-type-string": "Texto",
"param-type-string/line": "Texto (unha liña)",
"param-type-string/wiki-page-name": "Título de páxina",
"param-type-string/wiki-user-name": "Nome de usuario",
"param-type-unknown": "Descoñecido",
"parse-error": "Os datos non poden ser analizados. Normalmente isto ocorre por un erro de sintaxe no JSON ou pola presenza de dous bloques de datos.",
"preload-data": "Cubra os datos",
"preload-load": "Executar",
"preload-none": "Non cubrir",
"preload-running": "Executando…",
"preload-select": "Cubrir dende",
"no-data": "Non se atoparon datos. Por favor, engada unha marca <templatedata /> para poder editala.",
"section-description": "Descrición",
"section-params": "Parámetros",
"section-sets": "Conxuntos",
"set-add": "Engadir un conxunto",
"set-label": "Nome",
"set-params": "Parámetros",
"set-remove": "Eliminar este conxunto",
"start-tde": "Modificar datos do modelo",
"title": "Modificar datos do modelo",
"title-documentation": "documentación",
"use-pipes": " (separados por barras “|”)"
},
"ja": {
"apply": "適用",
"close": "閉じる",
"colon": ": ",
"error-description": "エラーが発生しました$2:\n\n$1",
"param-add": "引数を追加",
"param-aliases": "その他の名前",
"param-default": "既定値",
"param-deprecated": "廃止予定",
"param-deprecated-tooltip": "詳細: ",
"param-description": "説明",
"param-inherits": "継承",
"param-label": "表示名",
"param-name": "名前",
"param-remove": "この引数を除去",
"param-required": "必須",
"param-type": "型: ",
"param-type-number": "数値",
"param-type-string": "文字列",
"param-type-string/line": "文字列 (1 行)",
"param-type-string/wiki-page-name": "ページ名",
"param-type-string/wiki-user-name": "利用者名",
"param-type-unknown": "不明",
"no-data": "データが見つかりませんでした。編集できるようにするには、<templatedata /> タグを追加してください。",
"section-description": "説明",
"section-params": "引数",
"section-sets": "集合",
"set-add": "集合を追加",
"set-label": "名前: ",
"set-params": "引数",
"set-remove": "この集合を除去",
"title": "TemplateData の変更",
"title-documentation": "説明文書",
"start-tde": "TemplateData の編集",
"use-pipe": " (パイプ記号「|」で区切る)"
},
"ko": {
"apply": "적용",
"close": "닫기",
"colon": ": ",
"error-description": "오류 발생$2:\n\n$1",
"param-add": "변수 추가하기",
"param-aliases": "다른 이름",
"param-default": "기본값",
"param-deprecated": "사용 중지",
"param-deprecated-tooltip": "자세한 정보",
"param-description": "설명",
"param-inherits": "상속받을 변수",
"param-label": "표시될 이름",
"param-name": "실제 이름",
"param-remove": "이 변수 제거",
"param-required": "필수",
"param-type": "Type: ",
"param-type-number": "숫자",
"param-type-string": "문자열",
"param-type-string/wiki-page-name": "문서 이름",
"param-type-string/wiki-user-name": "사용자 이름",
"param-type-unknown": "알 수 없음",
"no-data": "데이터가 없습니다. 편집을 가능하게 하려면 <templatedata /> 태그를 추가하십시오.",
"section-description": "설명",
"section-params": "변수",
"section-sets": "집합",
"set-add": "집합 추가하기",
"set-label": "이름: ",
"set-params": "변수",
"set-remove": "이 집합 제거하기",
"title": "틀 데이터 수정하기",
"title-documentation": "설명 문서",
"start-tde": "틀 데이터 편집하기",
"use-pipes": " (파이프 “|”로 구분)"
},
"it": {
"apply": "Applica (a tuo rischio e pericolo, ogni abuso sarà segnalato)",
"colon": "\xA0: ",
"param-add": "Aggiungi un parametro",
"param-aliases": "Altri nomi",
"param-default": "Valore di default",
"param-deprecated": "Deprecato",
"param-deprecated-tooltip": "Dettagli",
"param-description": "Descrizione",
"param-inherits": "Eredità",
"param-label": "Nome visualizzato",
"param-name": "Nome effettivo",
"param-remove": "Rimuovi questo parametro",
"param-required": "Richiesto",
"no-data": "Spiacente. Nessun dato è stato trovato. Aggiungere un tag <templatedata /> per poter modificare il template data.",
"section-description": "Descrizione",
"section-params": "Parametri",
"set-add": "Aggiungi un set",
"title": "Benvenuto in Modifica TemplateData",
"title-documentation": "tutorial per negati",
"use-pipes": " (separati da pipes « | »)"
},
"nl": {
"apply": "Oké",
"cancel": "Annuleren",
"close": "Sluiten",
"collapse": "Inklappen",
"colon": ": ",
"description": "Beschrijving van dit sjabloon",
"description-placeholder": "Voer hier een beschrijving van dit sjabloon in",
"error-description": "Er deed zich een fout voor$2:\n\n$1", // $2 is message(error-report) or '' ; $1 is the error
"error-it-lang-inexistent": "De taal $1 kan niet worden verwijderd, omdat TDE hem niet meer kan vinden.", // $1 is the language code
"error-name-already-used": "Dit element kan niet van naam veranderd worden omdat de naam al in gebruik is.",
"error-name-inexistent": "Het element \"$1\" kan niet worden verwijderd, omdat TDE het niet meer kan vinden.", // $1 is the name
"error-report": " (rapporteer het)",
"error-set-inexistent": "De set \"$1\" kan niet worden verwijderd, omdat TDE hem niet meer kan vinden.", // $1 is the id of the set
"error-tds-not-loaded": "Deze pagina is niet geladen.",
"expand": "Uitklappen",
"invalid-name": "\"$1\" is geen valide sleutel",
"it-add": "Taal toevoegen",
"it-otherlanguages-show": "Toon de talen ($1)", // $1 is the number of foreign languages
"it-otherlanguages-hide": "Verberg de talen", // $1 is the number of foreign languages
"it-remove": "Verwijder deze taal",
"param-add": "Parameter toevoegen",
"param-aliases": "Andere namen",
"param-default": "Standaardwaarde",
"param-deprecated": "Verouderd",
"param-description": "Beschrijving",
"param-description-placeholder": "Voer hier een beschrijving van deze parameter in",
"param-inherits": "Documentatie wordt overgenomen van",
"param-label": "Getoonde naam",
"param-label-placeholder": "Voer hier een naam in",
"param-name": "Echte naam",
"param-remove": "Verwijder deze parameter",
"param-required": "Verplicht",
"param-type": "Type",
"param-type-number": "Nummer",
"param-type-string": "Tekst",
"param-type-string/line": "Tekst (één lijn)",
"param-type-string/wiki-page-name": "Paginatitel",
"param-type-string/wiki-user-name": "Gebruikersnaam",
"param-type-unknown": "Onbekend",
"parse-error": "De data kan niet geparsed worden. Dit is meestal de oorzaak van een fout in de JSON-syntax, of wanneer er twee datasets aanwezig zijn.",
"preload-data": "Vul de data vooraf in",
"preload-load": "Start",
"preload-none": "Vul de data niet vooraf in",
"preload-running": "Bezig…",
"preload-select": "Vul vooraf in van",
"no-data": "Er staat nog geen templatedata op dit sjabloon; plaats <templatedata /> onderaan het sjabloon om dit sjabloon te bewerken.",
"section-description": "Beschrijving",
"section-params": "Parameters",
"section-sets": "Sets",
"set-add": "Voeg een set toe",
"set-label": "Naam",
"set-params": "Parameters",
"set-remove": "Verwijder deze set",
"start-tde": "Pas de templatedata aan",
"title": "Templatedata aanpassen",
"title-documentation": "documentatie",
"use-pipes": " (gescheiden door pipes \"|\")"
}
},
documentations = { // Local pages (but full link for default)
"default": '//en.wikipedia.orghttps://wikines.com/fr/User:NicoV/TemplateDataEditor',
"enwiki": 'User:NicoV/TemplateDataEditor',
"frwiki": 'Utilisateur:Ltrlg/TemplateDataEditor',
"itwiki": 'Wikipedia:VisualEditor/TemplateData'
};
////////// Translation //////////
function messageLang(name, lang) {
var
res,
i,
T = ;
if( name == '' ) {
return '';
}
if( lang == 'qqx' ) {
res = '(-tde-' + name;
if( arguments.length > 2 ) {
res += ': ';
for(i=2; i<arguments.length; i++) {
T.push(arguments);
}
res += T.join(', ');
}
return res + ')';
} else {
if( messages && messages ) {
res = messages;
} else if( messages.en ) {
res = messages.en;
} else {
arguments = 'qqx';
return messageLang.apply(null, arguments);
}
// Replace vars
for(i=arguments.length-2; i>0; i--) {
res = res.replace(new RegExp('\\$'+i, 'g'), arguments);
}
return res;
}
}
function message(name) {
var args = Array.prototype.slice.call(arguments);
args.shift();
args.unshift(name, userLanguage);
return messageLang.apply(null, args);
}
function documentationLink() {
var wiki = mw.config.get('wgWikiID');
if( documentations.hasOwnProperty( wiki ) ) {
return mw.util.getUrl( documentations );
} else {
return documentations;
}
}
////////// Getting & setting text (compatibility with WikEd) //////////
function getText() {
if( window.wikEd && window.wikEd.useWikEd ) {
WikEdUpdateTextarea();
}
return $('#wpTextbox1').val();
}
function setText(value) {
$('#wpTextbox1').val(value);
if( window.wikEd && window.wikEd.useWikEd ) {
WikEdUpdateFrame();
}
}
////////// Usefull functions //////////
function userError() {
var e = new Error( message.apply(null, arguments) );
e.userError = true;
return e;
}
function scriptError() {
var e = new Error( message.apply(null, arguments) );
e.userError = false;
return e;
}
function alertError(e) {
alert(message(
'error-description',
e.message,
e.userError ? '' : message('error-report')
));
console.error('“' + e.message + '”\nError thrown by ' + e.fileName + ' on line ' + e.lineNumber);
}
function ucfirst(str) {
return str.toUpperCase() + str.substring(1, str.length);
}
function norm(str) {
return ucfirst( str.replace('_', ' ') );
}
function trim(str) {
return str.replace(/^\s*(\S.*\S|\S)\s*$/, '$1');
}
function trimArray(Arr) {
var i = 0;
for(; i<Arr.length; i++) {
Arr = trim(Arr);
}
return Arr;
}
function strToArr(str) {
return trimArray( str.split('|') );
}
function arrToStr(arr) {
return arr.join(' | ');
}
function $clear() {
return $('<div>').addClass('tde-clear');
}
function selectValue(select) { // Select is a jQuery object $('<select>') or a DOM select node
var res;
$(select).children('option').each(function(){
if( $(this).prop('selected') ) {
res = $(this).val();
return false;
}
});
return res;
}
function getIndent(text) { // Should work fine with any well-indented JSON
var
lines = text.split('\n'),
i,
maxLength = Infinity,
indent = defaultIndent,
localIndent;
for(i=0; i<lines.length; i++) {
try {
localIndent = /^(\s*)\S/.exec(lines);
if( localIndent.length < maxLength && localIndent.length != 0 ) {
indent = localIndent;
maxLength = localIndent.length;
}
} catch(e) {
// Nothing to do, just a line without \S
}
}
return indent;
}
function noCurlyBraceKey(object) {
for(var i in object) {
if( //.test(i) ) {
throw userError('error-invalid-name', i);
}
}
}
function arrayRemoveElement(array, i) {
var
newLength = array.length-1,
j;
for(j=i; j<array.length-1; j++) {
array = array;
}
array.length = newLength;
}
////////// TemplateDataSkeleton (partial, adapted) //////////
function TemplateDataSkeletonFromText(text) {
var
pat = /\{\{\{(+)(.)/g, // '{{{' then any char other than {|}\n<
matches, name, newReq, oldReq,
params = {};
while( (matches=pat.exec(text)) != null ) {
name = trim(matches);
newReq = ( matches== '}' );
oldReq = ( params == null || params.required );
params = {
required: newReq && oldReq,
label: norm(name)
};
pat.lastIndex--; // need to backtrack one character
}
return { params: params };
}
function TemplateDataSkeleton(page, cb) {
function error() {
alertError( scriptError('tds-not-loaded') );
cb({});
}
$.ajax({
url: mw.util.wikiScript('api'),
data: {
action: 'query',
prop: 'revisions',
titles: page,
rvprop: 'content',
format: 'json'
},
dataType: 'json',
error: error,
success: function( data ) {
try {
var pageId = Object.keys(data.query.pages);
cb( TemplateDataSkeletonFromText(data.query.pages.revisions || '') ); // '' if missing page
} catch(e) {
error();
}
}
});
}
////////// Actions //////////
function action(_options) {
var
options = Object.assign({
type: null,
desc: '',
fn: function(){},
aClass: '',
aId: ''
}, _options),
img = action.images;
return $('<a>')
.attr({
title: options.desc,
href: '#',
'class': options.aClass,
id: options.aId
})
.click(function(){
options.fn.call(this);
return false;
})
.append($('<img>')
.attr({
alt: options.desc,
src: '//upload.wikimedia.org/wikipedia/commons/thumb/'
+ img.hashStart + '/'
+ img.hashStart + '/'
+ img.name + '/'
+ '24px-' + img.name + '.png'
})
);
}
action.images = {
add: {
hashStart: '8b',
name: 'VisualEditor_-_Icon_-_Add-item.svg'
},
remove: {
hashStart: '0e',
name: 'VisualEditor_-_Icon_-_Remove-item.svg'
},
close: {
hashStart: '8d',
name: 'VisualEditor_-_Icon_-_Close.svg'
},
expand: {
hashStart: '2f',
name: 'VisualEditor_-_Icon_-_Expand.svg'
},
collapse: {
hashStart: '32',
name: 'VisualEditor_-_Icon_-_Collapse.svg'
},
expand_inline: {
hashStart: 'd3',
name: 'VisualEditor_-_Icon_-_Move-ltr.svg'
},
collapse_inline: {
hashStart: '4e',
name: 'VisualEditor_-_Icon_-_Move-rtl.svg'
}
};
////////// class Interface //////////
function Interface() {
var that = this;
this.$title = $('<h2>')
.text( message('title') )
.append(document.createTextNode(' ('))
.append($('<a>')
.attr('href', documentationLink() )
.text( message('title-documentation') )
)
.append(document.createTextNode(')'));
this.$body = $('<div>').attr('id', 'tde-body');
this.$buttonContainer = $('<div>').addClass('tde-buttons');
this.$cont = $('<div>')
.attr('id', 'tde')
.append($('<div>').attr('id', 'tde-mask'))
.append($('<div>')
.attr('id', 'tde-dialog')
.append( this.$title )
.append( action({type: 'close', desc: message('close'), fn: function() { that.close(); }, aId: 'tde-close'}) )
.append( this.$body )
.append( this.$buttonContainer )
)
.hide();
$(document.body).append(this.$cont);
}
Interface.prototype = {
clear: function() {
this.$body.children().remove();
this.deleteButtons();
},
close: function() {
this.$cont.fadeOut();
},
open: function() {
this.$cont.fadeIn();
},
addCancelButton: function() {
var that = this;
this.addButton('cancel', function(){
that.close();
});
},
addButton: function(msg, fn) {
this.$buttonContainer.append($('<input>')
.attr('type', 'button')
.val( message(msg) )
.click(fn)
);
},
deleteButtons: function() {
this.$buttonContainer.children().remove();
},
replaceButton: function(fn) {
this.deleteButtons();
this.$buttonContainer.append($('<input>')
.attr({
id: 'tde-apply',
type: 'button'
})
.val( message('apply') )
.click(fn)
);
}
};
ui = new Interface;
////////// class Renamer //////////
function Renamer(id, name, parent, readonly) {
this.name = name;
this.parent = parent;
this.readonly = !! readonly;
var that = this;
this.$input = $('<input>')
.addClass('tde-renamer-name-input')
.attr({
type: 'text',
id: id
})
.prop('readonly', this.readonly)
.blur(function(){
that.exec();
})
.val(name);
}
Renamer.prototype = {
getNode: function() {
return this.$input;
},
exec: function() {
var newName = this.$input.val();
try {
this.parent.renameElement(this.name, newName);
this.name = newName;
} catch(e) {
alertError( e );
}
this.$input.val(this.name);
}
};
////////// trait UniqueElement //////////
UniqueElement = {
defineUniq: function() {
this.uniq = uniq;
uniq++;
}
};
////////// abstract class InterfaceText use UniqueElement //////////
function InterfaceText() { /* Call to this.construct from subclasses */ }
InterfaceText.prototype = Object.assign({}, UniqueElement, {
construct: function(values, labelText, placeholderMessage, $cont) {
this.defineUniq();
if( $.type(values) != 'object' ) {
this.data = {};
this.data = values;
} else {
this.data = values;
if( typeof this.data == 'undefined' ) {
this.data = '';
}
}
this.numberOtherLanguages = Object.keys( this.data ).length - 1;
this.label = labelText + (this.useColon ? message('colon') : '');
this.placeholder = placeholderMessage;
this.$cont = $cont.addClass('tde-it');;
this.createContent();
this.createInputs();
this.hideOther();
},
getClasses: function(lang) {
return 'tde-it-lang tde-it-lang-' + (lang || contentLanguage);
},
createInputs: function() {
var i;
for( i in this.data ) {
this.createInput(i, i == contentLanguage);
}
},
onChange: function(domInput) {
this.data[
/(^|\s)tde-it-lang-(\S+)(\s|$)/.exec( $(domInput).closest('.tde-it-lang').attr('class') )
] = domInput.value;
},
input: function($input, lang) {
var that = this;
return $input
.val( this.data )
.addClass('tde-it-input')
.attr('placeholder', messageLang(this.placeholder, lang))
.change(function(){
that.onChange(this);
});
},
getPlaceholder: function(lang) {
return messageLang(this.placeholder, lang);
},
hideOther: function() {
this.$expand.show();
this.$collapse.hide();
this.$cont.find('.tde-it-lang').each(function(){
if(
! $(this).hasClass('tde-it-lang-'+contentLanguage)
&& ! $(this).hasClass('tde-it-lang-'+userLanguage)
) {
$(this).hide();
}
});
this.$add.hide();
},
showOther: function() {
this.$expand.hide();
this.$collapse.show();
this.$cont.find('.tde-it-lang').css('display', ''); // .show() does .css('display', 'inline'), but here we need inline-block, as declared in the stylesheet
this.$add.show();
},
updateNumber: function() {
this.$expand.attr('title', message('it-otherlanguages-show', this.numberOtherLanguages));
this.$expand.find('img').attr('alt', message('it-otherlanguages-show', this.numberOtherLanguages));
this.$collapse.attr('title', message('it-otherlanguages-hide', this.numberOtherLanguages));
this.$collapse.find('img').attr('alt', message('it-otherlanguages-hide', this.numberOtherLanguages));
},
actionSuffix: '',
useColon: true,
createToggleLinks: function(){
var that = this;
this.$expand = action({
type: 'expand' + this.actionSuffix,
aClass: 'tde-it-expand',
fn: function(){
that.showOther();
return false;
}
});
this.$collapse = action({
type: 'collapse' + this.actionSuffix,
aClass: 'tde-it-collapse',
fn: function(){
that.hideOther();
return false;
}
});
this.updateNumber();
return $().add(this.$collapse).add(this.$expand);
},
createAddLink: function() {
var that = this;
this.$add = action({
type: 'add',
desc: message('it-add'),
fn: function(){
that.addInput();
},
aClass: 'tde-add-language'
});
return this.$add;
},
getLangDiv: function(lang) {
var res;
this.$cont.find('.tde-it-lang').each(function(){
if( $(this).hasClass('tde-it-lang-'+lang) ) {
res = $(this);
return false;
}
});
return res;
},
getValueInput: function(lang) {
return this.getLangDiv(lang).find('.tde-it-input');
},
renameElement: function(from, to) {
if( this.data.hasOwnProperty(to) ) {
if( to != from ) {
throw userError('error-name-already-used');
}
} else if( this.data.hasOwnProperty(from) ) {
this.getLangDiv(from).attr('class', this.getClasses(to));
this.getValueInput(to).attr('placeholder', this.getPlaceholder(to)); // "this.getValueInput(to)": "to" because the class have been modified by the line before
this.data = this.data;
delete this.data;
} else {
throw scriptError('error-it-lang-inexistent', from);
}
},
removeElement: function(lang) {
if( this.data.hasOwnProperty(lang) ) {
delete this.data;
this.getLangDiv(lang).remove();
} else {
throw scriptError('error-it-lang-inexistent', lang);
}
},
$removeLang: function(readonly) {
var that = this;
if( readonly ) {
return null;
} else {
return action({
type: 'remove',
desc: message('it-remove'),
fn: function(){
var $lang = $(this).closest('.tde-it-lang');
try {
that.removeElement( $lang.find('.tde-renamer-name-input').val() );
$lang.remove();
} catch(e) {
alertError(e);
}
}
});
}
},
untitledId: 0,
addInput: function() {
this.untitledId++;
var lang = '{' + this.untitledId + '}';
this.data = '';
this.createInput(lang, false);
},
getData: function() {
noCurlyBraceKey( this.data );
if( Object.keys(this.data).length == 1 ) {
return this.data || undefined;
} else {
// TODO delete empty strings
return this.data;
}
},
/* abstract */ createContent: function() { },
/* abstract */ createInput: function(lang, readonly) { }
});
////////// class InterfaceTextBlock extends InterfaceText //////////
function InterfaceTextBlock() {
this.construct.apply(this, arguments);
this.$cont.addClass('tde-it-block');
}
InterfaceTextBlock.prototype = Object.assign(new InterfaceText(), {
createContent: function() {
this.$tbody = $('<tbody>');
var $caption = $('<caption>')
.text(this.label)
.append(this.createToggleLinks());
this.$cont
.append($('<table>')
.append( $caption )
.append( this.$tbody )
)
.append( this.createAddLink() )
.append( $clear() );
},
useColon: false,
createInput: function(lang, readonly) {
this.$tbody.append($('<tr>')
.attr('class', this.getClasses(lang))
.append($('<th>')
.attr('scope', 'row')
.append( new Renamer(null, lang, this, readonly).getNode() )
)
.append($('<td>')
.append( this.input($('<textarea>'), lang) )
)
.append($('<td>')
.append( this.$removeLang(readonly) )
)
);
}
});
////////// class InterfaceTextInline extends InterfaceText //////////
function InterfaceTextInline() {
this.construct.apply(this, arguments);
this.$cont.addClass('tde-it-inline');
}
InterfaceTextInline.prototype = Object.assign(new InterfaceText(), {
createContent: function() {
this.$span = $('<span>');
this.$cont
.text( this.label )
.append( this.$span )
.append( this.createAddLink() )
.append( this.createToggleLinks() );
},
actionSuffix: '_inline',
createInput: function(lang, readonly) {
this.$span.append($('<span>')
.attr('class', this.getClasses(lang))
.append( new Renamer(null, lang, this, readonly).getNode() )
.append( document.createTextNode( message('colon') ) )
.append( this.input($('<input>').attr('type', 'text'), lang) )
.append( this.$removeLang(readonly) )
);
}
});
////////// trait DataForm //////////
DataForm = {
getCont: function( name ) {
return this;
},
newline: function(cont) {
this.getCont(cont).append('<br>');
return this;
},
addInput: function(cont, type, key, label) {
var
$cont = this.getCont(cont),
that = this,
inputClass = 'tde-' + this.type + '-' + key,
labelClass = inputClass + '-label',
id = inputClass + '-' + this.uniq,
$input;
function addLabel(colon) {
$cont
.append($('<label>')
.addClass(labelClass)
.attr('for', id)
.text(
label
+ ( type == 'array' ? message('use-pipes') : '' )
+ ( colon ? message('colon') : '' ) )
);
}
function addInput() {
$cont
.append( $input );
}
switch(type) {
case 'text':
$input = $('<input>')
.addClass(inputClass)
.attr({
type: 'text',
id: id
})
.val( this.data || '' )
.change(function(){ that.change(key, this.value); });
addLabel(true);
addInput();
break;
case 'array':
$input = $('<input>')
.addClass(inputClass)
.attr({
type: 'text',
id: id
})
.val( arrToStr( this.data || ) )
.change(function(){ that.changeArray(key, this.value); });
addLabel(true);
addInput();
break;
case 'checkbox':
$input = $('<input>')
.addClass(inputClass)
.attr({
type: 'checkbox',
id: id
})
.prop('checked', this.data)
.change(function(){ that.change(key, this.checked); });
addInput();
addLabel(false);
break;
case 'typeSelect':
$input = $('<select>')
.addClass(inputClass)
.attr('type', 'text')
.attr('id', id)
.append( Param.type('unknown', this.data.type) )
.append( Param.type('number', this.data.type) )
.append( Param.type('string', this.data.type) )
.append( Param.type('string/line', this.data.type) )
.append( Param.type('string/wiki-user-name', this.data.type) )
.append( Param.type('string/wiki-page-name', this.data.type) )
.change(function(){ that.changeType(this); });
addLabel(true);
addInput();
break;
}
this = $input;
return this;
},
addDescription: function(cont) {
var $div = $('<div>');
this.getCont(cont).append($div);
this.description = new InterfaceTextBlock(
this.data.description || '',
message(this.type + '-description'),
this.type + '-description-placeholder',
$div
);
return this;
},
addLabel: function(cont) {
var $span = $('<span>');
this.getCont(cont).append($span);
this.label = new InterfaceTextInline(
this.data.label || '',
message(this.type + '-label'),
this.type + '-label-placeholder',
$span
);
return this;
},
change: function(key, newValue) {
if( key == 'deprecated' ) {
this.data = newValue || false;
} else {
this.data = newValue;
}
},
changeArray: function(key, str) {
this.change(key, strToArr(str));
},
changeType: function(domSelect) {
this.change('type', selectValue(domSelect));
}
};
////////// class Param uses UniqueElement, DataForm //////////
function Param(params, name, $list, data) {
this.defineUniq();
var
that = this;
this.params = params;
this.name = name;
this.$cont = $('<li>');
this.data = data;
this.$head = $('<div>');
this.$body = $('<div>');
this.$expand = action({type: 'expand', desc: message('expand'), fn: function() { that.expand(); }, aClass: 'tde-param-expand'});
this.$collapse = action({type: 'collapse', desc: message('collapse'), fn: function() { that.collapse(); }, aClass: 'tde-param-collapse'});
if(
( data.required || data.description == '' )
&& ! data.inherits
) {
this.expand();
} else {
this.collapse();
}
this.$cont
.append( action({type: 'remove', desc: message('param-remove'), fn: function() { that.remove(); }, aClass: 'tde-remove-line'}) )
.append( this.$expand )
.append( this.$collapse )
.append( this.$head )
.append( this.$body )
.append( $clear() );
this.$head
.append($('<label>')
.attr('for', 'tde-paramName-'+this.uniq)
.text( message('param-name') + message('colon') )
)
.append( (new Renamer('tde-paramName-'+this.uniq, name, params)).getNode() );
this
.addInput('head', 'checkbox', 'required', message('param-required'))
.addInput('head', 'text', 'inherits', message('param-inherits'))
.addLabel('body')
.newline('body')
.addInput('body', 'typeSelect', 'type', message('param-type'))
.addInput('body', 'text', 'default', message('param-default'))
.newline('body')
.addInput('body', 'text', 'deprecated', message('param-deprecated'))
.newline('body')
.addInput('body', 'array', 'aliases', message('param-aliases'))
.addDescription('body');
$list.append( this.$cont );
}
Param.prototype = Object.assign({}, UniqueElement, DataForm, {
type: 'param',
expand: function() {
this.$collapse.show();
this.$expand.hide();
this.$body.show();
},
collapse: function() {
this.$collapse.hide();
this.$expand.show();
this.$body.hide();
},
remove: function() {
try {
this.params.removeElement(this.name);
this.$cont.remove();
} catch(e) {
alertError( e );
}
},
getCont: function( name ) {
return this;
},
getData: function() {
this.data.label = this.label.getData();
this.data.description = this.description.getData();
return this.data;
}
});
Param.type = function(type, currentType) {
return $('<option>')
.val(type)
.text( message('param-type-' + type) )
.prop('selected', currentType == type);
};
////////// class Params //////////
function Params($list, data) {
this.$list = $list;
this.data = data;
this.params = {};
var i, that = this;
for( i in data ) {
this.createLi(i);
}
this.$list.first().after(
action({type: 'add', fn: function(){that.addItem();return false;}, desc: message('param-add'), aClass: 'tde-add-line'})
);
}
Params.prototype = {
untitledId: 0,
addItem: function() {
this.untitledId++;
var name = '{' + this.untitledId + '}';
this.data = {};
this.createLi(name);
},
createLi: function(name) {
this.params = new Param(this, name, this.$list, this.data);
},
renameElement: function(from, to) {
if( this.data.hasOwnProperty(to) ) {
if( to != from ) {
throw userError('error-name-already-used');
}
} else if( this.data.hasOwnProperty(from) ) {
this.data = this.data;
this.params = this.params;
delete this.data;
delete this.params;
} else {
throw scriptError('error-name-inexistent', from);
}
},
removeElement: function(name) {
if( this.data.hasOwnProperty(name) ) {
delete this.data;
delete this.params;
} else {
throw scriptError('error-name-inexistent', name);
}
},
getData: function() {
for( var i in this.data ) {
this.data = this.params.getData();
}
noCurlyBraceKey( this.data );
return this.data;
}
};
////////// class Set uses UniqueElement, DataForm //////////
function Set(sets, $list, data) {
this.defineUniq();
var
that = this;
this.sets = sets;
this.$cont = $('<li>');
this.data = data;
this.$body = $('<div>');
this.$cont
.append( action({type: 'remove', desc: message('set-remove'), fn: function() { that.remove(); }, aClass: 'tde-remove-line'}) )
.append( this.$body )
.append( $clear() );
this
.addLabel('body')
.newline('body')
.addInput('body', 'array', 'params', message('set-params'));
$list.append( this.$cont );
}
Set.prototype = Object.assign({}, UniqueElement, DataForm, {
type: 'set',
remove: function() {
try {
this.sets.removeElement(this);
this.$cont.remove();
} catch(e) {
alertError( e );
}
},
getData: function() {
this.data.label = this.label.getData();
return this.data;
}
});
Param.type = function(type, currentType) {
return $('<option>')
.val(type)
.text( message('param-type-' + type) )
.prop('selected', currentType == type);
};
////////// class Sets //////////
function Sets($list, data) {
this.$list = $list;
this.data = data;
this.sets = ;
var i, that = this;
for(i = 0; i<data.length; i++ ) {
this.createLi(i);
}
this.$list.first().after(
action({type: 'add', fn: function(){that.addItem();return false;}, desc: message('set-add'), aClass: 'tde-add-line'})
);
}
Sets.prototype = {
addItem: function() {
this.data.push({});
this.createLi(this.data.length-1);
},
createLi: function(i) {
this.sets = new Set(this, this.$list, this.data);
},
removeElement: function(set) {
var i = this.sets.indexOf(set);
if( i >= 0 ) {
arrayRemoveElement(this.data, i);
arrayRemoveElement(this.sets, i);
} else {
throw scriptError('error-set-inexistent', name);
}
},
getData: function() {
for(var i=0; i<this.data.length; i++) {
this.data = this.sets.getData();
}
return this.data;
}
};
////////// class TemplateData //////////
function TemplateData(data) {
this.data = data;
this.cleanData();
ui.clear();
ui.$title
.text( message('title') )
.append(document.createTextNode(' ('))
.append($('<a>')
.attr('href', documentationLink() )
.text( message('title-documentation') )
)
.append(document.createTextNode(')'));
this.dataToUi();
ui.open();
}
TemplateData.regexpDouble = /<templatedata*>(*)<\/templatedata>/;
TemplateData.regexpSimple = /<templatedata*\/>/;
TemplateData.prototype = {
cleanData: function() {
if( typeof this.data.description == 'undefined' ) this.data.description = '';
if( $.type(this.data.params) != 'object' ) this.data.params = {};
if( $.type(this.data.sets) != 'array' ) this.data.sets = ;
},
dataToUi: function() {
this.descriptionToUi();
this.paramsToUi();
this.setsToUi();
},
descriptionToUi: function() {
var $div = $('<div>').attr('id', 'tde-desc-cont');
ui.$body
.append($('<h3>')
.text( message('section-description') )
)
.append($div);
this.description = new InterfaceTextBlock(this.data.description, message('description'), 'description-placeholder', $div);
},
paramsToUi: function() {
var $list = $('<ul>');
ui.$body.append($('<h3>')
.text( message('section-params') )
)
.append($list);
this.params = new Params($list, this.data.params);
},
setsToUi: function() {
var $list = $('<ul>');
ui.$body.append($('<h3>')
.text( message('section-sets') )
)
.append($list);
this.sets = new Sets($list, this.data.sets);
},
getData: function() {
this.data.description = this.description.getData();
this.data.params = this.params.getData();
this.data.sets = this.sets.getData();
if( this.data.sets.length == 0 ) {
delete this.data.sets;
}
return this.data;
}
};
///////// Starting /////////
function write() {
try {
var
newContent = '<templatedata>\n' + JSON.stringify(td.getData(), null, indent) + '\n</templatedata>',
text = getText();
switch(matchType) {
case 1:
text = text.replace(regExpOneTag, newContent);
break;
case 2:
text = text.replace(regExpTwoTags, newContent);
break;
}
setText(text);
ui.close();
} catch(e) {
alertError(e);
}
}
function startWithData(data) {
td = new TemplateData(data);
ui.addCancelButton();
ui.addButton('apply', write);
}
function startWithTds(text) {
var
T = mw.config.get('wgPageName').replace('_', ' ').split('/'),
i,
page = '',
$preload = $('<div>').attr('id', 'tde-preload'),
$select = $('<select>').attr('id', 'tde-preload-select');
function $option(val, _label) {
var label = _label || val;
return $('<option>')
.val( val )
.text( label );
}
for(i=0; i<T.length; i++) {
page += (page ? '/' : '') + T;
T = page;
}
$select.append( $option('', message('preload-none')) );
for(i=T.length-1; i>-1; i-- ) {
$select.append( $option( T ) );
}
ui.clear();
ui.$title.text( message('preload-data') );
$preload
.append( $('<label>')
.attr('for', 'tde-preload-select')
.text( message('preload-select') + message('colon') )
)
.append($select);
ui.$body.html( $preload );
ui.addCancelButton();
ui.addButton('preload-load', function(){
var template = selectValue($select);
if( ! template ) {
startWithData({});
} else if( template == T ) { // The current template
startWithData(
TemplateDataSkeletonFromText(text)
);
} else {
$preload
.text( message('preload-running') )
.addClass('tde-preload-loading');
ui.deleteButtons();
TemplateDataSkeleton(template, startWithData);
}
});
ui.open();
}
function startTDE() {
var
text = getText(),
content,
data = null;
if( regExpTwoTags.test(text) ) {
matchType = 2;
content = regExpTwoTags.exec( text );
indent = getIndent(content);
if( /^\s*(\{\s*\})?\s*$/.test(content) ) {
startWithTds(text);
} else {
try {
data = JSON.parse( content );
} catch(e) {
data = null;
}
if( data != null ) {
startWithData(data);
} else {
alertError(userError('parse-error'));
}
}
} else if( regExpOneTag.test(text) ) {
matchType = 1;
indent = defaultIndent;
startWithTds(text);
} else {
matchType = 0;
alertError(userError('no-data'));
}
}
////////// Add a link to start TDE //////////
function addTdeLink() {
var
$img = $('<img>').attr('alt', message('start-tde')),
$link = $('<a>')
.attr({
href: '#',
title: message('start-tde')
})
.append($img)
.click(function(){
startTDE();
return false;
});
if( mw.user.options.get('usebetatoolbar') ) {
$img.attr('src', '//upload.wikimedia.org/wikipedia/commons/d/d8/TemplateData_-_Icon_-_Beta_toolbar.png');
mw.loader.using('ext.wikiEditor', function(){
$('#wikiEditor-ui-toolbar .section-main .group-insert').before($('<div>')
.addClass('group group-tde')
.append($link)
);
});
} else {
$img.attr('src', '//upload.wikimedia.org/wikipedia/commons/6/63/TemplateData_-_Icon_-_Old_toolbar.png');
$('#toolbar').append($link);
}
}
addTdeLink();
/*
$(
mw.util.addPortletLink('p-tb', '#', 'TemplateData', 'tde-toolbox', message('toolbox-label'))
).click(function(){
startTDE();
return false;
});
*/
}
if( .indexOf( mw.config.get('wgNamespaceNumber') ) !== -1 && .indexOf( mw.config.get('wgAction') ) !== -1 ) {
mw.loader.load(
'//fr.wikipedia.org/w/index.php?title=Utilisateur:Ltrlg/styles/TemplateDataEditor.css&action=raw&ctype=text/css',
'text/css'
);
mw.loader.using('mediawiki.util', function () {
$(document).ready(TemplateDataEditor);
});
}
// </syntaxhighlight> {{catégorisation JS|TemplateDataEditor}}