User:Hippietrail/editor.js
Appearance
Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.
- Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
- Konqueror and Chrome: click Reload or press F5;
- Opera: clear the cache in Tools → Preferences;
- Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.
- This script lacks a documentation subpage. Please create it.
- Useful links: root page • root page’s subpages • links • redirects • your own
/** 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 <p>'s being added
{
self.parse('<div>' + text + '</div>', function (res)
{
res.parse.text['*'] = res.parse.text['*'].replace(/^<div>/,'').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 + "([[WT:EDIT|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);
tpos = text.indexOf('{'+'{', pos);
wpos = text.indexOf('<nowiki>', pos);
spos = text.indexOf(str, pos);
pos = Math.min(
Math.min(
cpos == -1 ? Infinity : cpos ,
tpos == -1 ? Infinity : tpos
),
Math.min(
wpos == -1 ? Infinity : wpos,
spos == -1 ? Infinity : spos
)
)
if (pos == spos)
return pos == Infinity ? -1 : pos;
else if (pos == cpos)
pos = text.indexOf('-->', pos) + 3;
else if (pos == wpos)
pos = text.indexOf('</nowiki>', 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<poss.length; i++)
{
pos = poss[i];
if (util.matchGloss(gloss, text.substr(pos, text.indexOf('\n', pos)-pos).replace('{'+'{trans-top','').replace(/\W/g, ' ')))
{
transect.push(pos);
}
}
}
if (transect.length == 1)
{
pos = transect[0];
pos = text.indexOf('}}\n', pos) + 3;
var endpos = text.indexOf('{'+'{trans-bottom}}', pos);
if (endpos > -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.alt || 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 + ":" + "<dl><dd>" + content + "</dd></dl>";
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 <li> 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 <li> 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<tables.length; i++)
{
if (tables[i].className.indexOf('translations') > -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<cns.length; i++)
{
if (cns[i].nodeName.toUpperCase() == 'TD')
tds.push(cns[i])
}
left = tds[0].getElementsByTagName('ul');
if (left.length > 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<tables.length; i++)
{
if (tables[i].className.indexOf('translations') > -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);
}
})