User:Hippietrail/editor.js

/** See talk page for details **/

/* DOM abbreviation function */ function newNode(tagname){

var node = document.createElement(tagname); for( var i=1;i<arguments.length;i++ ){ if(typeof arguments[i] == 'string'){ //Text node.appendChild( document.createTextNode(arguments[i]) ); }else if(typeof arguments[i] == 'object'){ if(arguments[i].nodeName){ //If it is a DOM Node node.appendChild(arguments[i]); }else{ //Attributes (hopefully) for(var j in arguments[i]){ if(j == 'class'){ //Classname different because... node.className = arguments[i][j]; }else if(j == 'style'){ //Style is special node.style.cssText = arguments[i][j]; }else if(typeof arguments[i][j] == 'function'){ //Basic event handlers try{ node.addEventListener(j,arguments[i][j],false); //W3C }catch(e){try{ node.attachEvent('on'+j,arguments[i][j],"Language"); //MSIE }catch(e){ node['on'+j]=arguments[i][j]; }}; //Legacy }else{ node.setAttribute(j,arguments[i][j]); //Normal attributes

}       }      }    }  }  return node; }

/* Wrapper around API */ function API {

function request (query, callback) {       var xhr = sajax_init_object;

xhr.open('POST', '/w/api.php?format=json', true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(query); xhr.onreadystatechange = function {           if (xhr.readyState == 4) {               callback(eval("("+xhr.responseText+")")); }       }    }

function encode_array (arg, args) {       if (arg instanceof Array) args = arg;

return encodeURIComponent(Array.prototype.join.call(args,"|")); }

function Query (what) {       return function (props, callback) {           request('action=query&' + what + "&" + props, callback); }   }

var query = {

titles: function (arg) { return Query('titles=' + encode_array(arg, arguments)) },

pageids: function (arg) { return Query('pageids=' + encode_array(arg, arguments)) },

revids: function (arg) { return Query('revids=' + encode_array(arg, arguments)) },       page: function (title) {           //self is this without the interference from javascript var self = { query: query.titles(title), title: title,

edit: function (callback, section) {                   var q = 'prop=info|revisions&intoken=edit&rvprop=content|timestamp';

if (section != null) section = '&rvsection=' + section; else section = '';

q += section;

self.query(q, function (res)                   {                        // should only be one pageid                        for (var pageid in res.query.pages)                        {                            var page = res.query.pages[pageid];                            var text = '';

if (page.revisions) text = page.revisions[0]['*']

//the "save" function callback(text, function (ntext, summary, postsave)                           {                                if (text == ntext || !ntext)                                    return;

if(!summary) summary = "";

request('action=edit&title=' + encodeURIComponent(self.title) +                                       '&text=' + encodeURIComponent(ntext) + section +                                        '&summary=' + encodeURIComponent(summary) +                                        '&token=' + encodeURIComponent(page.edittoken) +                                        '&starttimestamp=' + encodeURIComponent(page.starttimestamp) +                                         '&basetimestamp=' + encodeURIComponent(page.revisions[0].timestamp),                                        postsave                                    ) });                       }                    });                },

create: function (text, summary, minor) {                   self.edit(function(otext, save)                    {                        save(text, summary, minor);                    }); },

parse: function (text, callback) {                   request('action=parse&title=' + encodeURIComponent(self.title) + '&text=' + encodeURIComponent(text.replace('subst:','')), callback) },

parseFragment: function (text, callback) //To prevent 's being added {                   self.parse(' ' + text + ' ', function (res)                    {                        res.parse.text['*'] = res.parse.text['*'].replace(/^ /,).replace(/<\/div>$/,);                        callback(res);                    }); }            }            return self; }   };

return query; }

//A class to make settings persistant, and to store changes to them - yay function Preferences (context) {   //Repeated calls with the same context should get the same preferences object. if (arguments.callee[context]) return arguments.callee[context]; else arguments.callee[context] = this;

/**    * Change the value of a preference. *    * This will cause all the people subscribed to the function to recieve an     * update. *    * @param {string} name  The name of the preference * @param {string} value The new value of the preference. */   this.set = function (name, value) {       if (value === null || storage[name] === value) return;

storage[name] = value;

if (callbacks[name]) for (var i=0; i < callbacks[name].length; i++) callbacks[name][i](value);

updateCookie; }

/**    * Get the value of a preference. *    * If the preference isn't set, return the second argument or undefined. *    * @param {string} name  The name of the preference * @param {string} def The default value of the preference */   this.get = function (name, def) {       if (storage[name]) return storage[name]; else return def; }

var storage = {}; var callbacks = {};

// Save storage into the cookie. function updateCookie {       var value = ""; for (var name in storage) {           value += '&' + encodeURIComponent(name) + "=" + encodeURIComponent(storage[name]); }

setCookie('preferences' + context, value) }   // Load storage from the cookie. function updateStorage {       var value = getCookie('preferences' + context, value) || ''; var pairs = value.split('&');

for (var i=1; i < pairs.length; i++) {           var val = pairs[i].split('=');

if (storage[val[0]] === val[1]) continue;

if (callbacks[val[0]]) {               for (var j=0; j < callbacks[val[0]].length; j++) callbacks[val[0]][j](val[1]); }

storage[val[0]] = val[1]; }   }

//__init__ updateStorage; } /** * A generic page editor for the current page. * * This is a singleton and it displays a small interface in the top left after * the first edit has been registered. * * @public * this.page * this.addEdit * this.error * */ function Editor {   //Singleton if (arguments.callee.instance) return arguments.callee.instance else arguments.callee.instance = this;

/**    * Get the API page object associated with this editor */   this.page = API.page(wgPageName);

/**    * Add the specific edit to the page. *    * If the node is specified it will be highlighted now, and unhighlighted * when the change is saved. *    * @param {edit}  The edit {redo:, undo:, edit:, summary:} * @param {*node} The node to highlight. * @param {*boolean} private: used when edit added using redo. */   this.addEdit = function (edit, node, fromRedo) {       if (node) {           nodestack.push(node); node.style.cssText = "border: 2px #00FF00 dashed;" }

if(! fromRedo) redostack = [];

if(! (loaded && !loading)) load else {           var ntext = false; try {               ntext = edit.edit(currentText); }           catch (e) {               this.error("ERROR:" + e); }

if (ntext) {               currentText = ntext; edit.redo; }           else return false; }       fixButtons; editstack.push(edit); }

/**    * Display an error message to the user. *    * @param {string|node}  The message. */   this.error = function (message) {        if (!errorlog) {           errorlog = newNode('ul',{style: "background-color: #FFDDDD; margin: 0px -10px -10px -10px; padding: 10px;"}); presence.appendChild(errorlog); }       errorlog.appendChild(newNode('li', message)); }

var thiz = this; // this is set incorrectly when private functions are used as callbacks.

var editstack = []; // A list of the edits that have been applied to get currentText var redostack = []; // A list of the edits that have been recently undone. var nodestack = []; // A lst of nodes to which we have added highlighting

var loaded = false; // Is the page-text loaded? var loading = false; // Is the page-text loading?

var originalText = ""; // What was the contents of the page before we fiddled? var currentText = ""; // What is the contents now?

var savebutton; var undobutton; var redobutton;

var saveCallback; // The callback returned by the api's edit function to save.

var presence; // The HTML element in the top-left var errorlog; // The ul for sticking errors in. var savelog; // The ul for save messages.

// Disable useless buttons, enable useful ones. function fixButtons {       if(! presence) return; presence.style.display = "block"; undobutton.disabled = false; (editstack.length > 0 ? false : true); savebutton.disabled = false; undobutton.disabled; redobutton.disabled = false; (redostack.length > 0 ? false : true); }

