User:Makyen/scripts/TemplateDataEditor.js

//

/**************************************************

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 /\{[0-9]+\}/ 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
  • ja: Shirayuki
  • ko: Kwj2772
  • nl: Wolf Lambert

Source

**************************************************/

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 = /]*>([\s\S]*)<\/templatedata>/,

regExpOneTag = /]*\/>/,

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": "Δεν έχουν βρεθεί δεδομένα. Παρακαλώ προσθέστε μια ετικέτα ώστε να μπορείτε να την επεξεργαστείτε.",

"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 tag to be able to edit it.",

"section-description": "Description",

"section-params": "Parameters",

"section-sets": "Sets",

"set-add": "Add a set",

"set-label": "Name",

"param-label-placeholder": "Enter name here",

"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 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»)"

},

"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": "データが見つかりませんでした。編集できるようにするには、 タグを追加してください。",

"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": "데이터가 없습니다. 편집을 가능하게 하려면 태그를 추가하십시오.",

"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 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 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",

"param-label-placeholder": "Voer hier een naam in",

"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.org/wiki/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

T.push(arguments[i]);

}

res += T.join(', ');

}

return res + ')';

} else {

if( messages[lang] && messages[lang][name] ) {

res = messages[lang][name];

} else if( messages.en[name] ) {

res = messages.en[name];

} else {

arguments[1] = 'qqx';

return messageLang.apply(null, arguments)

}

// Replace vars

for(i=arguments.length-2; i>0; i--) {

res = res.replace(new RegExp('\\$'+i, 'g'), arguments[i+1]);

}

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('wgDBname');

if( documentations.hasOwnProperty( wiki ) ) {

return mw.util.getUrl( documentations[wiki] );

} else {

return documentations['default'];

}

}

////////// 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[0].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[i] = trim(Arr[i]);

}

return Arr;

}

function strToArr(str) {

return trimArray( str.split('|') );

}

function arrToStr(arr) {

return arr.join(' | ');

}

function $clear() {

return $('

').addClass('tde-clear');

}

function selectValue(select) { // Select is a jQuery object $('')

.attr('type', 'button')

.val( message(msg) )

.click(fn)

);

},

deleteButtons: function() {

this.$buttonContainer.children().remove();

},

replaceButton: function(fn) {

this.deleteButtons();

this.$buttonContainer.append($('')

.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 = $('')

.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 = $.extend({}, UniqueElement, {

construct: function(values, labelText, placeholderMessage, $cont) {

this.defineUniq();

if( $.type(values) != 'object' ) {

this.data = {};

this.data[contentLanguage] = values;

} else {

this.data = values;

if( typeof this.data[contentLanguage] == 'undefined' ) {

this.data[contentLanguage] = '';

}

}

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') )[2]

] = domInput.value;

},

input: function($input, lang) {

var that = this;

return $input

.val( this.data[lang] )

.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[to] = this.data[from];

delete this.data[from];

} else {

throw scriptError('error-it-lang-inexistent', from);

}

},

removeElement: function(lang) {

if( this.data.hasOwnProperty(lang) ) {

delete this.data[lang];

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[lang] = '';

this.createInput(lang, false);

},

getData: function() {

noCurlyBraceKey( this.data );

if( Object.keys(this.data).length == 1 ) {

return this.data[contentLanguage] || 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 = $.extend(new InterfaceText(), {

createContent: function() {

this.$tbody = $('');

var $caption = $('')

.text(this.label)

.append(this.createToggleLinks());

this.$cont

.append($('

')

.append( $caption )

.append( this.$tbody )

)

.append( this.createAddLink() )

.append( $clear() );

},

useColon: false,

createInput: function(lang, readonly) {

this.$tbody.append($('

')

.attr('class', this.getClasses(lang))

.append($('

')

.attr('scope', 'row')

.append( new Renamer(null, lang, this, readonly).getNode() )

)

.append($('

')

.append( this.input($('