//Ensure that the currentText variable reflects the originalText with all //edits in the editstack function updateCurrentText {       var text = originalText; for (var i=0; i < editstack.length; i++) {           var ntext = false; try {               ntext = editstack[i].edit(text); }           catch (e) {               thiz.error("ERROR:" + e); }           if (ntext && ntext != text) {               text = ntext; editstack[i].redo; }           else {               editstack = editstack.splice(0, i); break; }       }        currentText = text; fixButtons; }

//Move an edit from the editstack to the redostack function undo {       if (editstack.length == 0) return false; var edit = editstack.pop; redostack.push(edit); edit.undo;

updateCurrentText; fixButtons; return true; }

//Move an edit from the redostack to the editstack function redo {       if (redostack.length == 0) return; var edit = redostack.pop; thiz.addEdit(edit, null, true); fixButtons; }

//Called on first interaction to request originalText and display presence function load {       loading = true; thiz.page.edit(function (text, _save)       {            originalText = text;            saveCallback = _save;            loading = false;            loaded = true;

if (!presence) {               savebutton = newNode('button',"Save Changes", {'click': save}); undobutton = newNode('button',"Undo", {'click': undo}); redobutton = newNode('button', "Redo", {'click':redo});

presence = newNode('div',{'style':"position: fixed; top:0px; left: 0px; background-color: #00FF00; z-index: 10;padding: 30px;"}) //Fix fixed positioning for IE6/ /*@cc_on @if (@_jscript_version <= 5.6) presence.style.cssText = "position: absolute; top: expression((dummy = (document.documentElement.scrollTop || document.body.scrollTop || 0)) + 'px'); background-color: #00FF00; z-index: 10000; padding: 30px;" @end @*/               window.setTimeout(function  {                    presence.style.backgroundColor = "#CCCCFF";                    presence.style.padding = "10px";                }, 400);

presence.appendChild(newNode('div',{'style':"position: relative; top:0px; left:0px; margin: -10px; color: #0000FF;cursor:pointer;", click:function {while(undo);presence.style.display = "none";}},"X")) document.body.insertBefore(presence, document.body.firstChild); fixButtons;

presence.appendChild(newNode('p', newNode('b', "Page Editing"), newNode('br'), savebutton, newNode('br'), undobutton, redobutton)) }

updateCurrentText; });       fixButtons;    }

//Send the currentText back to the server to save. function save (summary) {       if (loading) window.setTimeout(save, 500);

if (!loaded) throw "Not loaded...";

loaded = false;

var sum = {}; for (var i=0; i<editstack.length; i++) {           sum[editstack[i].summary] = true; }       var summary = ""; for (var name in sum) {           summary += name + " "; }       editstack = []; redostack = []; if (! savelog) {           savelog = newNode('ul', {style: "background-color: #DDFFDD; margin: 0px -10px -10px -10px; padding: 10px;"}); presence.appendChild(savelog); }       var saveLi = newNode('li', 'Saving:' + summary + "..."); savelog.appendChild(saveLi); originalText = currentText; fixButtons; var nst = [] var node; while (node = nodestack.pop) {           nst.push(node); }       saveCallback(currentText, summary + "(Assisted)", function (res)        {            try {                saveLi.appendChild(newNode('span', newNode('b', " Saved "),                    newNode('a', {'href': wgScript + '?title=' + encodeURIComponent(mw.config.get('wgPageName')) + '&diff=' + encodeURIComponent(res.edit.newrevid) + '&oldid=' + encodeURIComponent(res.edit.oldrevid)}, "(Show changes)")));           }catch(e){                if (res.error)                {                    thiz.error("Not saved: " + String(res.error.info));                }                else                {                    thiz.error(newNode('p',String(e)));                }            }

for (var i=0; i < nst.length; i++) nst[i].style.cssText = "background-color: #0F0;border: 2px #0F0 solid;";

window.setTimeout(function {                var node;                while (node = nst.pop)                    node.style.cssText = "";            }, 400); fixButtons; });       fixButtons;    } }

var util = { getVanillaIndexOf: function (str, text, pos) {       if (!pos) pos = 0; var cpos = 0, tpos = 0, wpos = 0, spos = 0; do       { cpos = text.indexOf('', pos) + 3;

else if (pos == wpos) pos = text.indexOf(' ', pos) + 9;

else if (pos == tpos) //FIXME pos = text.indexOf('}}', pos) + 2;

} while (pos < Infinity) return -1; },

validateNoWikisyntax: function(field, nonempty) {       return function(txt, error) {           if(/[\[\{\|#\}\]]/.test(txt)) return error("Please don't use wiki markup ([]{}#|) in the " + field +"."); if(nonempty && !txt) return error("Please specify a " + field + "."); return txt; }   },

escapeRe: function(txt) {       return txt.replace(/([\\{}(\|)[\].?*+])/g, "\\$1"); },

getTransTable: function (text, gloss) {       var pos = 0; var transect = []; while(pos > -1) {           pos = util.getVanillaIndexOf('{'+'{trans-top', text, pos+1)	// }} if (util.matchGloss(text.substr(pos, text.indexOf('\n', pos)-pos), gloss)) {               transect.push(pos); }       }        if (transect.length > 1) {           var poss = transect; transect = []; for (var i=0; i -1 && pos > -1) return [pos, endpos]; }

return false; },

matchGloss: function (line, gloss) {       line = line.replace('{'+'{trans-top}}','{'+'{trans-top|Translations}}'); var words = gloss.split(' '); var pos = 0; for (var i=0; i < words.length; i++) {           pos = line.indexOf(words[i], pos); if (pos == -1) return false; }       return pos > -1; },

//User:Karelklic getTransGlossText: function (node) { var ret = ''; var children = node.childNodes; for (var i=0; i<children.length; i++) {           if (children[i].nodeType == 3) ret += children[i].nodeValue; else if (children[i].nodeName.match(/^(i|b)$/i)) ret += util.getTransGlossText(children[i]); else if (ret.match(/\w$/)) //Prevent new words from being created across node boundaries ret += " "; }       // all characters except a-zA-Z0-9 are changed to spaces return ret.replace(/\W/g, ' '); },

getTransGloss: function (ul) {       var node = ul; while (node && node.className.indexOf('NavFrame') == -1) node = node.parentNode;

if (!node) return '';

var children = node.childNodes; for (var i=0; i< children.length; i++) {           if(children[i].className && children[i].className.indexOf('NavHead') > -1) return util.getTransGlossText(children[i]); }       return ''; },

isTrreq: function (li) {       var spans = li.getElementsByTagName('span'); return (spans && spans.length > 0 && spans[0].className.indexOf("trreq") > -1) } };

/** * A small amount of common code that can be usefully applied to adder forms. * * An adder is assumed to be an object that has: * * .fields A object mapping field names to either validation functions used *         for text fields, or the word 'checkbox' * * .createForm  A function  that returns a newNode('form') to be added to the *             document (by appending to insertNode) * * .onsubmit  A function (values, register (wikitext, callback)) that accepts *           the validated set of values and processes them, the register *           function accepts wikitext and a continuation function to be  *            called with the result of rendering it. * * Before onsubmit or any validation functions are called, but after running * createForm, a new property .elements will be added to the adder which is a * dictionary mapping field names to HTML input elements. * * @param {editor} The current editor. * @param {adder} The relevant adder. * @param {insertNode} Where to insert this in the document. */ function AdderWrapper (editor, adder, insertNode) {   var form = adder.createForm var status = newNode('p');

form.appendChild(status); insertNode.appendChild(form);

adder.elements = {};

//This is all because IE doesn't reliably allow form.elements['name'] for (var i=0; i< form.elements.length; i++) {       adder.elements[form.elements[i].name] = form.elements[i]; }

form.onsubmit = function {       try {           var submit = true; var values = {} for (var name in adder.fields) {               if (adder.fields[name] == 'checkbox') {                   values[name] = adder.elements[name].checked ? name : false; }               else {                   values[name] = adder.fields[name](adder.elements[name].value || '', function (msg)                     {                        status.appendChild(newNode('span',{style:'color: red'}, msg, newNode('br')));                         return false                    }); if (values[name] === false) submit = false; }           }            if (!submit) return false;

status.innerHTML = 'Loading...'; adder.onsubmit(values, function (text, callback)           {                editor.page.parseFragment(text, function (res) {                   callback(res.parse.text['*']); status.innerHTML = ""; });           });           }        catch(e) {           status.innerHTML = "ERROR:" + e.description; return false; }

return false; }

} // An adder for translations on en.wikt function TranslationAdders (editor) {   function TranslationAdder (insertUl) {       // Hippietrail var langmetadata = new LangMetadata ;

this.fields = { lang: function (txt, error) {               if (txt && !/^((?:[a-z][a-z][a-z]?-)?[A-Z][a-z][a-z][a-z]|polytonic|unicode)$/.test(txt)) return txt; return error("Please use a language code. (en, fr, aaa)") },           word: util.validateNoWikisyntax('translation', true), qual: util.validateNoWikisyntax('qualifier'), tr: util.validateNoWikisyntax('transcription'), alt: util.validateNoWikisyntax('display name'), sc: function (txt, error) {               if (txt && !/^([A-Z][a-z]{3}|[a-z]{2}-Arab|polytonic|unicode)$/.test(txt)) return error(newNode('span', "Please use a ", newNode('a',{href: '/wiki/Category:Script templates'},"script template"), "(e.g. fa-Arab, Deva, polytonic)"))

if (!txt) txt = prefs.get('script-' + thiz.elements.lang.value, langmetadata.guessScript(thiz.elements.lang.value) || ''); if (txt == 'Latn') txt = ''; return txt; },           m: 'checkbox', f: 'checkbox', n: 'checkbox', c: 'checkbox', p: 'checkbox' };

this.createForm = function {           var controls = { lang: newNode('input', {size:4, type:'text', name:'lang', value:prefs.get('curlang',''), title:'The two or three letter ISO 639 language code'}), transliteration: newNode('span', newNode('a', {href: '/wiki/Wiktionary:Transliteration'}, "Transliteration"), ": ",                                     newNode('input', {name: "tr", title: "The word transliterated into the Latin alphabet."}), " (e.g. ázbuka for азбука)"), qualifier: newNode('p', "Qualifier: ", newNode('input', {name: 'qual', title: "A qualifier for the word"}), " (e.g. literally, formally, slang)"), display: newNode('p',"Page name: ", newNode('input', {name: 'alt', title: "The word with all of the dictionary-only diacritics."}), " (e.g. amo for amō)"), script: newNode('p', newNode('a', {href: '/wiki/Category:Script_templates'},"Script template"),": ",                    newNode('input', {name: 'sc', size: 6, title: "The script template to render this word in."}), "(e.g. Cyrl for Cyrillic, Latn for Latin)", newNode('br')), gender_m: newNode('span',newNode('input', {type: 'checkbox', name: 'm'}), 'masc. '), gender_f: newNode('span', newNode('input', {type: 'checkbox', name: 'f'}), 'fem. '), gender_n: newNode('span', newNode('input', {type: 'checkbox', name: 'n'}), 'neuter '), gender_c: newNode('span', newNode('input', {type: 'checkbox', name: 'c'}), 'common\u00A0gender '), plural: newNode('span', newNode('input', {type: 'checkbox', name: 'p'}), 'plural ', newNode('br')) };

controls.gender = newNode('p', controls.gender_m, controls.gender_f, controls.gender_n, controls.gender_c, controls.plural);

langInput = controls.lang;

var showButton = newNode('span',{'click': function            {                if (!advancedMode)                {                    advancedMode = true;                    showButton.innerHTML = " Less";                }                else                {                    advancedMode = false;                    showButton.innerHTML = " More";                }                updateScriptGuess.call(langInput, true);            }, 'style':"color: #0000FF;cursor: pointer;"}, advancedMode ? " Less" : " More");

function autoTransliterate { thiz.elements.alt.value = langmetadata.generateAltForm(thiz.elements.lang.value, thiz.elements.word.value) || ''; }           function updateScriptGuess (preserve) { preserve = (preserve === true);

//show all arguments function show {                   for (var i=0; i<arguments.length; i++) {                       if (arguments[i].nodeName.toLowerCase == 'p') arguments[i].style.display = "block"; else arguments[i].style.display = "inline"; }

}               //hide all arguments function hide {                   for (var i=0; i < arguments.length; i++) arguments[i].style.display = "none"; }               //if the first argument is false hide the remaining arguments, otherwise show them. function toggle (condition) {                   if (condition) //eww... show.apply(this, [].splice.call(arguments, 1, arguments.length - 1)); else hide.apply(this, [].splice.call(arguments, 1, arguments.length - 1)); }

if (!preserve) langInput.value = cleanLangCode(langInput.value);

var guess = prefs.get('script-' + langInput.value, langmetadata.guessScript(langInput.value || '')); if (!preserve) {                   if (guess) thiz.elements.sc.value = guess; else thiz.elements.sc.value = '';

autoTransliterate; }

var lang = langInput.value;

if (!advancedMode) {                   var g = langmetadata.getGenders(lang);

if (!lang) {                       hide(controls.gender); }                   else if (g == undefined) {                       show(controls.gender,controls.gender_m, controls.gender_f, controls.gender_n, controls.gender_c); }                   else {                       toggle(g.indexOf('m') > -1, controls.gender); toggle(g.indexOf('m') > -1, controls.gender_m); toggle(g.indexOf('f') > -1, controls.gender_f); toggle(g.indexOf('n') > -1, controls.gender_n); toggle(g.indexOf('c') > -1, controls.gender_c); }

var p = langmetadata.hasPlural(lang);

toggle(p !== false, controls.plural); toggle(g || p, controls.gender);

toggle(guess && guess != 'Latn', controls.transliteration);

var alt = langmetadata.needsAlt(lang);

toggle(alt === true, controls.display);

hide(controls.qualifier); //only in more hide(controls.script); //should be in less when array returned from .getScripts

}               else {                   show(controls.gender_m, controls.gender_f, controls.gender_n, controls.gender_c,                        controls.plural, controls.transliteration, controls.qualifier, controls.display,                        controls.script); }           }

//In browsers other than IE this can be in the newNode function above langInput.onchange = updateScriptGuess;

window.setTimeout(function {updateScriptGuess.call(langInput)}, 0);

inputForm = newNode('form',                       newNode('p', newNode('a',{href:"/wiki/User_talk:Conrad.Irwin/editor.js#Usage"},"Help"),' ', langInput, newNode('b',': '), newNode('input', {'name': 'word', size:20, change:autoTransliterate}), newNode('input',{'type': 'submit', 'value':'Preview translation'}), showButton ),                        controls.gender,                        controls.transliteration,                        controls.display,                        controls.qualifier,                        controls.script                    ) return inputForm; }

this.onsubmit = function (values, render) {           var wikitext = '{'+'{subst:' + values.lang + '}}: ' + (values.qual? '{'+'{qualifier|' + values.qual + '}} ' : '') + '{'+'{t' + (langmetadata.hasWiktionary(values.lang) ? '' : 'ø') + '|' + values.lang + '|' + (values.alt ? values.alt : values.word) + (values.m ? '|m' : '') + (values.f ? '|f' : '') + (values.n ? '|n' : '') + (values.c ? '|c' : '') + (values.p ? '|p' : '') + (values.tr ? '|tr=' + values.tr : '') + ((values.alt && values.alt != values.word) ? '|alt=' + values.word : '') + (values.sc ? '|sc=' + values.sc : '') + '}}'; render(wikitext, function (html) { registerEdits(values, wikitext, html)}); }

var thiz = this; var prefs = new Preferences('TranslationAdder'); var langInput; var inputForm; var advancedMode = prefs.get('more-display', 'none') != 'none'; //from ye days of yore

//Reset elements to default values. function resetElements {           if (prefs.get('more-display', 'none') != advancedMode ? 'block' : 'none') prefs.set('more-display', advancedMode ? 'block' : 'none'); //named for compatibility thiz.elements.word.value = thiz.elements.tr.value = thiz.elements.alt.value = thiz.elements.qual.value = ''; thiz.elements.m.checked = thiz.elements.f.checked = thiz.elements.n.checked = thiz.elements.c.checked = thiz.elements.p.checked = false; prefs.set('curlang', thiz.elements.lang.value); if ((thiz.elements.sc.value || 'Latn') != (prefs.get('script-'+thiz.elements.lang.value, langmetadata.guessScript(thiz.elements.lang.value) || 'Latn'))) {               prefs.set('script-'+thiz.elements.lang.value, thiz.elements.sc.value); thiz.elements.lang.update; }       }

// This is onsubmit after the wikitext has been rendered to give content function registerEdits (values, wikitext, content) {           var li = newNode('li'); li.innerHTML = content; var lang = getLangName(li); var summary = 't+' + values.lang + ':| values.word) + '';

var insertBefore = null; var nextLanguage = null;

function addEdit (edit, span) {               editor.addEdit({                    'undo': function                      {                        edit.undo;                        if (thiz.elements.word.value == "" && thiz.elements.tr.value == "" && thiz.elements.alt.value == "" && thiz.elements.qual.value == "")                       {                            var fields = ["lang","word","alt","qual","tr","sc"];                            var cb = "mnfcp".split("");                            for (var i=0; i < fields.length; i++)                            {                                thiz.elements[fields[i]].value = values[fields[i]];                            }                            for (var i=0; i < cb.length; i++)                            {                                thiz.elements[fields[i]].checked = values[fields[i]];                            }                        }                    },                    'redo': function                     {                        edit.redo;                        var fields = ["lang","word","alt","qual","tr","sc"];                        for (var i=0; i < fields.length; i++) {                           if (thiz.elements[fields[i]].value != values[fields[i]]) return; }                       resetElements; },                   'edit': edit.edit, 'summary': summary }, span);           }

if (lang) {               //Get all li's in this table row. var lis = []; var ls = insertUl.parentNode.parentNode.getElementsByTagName('li'); for (var j=0; j < ls.length; j++) lis.push(ls[j]);

ls = insertUl.parentNode.parentNode.getElementsByTagName('dd'); for (var j=0; j < ls.length; j++) lis.push(ls[j]);

for (var j=0; j < lis.length; j++) {                   if (lis[j].getElementsByTagName('form').length > 0) continue; var ln = getLangName(lis[j]); if (ln == lang) {                       var span = newNode('span'); var parent = lis[j]; if (util.isTrreq(parent)) {                           span.innerHTML = content; var trspan = parent.getElementsByTagName('span')[0]; addEdit({                               'redo': function  { parent.removeChild(trspan); parent.appendChild(span); },                                'undo': function  { parent.removeChild(span); parent.appendChild(trspan); },                                'edit': getEditFunction(values, wikitext, ln, values.lang, true, function (text, ipos) {                                   //Converting a Translation request into a translation var lineend = text.indexOf('\n', ipos); return text.substr(0, ipos) + wikitext + text.substr(lineend); })                           }, span); }                       else {                           if (parent.getElementsByTagName('ul').length + parent.getElementsByTagName('dl').length == 0) {                               span.innerHTML = ", " + content.substr(content.indexOf(':') + 1); addEdit({                                   'redo': function  { parent.appendChild(span) },                                    'undo': function  { parent.removeChild(span) },                                    'edit': getEditFunction(values, wikitext, ln, values.lang, false, function (text, ipos) {                                                //We are adding the wikitext to a list of translations that already exists. var lineend = text.indexOf('\n', ipos); wikitext = wikitext.replace('subst:',''); wikitext = wikitext.substr(wikitext.indexOf(':') + 1); return text.substr(0, lineend) + ", " + wikitext + text.substr(lineend); })                               }, span); return resetElements; }                           else {                               var node = parent.firstChild; var hastrans = false; while (node) {                                   if (node.nodeType == 1) {                                       var nn = node.nodeName.toUpperCase; if (nn == 'UL' || nn == 'DL') {                                           span.innerHTML = (hastrans ? ", ": " ") + content.substr(content.indexOf(':') + 1); addEdit({                                               'redo': function  { parent.insertBefore(span, node) },                                                'undo': function  { parent.removeChild(span) },                                                'edit': getEditFunction(values, wikitext, ln, values.lang, false, function (text, ipos) {                                                           //Adding the translation to a language that has nested translations under it                                                            var lineend = text.indexOf('\n', ipos); wikitext = wikitext.replace('subst:',''); wikitext = wikitext.substr(wikitext.indexOf(':') + 1); return text.substr(0, lineend) + (hastrans ? ", " : " ") + wikitext + text.substr(lineend); })                                           }, span); return resetElements; }                                       else {                                           hastrans = true; }

}                                   node = node.nextSibling; }                           }                        }                        return resetElements; }                   else if (ln && ln > lang && (!nextLanguage || ln < nextLanguage) && lis[j].parentNode.parentNode.nodeName.toLowerCase != 'li') {                       nextLanguage = ln; var parent = lis[j]; insertBefore = [ {                               'redo': function  {parent.parentNode.insertBefore(li, parent);}, 'undo': function {parent.parentNode.removeChild(li)}, 'edit': getEditFunction(values, wikitext, ln, getLangCode(parent), util.isTrreq(parent), function (text, ipos)                                       {                                            //Adding a new language's translation before another language's translation                                            var lineend = text.lastIndexOf('\n', ipos);                                            return text.substr(0, lineend) + "\n* " + wikitext + text.substr(lineend);                                        }) },li]; }               }            }            if (values.nested) {               nextLanguage = null; insertBefore = null;

var lis = insertUl.parentNode.parentNode.getElementsByTagName('li'); for (var j = 0; j < lis.length; j++) {                   //Ignore the editor form if (lis[j].getElementsByTagName('form').length > 0) continue;

//Don't look at nested translations if (lis[j].parentNode.parentNode.nodeName.toLowerCase != 'li') continue;

var ln = getLangName(lis[j]); if (ln == values.nested) {                       var sublis = lis[j].getElementsByTagName('li');

if (! sublis.length) sublis = lis[j].getElementsByTagName('dd');

if (sublis.length == 0) {                           var parent = lis[j]; var dd = newNode('dd'); var dl = newNode('dl', dd); dd.innerHTML = content;

addEdit({                               'redo': function  {parent.appendChild(dl);},                                'undo': function  {parent.removeChild(dl);},                                'edit': getEditFunction(values, wikitext, values.nested, null, util.isTrreq(parent), function (text, ipos) {                                           //Adding a new dl to an existing translation line var lineend = text.indexOf('\n', ipos); return text.substr(0, lineend) + "\n*: " + wikitext + text.substr(lineend); })                           }, dd); }                       else {                       //Adding a new dd to an existing dl

}                       return resetElements; }                   else if (ln && ln > values.nested && (!nextLanguage || ln < nextLanguage)) {                       nextLanguage = ln; var parent = lis[j]; li.innerHTML = values.nested + ":" + "" + content + ""; insertBefore = [ {                               'redo': function  {parent.parentNode.insertBefore(li, parent);}, 'undo': function {parent.parentNode.removeChild(li)}, 'edit': getEditFunction(values, wikitext, ln, getLangCode(parent), util.isTrreq(parent), function (text, ipos)                                       {                                            //Adding a new nested translation section.                                            var lineend = text.lastIndexOf('\n', ipos);                                            return text.substr(0, lineend) + "* " + values.nested + "\n*: " + wikitext + text.substr(lineend);                                        }) },li]; }               }            }

li.className = "trans-" + wikitext.replace(/.*\{\{subst:/,).replace(/\}\}.*/, ); if (insertBefore) {               addEdit(insertBefore[0], insertBefore[1]); }           else {               //Append the translations to the end (no better way found) addEdit({                   'redo': function  {insertUl.appendChild(li);},                    'undo': function  {insertUl.removeChild(li)},                    'edit': getEditFunction(values, wikitext)                }, li); }           return resetElements; }

//Get the wikitext modification for the current form submission. function getEditFunction (values, wikitext, findLanguage, findLangCode, trreq, callback) {           return function(text) {               var p = util.getTransTable(text, util.getTransGloss(insertUl));

if (!p) return editor.error("Could not find translation table for '" + values.lang + ":" + values.word + "'. Please improve glosses");

var stapos = p[0]; var endpos = p[1];

if (findLanguage) {                   var ipos = 0; if (trreq) {                       ipos = text.indexOf('{'+'{trreq|'+findLanguage+'}}', stapos); if (ipos < 0 || ipos > endpos) ipos = text.indexOf('{'+'{trreq|'+findLangCode+'}}', stapos); }                   else {

ipos = text.substr(stapos).search(RegExp("\\*[:*]? ?\\[\\[" + util.escapeRe(findLanguage) + "\\]\\]:")) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(RegExp('\\*[:*]? ?' + util.escapeRe(findLanguage) + ':')) + stapos; if (ipos < stapos| ipos > endpos) ipos = text.indexOf('{'+'{subst:'+findLangCode+'}}:', stapos); }                   if (ipos >= stapos && ipos < endpos) {                       return callback(text, ipos, trreq); }                   else {                       return editor.error("Could not find translation entry for '" + values.lang + ":" +values.word + "'. Please reformat"); }               }

return text.substr(0, endpos) + "* " + wikitext + "\n" + text.substr(endpos); };       }

//Given user input, return a language code. For all languages in ISO 639-1, this will convert the name and the ISO 639-3 code to the -1 code. //FIXME: move to meta-data function cleanLangCode(lang) {           var key = lang.toLowerCase.replace(' ',''); var dict = {aar:"aa",afar:"aa",abk:"ab",abkhazian:"ab",afr:"af",afrikaans:"af",aka:"ak",akan:"ak",amh:"am",amharic:"am",ara:"ar",arabic:"ar",arg:"an",aragonese:"an",asm:"as",assamese:"as",ava:"av",avaric:"av",ave:"ae",avestan:"ae",aym:"ay",aymara:"ay",aze:"az",azerbaijani:"az",bak:"ba",bashkir:"ba",bam:"bm",bambara:"bm",bel:"be",belarusian:"be",ben:"bn",bengali:"bn",bis:"bi",bislama:"bi",bod:"bo",tibetan:"bo",bos:"bs",bosnian:"bs",bre:"br",breton:"br",bul:"bg",bulgarian:"bg",cat:"ca",catalan:"ca",ces:"cs",czech:"cs",cha:"ch",chamorro:"ch",che:"ce",chechen:"ce",chu:"cu",churchslavic:"cu",chv:"cv",chuvash:"cv",cor:"kw",cornish:"kw",cos:"co",corsican:"co",cre:"cr",cree:"cr",cym:"cy",welsh:"cy",dan:"da",danish:"da",deu:"de",german:"de",div:"dv",dhivehi:"dv",dzo:"dz",dzongkha:"dz",ell:"el",greek:"el",eng:"en",english:"en",epo:"eo",esperanto:"eo",est:"et",estonian:"et",eus:"eu",basque:"eu",ewe:"ee",fao:"fo",faroese:"fo",fas:"fa",persian:"fa",fij:"fj",fijian:"fj",fin:"fi",finnish:"fi",fra:"fr",french:"fr",fry:"fy",westernfrisian:"fy",ful:"ff",fulah:"ff",gla:"gd",scottishgaelic:"gd",gle:"ga",irish:"ga",glg:"gl",galician:"gl",glv:"gv",manx:"gv",grn:"gn",guarani:"gn",guj:"gu",gujarati:"gu",hat:"ht",haitian:"ht",hau:"ha",hausa:"ha",heb:"he",hebrew:"he",her:"hz",herero:"hz",hin:"hi",hindi:"hi",hmo:"ho",hirimotu:"ho",hrv:"hr",croatian:"hr",hun:"hu",hungarian:"hu",hye:"hy",armenian:"hy",ibo:"ig",igbo:"ig",ido:"io",iii:"ii",sichuanyi:"ii",iku:"iu",inuktitut:"iu",ile:"ie",interlingue:"ie",ina:"ia",interlingua:"ia",ind:"id",indonesian:"id",ipk:"ik",inupiaq:"ik",isl:"is",icelandic:"is",ita:"it",italian:"it",jav:"jv",javanese:"jv",jpn:"ja",japanese:"ja",kal:"kl",kalaallisut:"kl",kan:"kn",kannada:"kn",kas:"ks",kashmiri:"ks",kat:"ka",georgian:"ka",kau:"kr",kanuri:"kr",kaz:"kk",kazakh:"kk",khm:"km",centralkhmer:"km",kik:"ki",kikuyu:"ki",kin:"rw",kinyarwanda:"rw",kir:"ky",kirghiz:"ky",kom:"kv",komi:"kv",kon:"kg",kongo:"kg",kor:"ko",korean:"ko",kua:"kj",kuanyama:"kj",kur:"ku",kurdish:"ku",lao:"lo",lat:"la",latin:"la",lav:"lv",latvian:"lv",lim:"li",limburgan:"li",lin:"ln",lingala:"ln",lit:"lt",lithuanian:"lt",ltz:"lb",luxembourgish:"lb",lub:"lu",lubakatanga:"lu",lug:"lg",ganda:"lg",mah:"mh",marshallese:"mh",mal:"ml",malayalam:"ml",mar:"mr",marathi:"mr",mkd:"mk",macedonian:"mk",mlg:"mg",malagasy:"mg",mlt:"mt",maltese:"mt",mon:"mn",mongolian:"mn",mri:"mi",maori:"mi",msa:"ms",malay:"ms",mya:"my",burmese:"my",nau:"na",nauru:"na",nav:"nv",navajo:"nv",nbl:"nr",southndebele:"nr",nde:"nd",northndebele:"nd",ndo:"ng",ndonga:"ng",nep:"ne",nepali:"ne",nld:"nl",dutch:"nl",nno:"nn",norwegiannynorsk:"nn",nob:"nb",norwegianbokmal:"nb",nor:"no",norwegian:"no",nya:"ny",nyanja:"ny",oci:"oc",occitan:"oc",oji:"oj",ojibwa:"oj",ori:"or",oriya:"or",orm:"om",oromo:"om",oss:"os",ossetian:"os",pan:"pa",panjabi:"pa",pli:"pi",pali:"pi",pol:"pl",polish:"pl",por:"pt",portuguese:"pt",pus:"ps",pushto:"ps",que:"qu",quechua:"qu",roh:"rm",romansh:"rm",ron:"ro",romanian:"ro",run:"rn",rundi:"rn",rus:"ru",russian:"ru",sag:"sg",sango:"sg",san:"sa",sanskrit:"sa",sin:"si",sinhala:"si",slk:"sk",slovak:"sk",slv:"sl",slovenian:"sl",sme:"se",northernsami:"se",smo:"sm",samoan:"sm",sna:"sn",shona:"sn",snd:"sd",sindhi:"sd",som:"so",somali:"so",sot:"st",southernsotho:"st",spa:"es",spanish:"es",sqi:"sq",albanian:"sq",srd:"sc",sardinian:"sc",srp:"sr",serbian:"sr",ssw:"ss",swati:"ss",sun:"su",sundanese:"su",swa:"sw",swahili:"sw",swe:"sv",swedish:"sv",tah:"ty",tahitian:"ty",tam:"ta",tamil:"ta",tat:"tt",tatar:"tt",tel:"te",telugu:"te",tgk:"tg",tajik:"tg",tgl:"tl",tagalog:"tl",tha:"th",thai:"th",tir:"ti",tigrinya:"ti",ton:"to",tonga:"to",tsn:"tn",tswana:"tn",tso:"ts",tsonga:"ts",tuk:"tk",turkmen:"tk",tur:"tr",turkish:"tr",twi:"tw",uig:"ug",uighur:"ug",ukr:"uk",ukrainian:"uk",urd:"ur",urdu:"ur",uzb:"uz",uzbek:"uz",ven:"ve",venda:"ve",vie:"vi",vietnamese:"vi",vol:"vo",volapuk:"vo",wln:"wa",walloon:"wa",wol:"wo",wolof:"wo",xho:"xh",xhosa:"xh",yid:"yi",yiddish:"yi",yor:"yo",yoruba:"yo",zha:"za",zhuang:"za",zho:"zh",chinese:"zh",zul:"zu",zulu:"zu"}; if (dict[key]) return dict[key]; else return lang; }       // For an  in well-formed translation sections, return the language name. function getLangName(li) {           var guess = li.textContent || li.innerText;

if (guess) guess = guess.substr(0, guess.indexOf(':'));

if (guess == 'Template') return false;

return guess; }

// Try to get the language code from an  containing { {t t+ or t-	// }} function getLangCode(li) {           var spans = li.getElementsByTagName('span'); for (var i=0; i < spans.length; i++) {               if (spans[i].className == "tlc") return spans[i].innerHTML; }           if (li.className.indexOf('trans-') == 0) return li.className.substr(2); return false; }

}   var tables = document.getElementsByTagName('table'); for (var i=0; i -1 && util.getTransGloss(tables[i]) != 'Translations to be checked') {           var _lists = tables[i].getElementsByTagName('ul'); var lists = []; for (var j=0; j<_lists.length; j++) if (_lists[j].parentNode.nodeName.toLowerCase == 'td') lists.push(_lists[j]);

if (lists.length == 0) {               tables[i].getElementsByTagName('td')[0].appendChild(newNode('ul')); lists = tables[i].getElementsByTagName('ul'); }           if (lists.length == 1) {               var table = tables[i].getElementsByTagName('td')[2] if (table) {                   table.appendChild(newNode('ul')); lists = tables[i].getElementsByTagName('ul'); }           }            if (lists) {               var li = newNode('li'); var ul = lists[lists.length - 1]; var table = tables[i]; if (table.getElementsByTagName('tbody').length > 0) table = table.getElementsByTagName('tbody')[0]; table.appendChild(newNode('tr', newNode('td'), newNode('td'), newNode('td', {'style':'text-align: left'},newNode('ul', li)))); new AdderWrapper(editor, new TranslationAdder(ul), li); }       }    } }

function TranslationBalancers(editor) {   function TranslationBalancer (insertTd) {       var left; var right; var moveLeft; var moveRight;

//create the form function init {           var cns = insertTd.parentNode.childNodes; var tds = []; for (var i=0; i 0) left = left[0]; else {               left = newNode('ul'); tds[0].appendChild(left); }

right = tds[2].getElementsByTagName('ul'); if (right.length > 0) right = right[0]; else {               right = newNode('ul'); tds[2].appendChild(right); }

moveLeft = newNode('input',{'type':'submit','name':'ml', 'value':'←', 'click': function{return getEditObject('←')}}); moveRight = newNode('input',{'type':'submit','name':'mr', 'value':'→', 'click': function{return getEditObject('→')}});

var form = newNode('form', moveLeft, newNode('br'), moveRight); insertTd.appendChild(form); form.onsubmit = function { return false; } }

//store the edit object with the editor function getEditObject(move) {           if (move == '→') {               var li = left.lastChild; while (li && li.nodeName.toLowerCase != 'li') li = li.previousSibling;

if (li && li.childNodes.length > li.getElementsByTagName('form').length) {                   editor.addEdit({                        'redo': function  {left.removeChild(li); right.insertBefore(li, right.firstChild);},                        'undo': function  {right.removeChild(li); left.appendChild(li);},                        'edit': getEdit(util.getTransGloss(moveRight.parentNode), true),                        'summary': 't-balance'                    }); }           }            else if (move == '←') {               var li = right.firstChild; while (li && li.nodeName.toLowerCase != 'li') li = li.nextSibling;

if (li && li.childNodes.length > li.getElementsByTagName('form').length) {                   editor.addEdit({                        'redo': function  {right.removeChild(li); left.appendChild(li);},                        'undo': function  {left.removeChild(li); right.insertBefore(li, right.firstChild);},                        'edit': getEdit(util.getTransGloss(moveLeft.parentNode), false),                        'summary': 't-balance'                    }); }           }        }

//get the wikitext modification function getEdit(gloss, moveRight) {           return function (text) {               var p = util.getTransTable(text, gloss);

if (!p) return editor.error("Could not find translation table, please improve glosses.");

var stapos = p[0]; var endpos = p[1];

var midpos = text.indexOf('{'+'{trans-mid}}', stapos);

if (midpos < stapos || midpos > endpos) return editor.error("Could not find {"+"{trans-mid}}, please correct page.");

var midstart = text.lastIndexOf("\n", midpos); var midend = text.indexOf("\n", midpos);

if (moveRight) {                   var linestart = text.lastIndexOf("\n", midstart - 3); while (/^[:*#;]$/.test(text.substr(linestart+2,1))) linestart = text.lastIndexOf("\n", linestart - 1);

return text.substr(0, linestart) + text.substr(midstart, midend - midstart) + text.substr(linestart, midstart - linestart) + text.substr(midend); }               else {                   var lineend = text.indexOf("\n", midend + 3); while (/^[:*#;]$/.test(text.substr(lineend+2,1))) lineend = text.indexOf("\n", lineend + 1);

return text.substr(0, midstart) + text.substr(midend, lineend - midend) + text.substr(midstart, midend - midstart) + text.substr(lineend); }           }        }        init; }

var tables = document.getElementsByTagName('table'); for (var i=0; i -1 && util.getTransGloss(tables[i]) != 'Translations to be checked') {           var tr = tables[i].getElementsByTagName('tr')[0];

var passed = 0; for (var j=0; j<tr.childNodes.length; j++) {               if (tr.childNodes[j].nodeName.toUpperCase == 'TD') {                   if (passed == 1) {                       new TranslationBalancer(tr.childNodes[j]); }                   passed ++; }           }        }    }

}

function LangMetadata {   //Singleton if (arguments.callee.instance) return arguments.callee.instance else arguments.callee.instance = this;

var metadata = {aa:{hw:true,sc:["Latn","Ethi"]},ab:{hw:true,sc:["Cyrl","Latn","Geor"]},af:{g:"",hw:true,p:true,sc:"Latn"},ak:{hw:true},akk:{g:"mf",p:true,sc:"Xsux"},als:{hw:true},am:{g:"mf",hw:true,p:true,sc:"Ethi"},an:{hw:true,sc:"Latn"},ang:{alt:true,g:"mfn",hw:true,p:true,sc:"Latn"},ar:{alt:true,g:"mf",hw:true,p:true,sc:"Arab"},arc:{g:"mf",p:true,sc:"Hebr"},arz:{alt:true,g:"mf",p:true,sc:"Arab"},as:{hw:true,sc:"Beng"},ast:{g:"mf",hw:true,p:true,sc:"Latn"},av:{hw:true,sc:"Cyrl"},ay:{hw:true},az:{alt:false,g:"",hw:true,sc:["Latn","Cyrl","Arab"]},ba:{hw:true,sc:"Cyrl"},bar:{sc:"Latn"},be:{g:"mfn",hw:true,p:true,sc:["Cyrl","Latn"]},"be-x-old":{sc:"Cyrl"},bg:{g:"mfn",hw:true,p:true,sc:"Cyrl"},bh:{hw:true,sc:"Deva"},bhb:{sc:"Deva"},bi:{hw:true,sc:"Latn"},bm:{hw:true,sc:["Latn","Nkoo","Arab"]},bn:{g:"",hw:true,sc:"Beng"},bo:{hw:true,sc:"Tibt"},br:{g:"mf",hw:true,sc:"Latn"},bs:{hw:true,sc:"Latn"},ca:{g:"mf",hw:true,p:true,sc:"Latn"},ch:{hw:true,sc:"Latn"},chr:{hw:true,sc:"Cher"},co:{hw:true,sc:"Latn"},cr:{hw:true,sc:"Cans"},crh:{alt:false,g:"",sc:"Latn"},cs:{g:"mfn",hw:true,p:true,sc:"Latn"},csb:{hw:true},cu:{g:"mfn",p:true,sc:["Cyrs","Glag"]},cv:{alt:false,g:"",sc:"Cyrl"},cy:{g:"mf",hw:true,p:true,sc:"Latn"},da:{g:"cn",hw:true,p:true,sc:"Latn"},de:{g:"mfn",hw:true,p:true,sc:"Latn"},dv:{hw:true,p:true,sc:"Thaa"},dz:{hw:true,sc:"Tibt"},el:{g:"mfn",hw:true,p:true,sc:"Grek"},en:{g:"",hw:true,p:true,sc:"Latn"},eo:{g:"",hw:true,p:true,sc:"Latn"},es:{alt:false,g:"mf",hw:true,p:true,sc:"Latn"},et:{alt:false,g:"",hw:true,p:true,sc:"Latn"},ett:{p:true,sc:"Ital"},eu:{alt:false,g:"",hw:true,p:true,sc:"Latn"},fa:{g:"",hw:true,sc:"Arab",wsc:"fa-Arab"},fi:{g:"",hw:true,p:true,sc:"Latn"},fil:{g:"",p:false,sc:"Latn"},fj:{hw:true,sc:"Latn"},fo:{g:"mfn",hw:true,sc:"Latn"},fr:{alt:false,g:"mf",hw:true,p:true,sc:"Latn"},fy:{hw:true,sc:"Latn"},ga:{hw:true,sc:"Latn"},gd:{hw:true,sc:"Latn"},gez:{sc:"Ethi"},gl:{hw:true,sc:"Latn"},gmy:{sc:"Linb"},gn:{hw:true},got:{sc:"Goth"},grc:{g:"mfn",p:true,sc:"Grek",wsc:"polytonic"},gu:{hw:true,sc:"Gujr"},gv:{hw:true},ha:{hw:true},har:{sc:"Ethi"},he:{alt:true,g:"mf",hw:true,p:true,sc:"Hebr"},hi:{g:"mf",hw:true,p:true,sc:"Deva"},hit:{sc:"Xsux"},hr:{alt:true,g:"mfn",hw:true,p:true,sc:"Latn"},hsb:{hw:true},hu:{alt:false,g:"",hw:true,p:true,sc:"Latn"},hy:{alt:false,g:"",hw:true,sc:"Armn"},ia:{alt:false,g:"",hw:true,sc:"Latn"},id:{hw:true,sc:"Latn"},ie:{alt:false,g:"",hw:true,sc:"Latn"},ik:{hw:true},ims:{sc:"Ital"},io:{hw:true},is:{alt:false,g:"mfn",hw:true,p:true,sc:"Latn"},it:{alt:false,g:"mf",hw:true,p:true,sc:"Latn"},iu:{hw:true},ja:{alt:false,g:"",hw:true,p:false,sc:"Jpan"},jbo:{hw:true,sc:"Latn"},jv:{hw:true},ka:{alt:false,g:"",hw:true,sc:"Geor"},kjh:{sc:"Cyrl"},kk:{alt:false,g:"",hw:true,sc:"Cyrl"},kl:{hw:true},km:{hw:true,sc:"Khmr"},kn:{hw:true,sc:"Knda"},ko:{alt:false,g:"",hw:true,p:false,sc:"Kore"},ks:{hw:true,sc:["Arab","Deva"],wsc:"ks-Arab"},ku:{hw:true,sc:"Arab",wsc:"ku-Arab"},kw:{hw:true},ky:{alt:false,g:"",hw:true,sc:"Cyrl"},la:{alt:true,g:"mfn",hw:true,p:true,sc:"Latn"},lb:{hw:true},lez:{sc:"Cyrl"},li:{hw:true},ln:{hw:true},lo:{alt:false,g:"",hw:true,p:false,sc:"Laoo"},lt:{alt:true,g:"mf",hw:true,p:true,sc:"Latn"},lv:{alt:false,g:"mf",hw:true,p:true,sc:"Latn"},mg:{hw:true},mh:{hw:true},mi:{alt:false,g:0,hw:true,sc:"Latn"},mk:{hw:true,sc:"Cyrl"},ml:{g:"",hw:true,sc:"Mlym"},mn:{alt:false,g:"",hw:true,sc:["Cyrl","Mong"]},mo:{hw:true,sc:"Cyrl"},mol:{sc:"Cyrl"},mr:{g:"mfn",hw:true,sc:"Deva"},ms:{hw:true},mt:{g:"mf",hw:true,sc:"Latn"},my:{hw:true,sc:"Mymr"},na:{hw:true},nah:{hw:true},nds:{hw:true},ne:{hw:true,sc:"Deva"},nl:{alt:false,g:"mfn",hw:true,p:true,sc:"Latn"},nn:{alt:false,g:"mfn",hw:true,p:true,sc:"Latn"},no:{alt:false,g:"mfn",hw:true,p:true,sc:"Latn"},oc:{hw:true},om:{hw:true},or:{hw:true,sc:"Orya"},os:{alt:false,g:"",sc:"Cyrl"},osc:{sc:"Ital"},ota:{sc:"Arab",wsc:"ota-Arab"},pa:{g:"mf",hw:true,p:true,sc:["Guru","Arab"]},peo:{sc:"Xpeo"},phn:{sc:"Phnx"},pi:{hw:true},pjt:{sc:"Latn"},pl:{g:"mfn",hw:true,p:true,sc:"Latn"},ps:{hw:true,sc:"Arab",wsc:"ps-Arab"},pt:{alt:false,g:"mf",hw:true,p:true,sc:"Latn"},qu:{hw:true},rm:{hw:true},rn:{hw:true},ro:{g:"mfn",hw:true,p:true,sc:"Latn"},"roa-rup":{hw:true},ru:{alt:true,g:"mfn",hw:true,p:true,sc:"Cyrl"},rw:{hw:true,sc:"Latn"},sa:{g:"mfn",hw:true,p:true,sc:"Deva"},sc:{hw:true},scn:{hw:true},sd:{hw:true,sc:"Arab",wsc:"sd-Arab"},sg:{hw:true},sh:{hw:true},si:{hw:true,sc:"Sinh"},simple:{hw:true,sc:"Latn"},sk:{g:"mfn",hw:true,p:true,sc:"Latn"},sl:{g:"mfn",hw:true,p:true,sc:"Latn"},sm:{hw:true},sn:{hw:true},so:{hw:true},spx:{sc:"Ital"},sq:{alt:false,g:"mf",hw:true,sc:"Latn"},sr:{g:"mfn",hw:true,p:true,sc:["Cyrl","Latn"]},ss:{hw:true},st:{hw:true},su:{hw:true},sux:{sc:"Xsux"},sv:{alt:false,g:"nc",hw:true,p:true,sc:"Latn"},sw:{alt:false,g:"",hw:true,sc:"Latn"},syr:{sc:"Syrc"},ta:{alt:false,g:"",hw:true,sc:"Taml"},te:{alt:false,g:"",hw:true,sc:"Telu"},tg:{alt:false,g:"",hw:true,sc:"Cyrl"},th:{alt:false,g:"",hw:true,p:false,sc:"Thai"},ti:{hw:true,sc:"Ethi"},tig:{sc:"Ethi"},tk:{alt:false,g:"",hw:true,sc:"Latn"},tl:{g:"",hw:true,p:false,sc:["Latn","Tglg"]},tmr:{sc:"Hebr"},tn:{hw:true},to:{hw:true},tokipona:{hw:true},tpi:{hw:true,sc:"Latn"},tr:{alt:true,g:"",hw:true,p:true,sc:"Latn"},ts:{hw:true},tt:{alt:false,g:"",hw:true,sc:"Cyrl"},tw:{hw:true},ug:{hw:true,sc:"Arab",wsc:"ug-Arab"},uga:{sc:"Ugar"},uk:{g:"mfn",hw:true,p:true,sc:"Cyrl"},ur:{g:"mf",hw:true,p:true,sc:"Arab",wsc:"ur-Arab"},uz:{alt:false,g:"",hw:true,sc:"Latn"},vi:{g:"",hw:true,p:false,sc:"Latn"},vo:{hw:true},wa:{hw:true},wo:{hw:true},xae:{sc:"Ital"},xcr:{sc:"Cari"},xfa:{sc:"Ital"},xh:{hw:true},xlc:{sc:"Lyci"},xld:{sc:"Lydi"},xlu:{sc:"Xsux"},xrr:{sc:"Ital"},xst:{sc:"Ethi"},xum:{sc:"Ital"},xve:{sc:"Ital"},xvo:{sc:"Ital"},yi:{g:"mfn",hw:true,p:true,sc:"Hebr",wsc:"yi-Hebr"},yo:{hw:true},yua:{alt:true,p:true,sc:"Latn"},za:{hw:true},zh:{g:"",hw:true,p:false,sc:"Hani"},"zh-classical":{sc:"Hant"},"zh-min-nan":{hw:true,sc:"Latn"},"zh-yue":{sc:"Hani"},zu:{hw:true,sc:"Latn"}};

//The language code is necessary in case someone has just added a translation into "Norwegian" and wants to add a "Nynorsk" translation //as the wikitext will contain Norwegian: not Norwegian:. This does not support linking of the headings, it may not need to. // FIXME: This is all wrong....    var nesting = {nn: ['Norwegian', 'no'], nb: ['Norwegian', 'no'], dsb: ['Sorbian',null], hsb: ['Sorbian',null], ang:['English','en'], enm: ['English','en']}

var altForm = { ang: {from:"ĀāǢǣĊċĒēĠġĪīŌōŪūȲȳ", to:"AaÆæCcEeGgIiOoUuYy", strip:"\u0304\u0307"}, //macron and above dot ar: {strip:"\u064B\u064C\u064D\u064E\u064F\u0650\u0651\u0652"}, he: {strip:"\u05B0\u05B1\u05B2\u05B3\u05B4\u05B5\u05B6\u05B7\u05B8\u05B9\u05BA\u05BB\u05BC\u05BD\u05BF\u05C1\u05C2"}, hr: {from:"ȀȁÀàȂȃÁáĀāȄȅÈèȆȇÉéĒēȈȉÌìȊȋÍíĪīȌȍÒòȎȏÓóŌōȐȑȒȓŔŕȔȕÙùȖȗÚúŪū", to:"AaAaAaAaAaEeEeEeEeEeIiIiIiIiIiOoOoOoOoOoRrRrRrUuUuUuUuUu", strip:"\u030F\u0300\u0311\u0301\u0304"}, la: {from:"ĀāĒēĪīŌōŪū", to:"AaEeIiOoUu",strip:"\u0304"}, //macron lt: {from:"áãàéẽèìýỹñóõòúù", to:"aaaeeeiyynooouu", strip:"\u0340\u0301\u0303"}, sh: {from:"ȀȁÀàȂȃÁáĀāȄȅÈèȆȇÉéĒēȈȉÌìȊȋÍíĪīȌȍÒòȎȏÓóŌōȐȑȒȓŔŕȔȕÙùȖȗÚúŪū", to:"AaAaAaAaAaEeEeEeEeEeIiIiIiIiIiOoOoOoOoOoRrRrRrUuUuUuUuUu", strip:"\u030F\u0300\u0311\u0301\u0304"}, sr: {from:"ȀȁÀàȂȃÁáĀāȄȅÈèȆȇÉéĒēȈȉÌìȊȋÍíĪīȌȍÒòȎȏÓóŌōȐȑȒȓŔŕȔȕÙùȖȗÚúŪū", to:"AaAaAaAaAaEeEeEeEeEeIiIiIiIiIiOoOoOoOoOoRrRrRrUuUuUuUuUu", strip:"\u030F\u0300\u0311\u0301\u0304"}, tr: {from:"ÂâÛû", to:"AaUu",strip:"\u0302"} };    //Returns true if the specified lang.wiktionary exists according to the meta list this.hasWiktionary = function(lang) {       if (metadata[lang]) return metadata[lang].hw; }

//Given a language code return a default script code. this.guessScript = function(lang) {       if (metadata[lang]) { // enwikt language template? (ur-Arab, polytonic) if (metadata[lang].wsc) { return metadata[lang].wsc; }           // ISO script code? (Arab, Grek) if (metadata[lang].sc) { if (typeof metadata[lang].sc == 'object') return metadata[lang].sc[0]; else return metadata[lang].sc; }       }

return false; }

//Returns a string of standard gender letters (mfnc) or an empty string this.getGenders = function(lang) {       if (metadata[lang]) return metadata[lang].g;   }

//Returns true if the specified lang has the concept of plural nouns this.hasPlural = function(lang) {       if (metadata[lang]) return metadata[lang].p;   }

//Returns true if the specified lang uses optional vowels or diacritics this.needsAlt = function(lang) {       if (metadata[lang]) return metadata[lang].alt && (!altForm[lang]); }

//   this.nestedUnder = function (lang) //   { //        if (nesting[lang]) //           return nesting[lang]; //   }

this.generateAltForm = function (lang, word) {       //FIXME: use a dictionary and iterate along the string. // this is horrendously slow and horrid. if (altForm[lang]) {           var alt = altForm[lang];

var map = {};

if (alt.from && alt.to) {               for (var i = 0; i < alt.from.length; i++) {                   map[alt.from.charAt(i)] = alt.to.charAt(i); }           }            if (alt.strip) {               for (var i = 0; i < alt.strip.length; i++) {                   map[alt.strip.charAt(i)] = ""; }           }

var input = word.split(""); var output = "";

for (var i = 0; i < input.length; i++) {               var repl = map[input[i]]; output += (repl == null) ? input[i] : repl; }           return output; }   } }

$(function {

var prefs = new Preferences('EditorJs');

if (prefs.get('enabled', 'true') == 'true') {       if (! window.loadedEditor) {           window.loadedEditor = true; var editor = new Editor; TranslationAdders(editor); TranslationBalancers(editor); }   }

// The enable-disable button on WT:EDIT var node = document.getElementById('editor-js-disable-button');

if (node) {       node.innerHTML = ""; var toggle = newNode('span', {click: function        {            if (prefs.get('enabled', 'true') == 'true')            {                toggle.innerHTML = "Enable";                prefs.set('enabled', 'false');            }            else            {                toggle.innerHTML = "Disable";                prefs.set('enabled', 'true');            }

} }, (prefs.get('enabled', 'true') == 'true' ? 'Disable' : 'Enable'))

node.appendChild(toggle); } })