Участник:Pavliukdanila/Черновичок

Материал из Викисловаря

//

Документация

// // implicit dependencies : ext.gadget.Editor,ext.gadget.LegacyScriptsNewNode,jquery.cookie,ext.gadget.LanguageUtils,mediawiki.RegExp /* jshint maxerr:1048576, strict:true, undef:true, latedef:true, es5:true, sub:true */ /* global mw, newNode, importScript, importScriptURI, $, AdderWrapper */ /** * Storage of "string" preferences. */ function CookiePreferences(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; var storage = {}; var defaults = {}; /** * Change the value of a preference and store into a cookie. */ this.set = function (name, value) { if (value === null || storage[name] === value) return; storage[name] = value; updateCookie(); }; /** * Get the value of a preference from the cookie or default * * If the preference isn't set, return the second argument or undefined. */ this.get = function (name, def) { if (storage[name]) return storage[name]; else if (defaults[name]) return defaults[name]; else return def; }; /** * let the default for get(name) be value for this session */ this.setDefault = function (name, value) { defaults[name] = value; }; // Save storage into the cookie. function updateCookie() { var value = ""; for (var name in storage) { value += '&' + encodeURIComponent(name) + "=" + encodeURIComponent(storage[name]); } $.cookie('preferences' + context, value, { expires: 30 }); } // Load storage from the cookie. // NOTE: If you wish to update the cookie format, both loading and storing // must continue to work for 30 days. function updateStorage() { var value = $.cookie('preferences' + context, value, { expires: 30 }) || ''; var pairs = value.split('&'); for (var i = 1; i < pairs.length; i++) { var val = pairs[i].split('='); if (storage[val[0]] === val[1]) continue; storage[val[0]] = val[1]; } } //__init__ updateStorage(); } 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; }; }, // pos is a position in the line containing the gloss getWikitextGloss: function (txt, pos) { var g_start = txt.lastIndexOf('\n{{trans-top', pos) + 1; var g_end = txt.indexOf('\n', pos); var g_line = txt.substr(g_start, g_end - g_start); g_line = g_line.replace("{{trans-top}}", "{{trans-top|Translations}}"); return g_line.replace(/\{\{trans-top\|(.*)\}\}/, "$1"); }, // get [start_pos, end_pos] of position of wikitext for trans_table containing node in text getTransTable: function (text, node, recursive) { var gloss = util.getTransGloss(node); var pos = 0; var transect = []; while (pos > -1) { pos = util.getVanillaIndexOf('{{trans-top', text, pos + 1); // }} if (pos > -1 && util.matchGloss(util.getWikitextGloss(text, 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, util.getWikitextGloss(text, pos))) { transect.push(pos); } } if (transect.length > 1 && !recursive) transect = util.tieBreakTransTable(text, transect, node); } if (transect.length == 1) { pos = transect[0]; pos = util.getVanillaIndexOf("\n", text, pos) + 1; var endpos = text.indexOf('{{trans-bottom}}', pos); if (endpos > -1 && pos > 0) return [pos, endpos]; } return false; }, // try to narrow down the correct poss if multiple matching trans tables tieBreakTransTable: function (text, poss, node) { if (node.nodeName.toLowerCase() == 'div') { while (node && !(node.className && node.className.indexOf('NavFrame') > -1)) node = node.parentNode; var nodes = node.getElementsByTagName('table'); if (!nodes.length) return poss; node = nodes[0]; } else { while (node && node.nodeName.toLowerCase() != 'table') node = node.parentNode; } var before_count = 0; var after_count = 0; var is_found = false; $("table.translations").each(function () { var gloss = util.getTransGloss(this); if (gloss == "Translations to be checked") return; if (this == node) { is_found = true; return; } var pos = util.getTransTable(text, this, true); if (pos) { for (var j = 0; j < poss.length; j++) { if (poss[j] == pos) return util.tieBreakTransTable(poss.splice(j, 1), node); } } else { var matched = 0; for (var j = 0; j < poss.length; j++) { if (util.matchGloss(util.getWikitextGloss(text, poss[j]), gloss) && util.matchGloss(gloss, util.getWikitextGloss(text, poss[j]))) { matched++; } } if (matched == poss.length) { if (is_found) after_count++; else before_count++; } } }); if (before_count + 1 + after_count == poss.length) return [poss[before_count]]; else return poss; }, matchGloss: function (line, gloss) { if (gloss.match(/^ *$/)) return !!(line.match(/\{\{trans-top\| *\}\}/) || line.match(/^ *$/)); var words = gloss.split(/\W+/); 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) || children[i].className.indexOf('wt-edit-recurse') > -1) 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); }, genderList: { "s": "singular", "d": "dual", "p": "plural", "m": "masc.", "m-d": "masc. dual", "m-p": "masc. pl.", "f": "fem.", "f-d": "fem. dual", "f-p": "fem. pl.", "c": "common", "c-d": "common dual", "c-p": "common pl.", "n": "neuter", "n-d": "neuter dual", "n-p": "neuter pl.", "impf": "imperfective", "pf": "perfective" } }; // An adder for translations on en.wikt function TranslationAdders(editor) { function TranslationLabeller(insertDiv) { var original_span; var adder_form; var initial_value; var edit_button; var editing = false; var adderInterface = { 'fields': { 'gloss': function (txt, error) { return util.validateNoWikisyntax('gloss', true)(txt, error); } }, 'createForm': function () { var thisId = "a" + String(Math.random()).replace(".", ""); return adder_form = newNode('form', { style: 'display: inline', width: 'auto', click: kill_event }, newNode('label', { 'for': thisId }, "Gloss: "), newNode('input', { type: 'text', name: 'gloss', value: initial_value, style: 'width: 50%', title: 'Insert a summary of the relevant definition', id: thisId }), newNode('input', { type: 'submit', name: 'preview', value: 'Preview' }), newNode('a', { href: '/wiki/Help:Glosses' }, 'Help?!') ); }, 'onsubmit': function (values, render) { render(values.gloss, function (new_html) { if (editing) toggle_editing(false); var old_html = original_span.innerHTML; editor.addEdit({ 'undo': function () { original_span.innerHTML = old_html; if (!editing) toggle_editing(); }, 'redo': function () { original_span.innerHTML = new_html; if (editing) toggle_editing(); }, 'edit': function (text) { return perform_edit(text, values.gloss); }, 'summary': 'tgloss:"' + (values.gloss.length > 50 ? values.gloss.substr(0, 50) + '...' : values.gloss + '"') }, original_span); }); } }; // The actual modification to the wikitext function perform_edit(wikitext, gloss) { var pos = util.getTransTable(wikitext, insertDiv)[0] - 4; var g_start = wikitext.lastIndexOf('\n{{trans-top', pos) + 1; var g_end = wikitext.indexOf('}}\n', pos) + 2; if (g_start === 0 || wikitext.substr(g_start, g_end - g_start).indexOf("\n") > -1) { editor.error("Could not find translation table."); return wikitext; } else { return wikitext.substr(0, g_start) + '{{trans-top|' + gloss + '}}' + wikitext.substr(g_end); } } // Don't open and close box when interacting with form. function kill_event(e) { if (e && e.stopPropagation) e.stopPropagation(); else window.event.cancelBubble = true; } // What to do when the +/- button is clicked. function toggle_editing() { if (editing) { adder_form.style.display = "none"; original_span.style.display = "inline"; editing = false; return; } editing = true; edit_button.text("Loading..."); editor.withCurrentText(function (currentText) { var pos = util.getTransTable(currentText, insertDiv); edit_button.text('±'); if (!pos) return editor.error("Could not find translation table"); var gloss_line = currentText.substr(currentText.lastIndexOf('\n', pos[0] - 2) + 1); gloss_line = gloss_line.substr(0, gloss_line.indexOf('\n')); initial_value = gloss_line.replace(/^\{\{trans-top(\|(.*)|)\}\}\s*$/, "$2"); if (initial_value.indexOf("\n") > 0) return editor.error("Internal error: guess spanning multiple lines"); if (!original_span) { original_span = newNode('span', { 'class': 'wt-edit-recurse' }); for (var i = 0; i < insertDiv.childNodes.length; i++) { var child = insertDiv.childNodes[i]; if (child != edit_button[0] && (!child.className || child.className != 'NavToggle')) { original_span.appendChild(insertDiv.removeChild(child)); i--; } } insertDiv.appendChild(original_span); new AdderWrapper(editor, adderInterface, insertDiv, original_span); } original_span.style.display = "none"; adder_form.style.display = "inline"; adder_form.getElementsByTagName('input')[0].focus(); }); } edit_button = $('<a href="#">±</a>') //.addClass("translation-gloss-edit-button") .attr("title", "Edit table heading").css("padding", "2px").css("margin-left", "-5px") .on("click", function (e) { if (e && e.preventDefault) e.preventDefault(); kill_event(e); toggle_editing(); return false; }); $(insertDiv).prepend(edit_button); //XXX: this places anchor before NavToggle which may not be a good idea } function TranslationAdder(insertUl) { // Hippietrail var langmetadata = new LangMetadata(); this.fields = { lang: function (txt, error) { if (txt == 'en') return error("Please choose a foreign language. (fr, es, aaa)"); if (txt == 'nds') return error("Please use the code nds-de for German Low German or nds-nl for Dutch Low Saxon"); if (/^[a-z]{2,3}(-[a-z\-]{1,7})?$/.test(txt)) return txt; return error("Please use a language code. (fr, es, aaa)"); }, word: function (txt, error) { if (txt == '{{trreq}}') return '{{t-needed}}'; if (txt == '{{t-needed}}') return txt; if (txt.indexOf(',') == -1 || forceComma) { forceComma = false; if (langmetadata.expectedCase(thiz.elements.lang.value, mw.config.get('wgTitle'), txt) || forceCase) { forceCase = false; return util.validateNoWikisyntax('translation', true)(txt, error); } if (prefs.get('case-knowledge', 'none') == 'none') { return error(newNode('span', "Translations normally don't have capital letters. If you're certain it does, you can ", newNode('span', { style: "color: blue; text-decoration: underline; cursor: pointer;", click: function () { forceCase = true; inputForm.onsubmit(); prefs.set('case-knowledge', 'guru'); } }, "continue by clicking here."))); } else { var msg = newNode('span', newNode('span', { style: "color: blue; text-decoration: underline; cursor: pointer;", click: function () { prefs.set('case-knowledge', 'none'); try { msg.parentNode.removeChild(msg); } catch (e) { } editor.undo(); } }, "Please click undo"), " unless you are certain that this translation has a capital letter."); error(msg); return txt; } } if (prefs.get('comma-knowledge', 'none') == 'none') { return error(newNode('span', "You can only add one translation at a time. If this is one translation that contains a comma, you can ", newNode('span', { style: "color: blue; text-decoration: underline; cursor: pointer;", click: function () { forceComma = true; inputForm.onsubmit(); prefs.set('comma-knowledge', 'guru'); } }, "add it by clicking here."))); } else { var msg = newNode('span', newNode('span', { style: "color: blue; text-decoration: underline; cursor: pointer;", click: function () { prefs.set('comma-knowledge', 'none'); try { msg.parentNode.removeChild(msg); } catch (e) { } editor.undo(); } }, "Please click undo"), " if you were trying to create a list of translations in one go, this is currently not supported."); error(msg); return txt; } }, qual: util.validateNoWikisyntax('qualifier'), tr: util.validateNoWikisyntax('transcription'), rawPageName: util.validateNoWikisyntax('raw page name'), sc: function (txt, error) { if (txt && !/^((?:[a-z][a-z][a-z]?-)?[A-Z][a-z][a-z][a-z]|polytonic|unicode)$/.test(txt)) return error(newNode('span', "Please use a ", newNode('a', { href: '/wiki/Wiktionary:List_of_scripts' }, "valid script code"), "(e.g. fa-Arab, Deva, polytonic)")); var scripts = (new ScriptUtils()).GetScriptsByLangCode(thiz.elements.lang.value); if (txt && scripts.length > 0 && scripts.indexOf(txt) == -1) return error(newNode('span', "Please use a valid script code. Available script codes for this language are: " + scripts.join(","))); if (!txt) txt = prefs.get('script-' + thiz.elements.lang.value, langmetadata.guessScript(thiz.elements.lang.value) || ''); if (txt == 'Latn') txt = ''; return txt; }, nested: util.validateNoWikisyntax('nested'), "s": 'checkbox', "d": 'checkbox', "p": 'checkbox', "m": 'checkbox', "m-d": 'checkbox', "m-p": 'checkbox', "f": 'checkbox', "f-d": 'checkbox', "f-p": 'checkbox', "c": 'checkbox', "c-d": 'checkbox', "c-p": 'checkbox', "n": 'checkbox', "n-d": 'checkbox', "n-p": 'checkbox', "impf": 'checkbox', "pf": 'checkbox', nclass1: util.validateNoWikisyntax('noun class'), nclass2: util.validateNoWikisyntax('plural class') }; this.createForm = function () { function createGenderNode(name, text) { var inp = document.createElement("input"); inp.type = "checkbox"; inp.name = name; var lbl = document.createElement("label"); lbl.appendChild(inp); lbl.appendChild(document.createTextNode(text)); return lbl; } var genderControls = {}; for (var g in util.genderList) genderControls[g] = createGenderNode(g, util.genderList[g]); 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', "Raw page name: ", newNode('input', { name: 'rawPageName', title: "The word without all of the dictionary-only diacritics." }), " (e.g. amo for amō)"), script: newNode('p', newNode('a', { href: '/wiki/Wiktionary:List_of_scripts' }, "Script code"), ": ", newNode('input', { name: 'sc', size: 6, title: "The script code to apply to this word." }), "(e.g. Cyrl for Cyrillic, Latn for Latin)", newNode('br')), nested: newNode('p', "Nesting: ", newNode('input', { name: 'nested', title: "The nesting of this language" }), " (e.g. Norwegian/Nynorsk)"), // Genders genders: genderControls, // Noun class nclass: newNode('p', "Noun class: ", newNode('input', { type: 'text', size: 4, name: 'nclass1', title: "The noun class of the word in the singular or citation form." }), " Plural class: ", newNode('input', { type: 'text', size: 4, name: 'nclass2', title: "The noun class of the word in the plural form, if any." })) }; function createGenderDiv(genderz) { var $div = $("<div>"); for (var i = 1; i < arguments.length; i++) $div.append(genderz[arguments[i]]); return $div; } var $mdiv = createGenderDiv(controls.genders, "m", "m-d", "m-p"); var $fdiv = createGenderDiv(controls.genders, "f", "f-d", "f-p"); var $cdiv = createGenderDiv(controls.genders, "c", "c-d", "c-p"); var $ndiv = createGenderDiv(controls.genders, "n", "n-d", "n-p"); var $sdpdiv = createGenderDiv(controls.genders, "s", "d", "p"); var $pfdiv = createGenderDiv(controls.genders, "impf", "pf"); controls.gender = $("<p>").append($mdiv).append($fdiv).append($cdiv).append($ndiv).append($sdpdiv).append($pfdiv)[0]; 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() { var rawPageName = langmetadata.computeRawPageName(thiz.elements.lang.value, thiz.elements.word.value); if (rawPageName && rawPageName !== thiz.elements.word.value) thiz.elements.rawPageName.value = rawPageName; } 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 = langmetadata.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 = ''; thiz.elements.nested.value = langmetadata.getNested(langInput.value || ''); autoTransliterate(); } var lang = langInput.value; if (!advancedMode) { var g = langmetadata.getGenders(lang); if (!lang) { hide(controls.gender); } else if (g === undefined) { hide(controls.gender); } else { for (var genderName in util.genderList) { toggle(g.indexOf(genderName) != -1, controls.genders[genderName]); } } toggle(g, controls.gender); toggle(langmetadata.hasNounClasses(lang), controls.nclass); var hasAutomaticTransliteration = new window.LanguageUtils().HasAutomaticTransliteration(lang); toggle(guess && guess != 'Latn' && !hasAutomaticTransliteration, controls.transliteration); toggle(langmetadata.needsRawPageName(lang), controls.display); hide(controls.qualifier, controls.nested); //only in more //should be hidden if the language has only one script toggle(langmetadata.getScripts(lang).length != 1, controls.script); } else { show( controls.gender, controls.genders['s'], controls.genders['d'], controls.genders['p'], controls.genders['m'], controls.genders['m-d'], controls.genders['m-p'], controls.genders['f'], controls.genders['f-d'], controls.genders['f-p'], controls.genders['c'], controls.genders['c-d'], controls.genders['c-p'], controls.genders['n'], controls.genders['n-d'], controls.genders['n-p'], controls.genders['impf'], controls.genders['pf'], controls.nclass, controls.transliteration, controls.qualifier, controls.display, controls.script, controls.nested); } } //autocomplete language names function langAutoFill(e) { e = (e || event).keyCode; if ((e >= 33 && e <= 40) || e == 8 || e == 46 || e == 27 || e == 16) { return; } var t = this, langPrefix = t.value; if (langPrefix.substr(0, 1) != langPrefix.substr(0, 1).toUpperCase()) { return; } new mw.Api().get({ "action": "expandtemplates", "format": "json", "text": "{{#invoke:languages/javascript-interface|GetSingleLanguageByLangaugePrefix|" + langPrefix + "}}", "prop": "wikitext" }).done(function (r) { if (r.expandtemplates && r.expandtemplates.wikitext !== "") { var langcode = r.expandtemplates.wikitext.split(":")[0]; var langname = r.expandtemplates.wikitext.split(":")[1]; var oldLength = t.value.length; t.value = langname; $(t).data("langcode", langcode); if (t.setSelectionRange) { t.setSelectionRange(oldLength, langname.length); } else if (t.createTextRange) { var z = t.createTextRange(); z.moveEnd('character', 0 - z.move('character', [t.value.length, t.value = langname][0]) + t.value.length); z.select(); } } else { $(t).removeData("langcode"); } }); } langInput.onkeyup = langAutoFill; langInput.onblur = function () { if ($(this).data("langcode")) $(this).val($(this).data("langcode")); updateScriptGuess.call(langInput); }; window.setTimeout(function () { updateScriptGuess.call(langInput); }, 0); inputForm = newNode('form', newNode('p', newNode('a', { href: "/wiki/User_talk:Conrad.Irwin/editor.js#Usage" }, "Add translation"), ' ', langInput, newNode('b', ': '), newNode('input', { 'name': 'word', size: 20, keyup: autoTransliterate, change: autoTransliterate }), newNode('input', { 'type': 'submit', 'value': 'Preview translation' }), showButton ), controls.gender, controls.nclass, controls.transliteration, controls.display, controls.qualifier, controls.script, controls.nested ); return inputForm; }; this.onsubmit = function (values, render) { var wikitext; function callRender() { render(wikitext, function (html) { registerEdits(values, wikitext, html); }); } if (values.word.indexOf('{{t-needed') === 0) { wikitext = '{{subst:#invoke:languages/templates|getByCode|' + values.lang + '|getCanonicalName}}: {{t-needed|' + values.lang + '}}'; callRender(); } else { langmetadata.retrieveRawPageName(values.lang, values.word, values.rawPageName, function (rawPageName, needsRawPageName) { if (needsRawPageName) { values.rawPageName = rawPageName; values.wordMinus = ''; } else { values.rawPageName = ''; values.wordMinus = rawPageName; } wikitext = '{{subst:#invoke:languages/templates|getByCode|' + values.lang + '|getCanonicalName}}: ' + '{{t|' + values.lang + '|' + (values.rawPageName || values.word) + (values.nclass1 ? '|c' + values.nclass1 : '') + (values.nclass2 ? '|c' + values.nclass2 : ''); // Add gender codes wikitext += (values['s'] ? '' : '') + (values['d'] ? '|d' : '') + (values['p'] ? '|p' : '') + (values['m'] ? '|m' : '') + (values['m-d'] ? '|m-d' : '') + (values['m-p'] ? '|m-p' : '') + (values['f'] ? '|f' : '') + (values['f-d'] ? '|f-d' : '') + (values['f-p'] ? '|f-p' : '') + (values['c'] ? '|c' : '') + (values['c-d'] ? '|c-d' : '') + (values['c-p'] ? '|c-p' : '') + (values['n'] ? '|n' : '') + (values['n-d'] ? '|n-d' : '') + (values['n-p'] ? '|n-p' : '') + (values['impf'] ? '|impf' : '') + (values['pf'] ? '|pf' : ''); wikitext += (values.tr ? '|tr=' + values.tr : '') + (values.rawPageName ? '|alt=' + values.word : '') + /* (values.sc ? '|sc=' + values.sc  : '') + */ '}}' + (values.qual ? ' {{qualifier|' + values.qual + '}}' : ''); langmetadata.hasWiktionaryWithEntry(values.lang, values.rawPageName || values.wordMinus, function (result) { if (result) wikitext = wikitext.replace(/\{t\|/, '{t+|'); callRender(); }); }); } if (!this.balancer) this.balancer = new TranslationBalancer(editor, insertUl.parentNode.parentNode.parentNode); }; var thiz = this; var prefs = new CookiePreferences('EditorJs'); var langInput; var inputForm; var advancedMode = prefs.get('more-display', 'none') != 'none'; var forceComma = false; var forceCase = false; //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.nclass1.value = thiz.elements.nclass2.value = thiz.elements.tr.value = thiz.elements.rawPageName.value = thiz.elements.qual.value = ''; thiz.elements['s'].checked = false; thiz.elements['d'].checked = false; thiz.elements['p'].checked = false; thiz.elements['m'].checked = false; thiz.elements['m-d'].checked = false; thiz.elements['m-p'].checked = false; thiz.elements['f'].checked = false; thiz.elements['f-d'].checked = false; thiz.elements['f-p'].checked = false; thiz.elements['c'].checked = false; thiz.elements['c-d'].checked = false; thiz.elements['c-p'].checked = false; thiz.elements['n'].checked = false; thiz.elements['n-d'].checked = false; thiz.elements['n-p'].checked = false; thiz.elements['impf'].checked = false; thiz.elements['pf'].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); // Uncaught TypeError: Object #<HTMLInputElement> has no method 'update' 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', { 'class': 'trans-' + values.lang }); li.innerHTML = content; var lang = getLangName(li); var summary = 't+' + values.lang + ':[[' + (values.rawPageName || values.wordMinus || values.word) + ']]'; var insertBefore = null; var nextLanguage = null; var nestedHeading, nestedLang; var nestedLang; if (values.nested.indexOf('/') > -1) { nestedLang = values.nested.replace(/.*\//, ''); nestedHeading = values.nested.replace(/\/.*/, ''); if (nestedHeading === '') nestedHeading = lang; content = content.replace(/.*: /, nestedLang + ": "); wikitext = wikitext.replace("subst:", "").replace(/.*: /, nestedLang + ": "); } else { nestedHeading = values.nested; nestedLang = lang; } var nestedWikitext = "\n* " + nestedHeading + ":\n*: " + wikitext; function addEdit(edit, span) { editor.addEdit({ 'undo': function () { edit.undo(); if (thiz.elements.word.value === "" && thiz.elements.nclass1.value === "" && thiz.elements.nclass2.value === "" && thiz.elements.tr.value === "" && thiz.elements.rawPageName.value === "" && thiz.elements.qual.value === "") { var fields = ["lang", "word", "nclass1", "nclass2", "rawPageName", "qual", "tr", "sc"]; for (var i = 0; i < fields.length; i++) { thiz.elements[fields[i]].value = values[fields[i]]; } for (var genderName in util.genderList) { thiz.elements[genderName].checked = values[genderName]; } } }, 'redo': function () { edit.redo(); var fields = ["lang", "word", "nclass1", "nclass2", "rawPageName", "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 lss = $(insertUl).parent().parent().find('li').get(); var dds = $(insertUl).parent().parent().find('dd').get(); var lis = lss.concat(dds); for (var j = 0; j < lis.length; j++) { if (lis[j].getElementsByTagName('form').length > 0) continue; var ln = getLangName(lis[j]); if (ln == lang) { if (values.word == '{{t-needed}}') { addEdit({ 'redo': function () { }, 'undo': function () { }, 'edit': function () { return editor.error("Can not add a translation request for a language with translations"); } }); return resetElements(); } var span = newNode('span'); var parent = lis[j]; if (util.isTrreq(parent)) { span.innerHTML = content.substr(content.indexOf(':') + 1); 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); return resetElements(); } 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); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + "," + wt + 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') { // If we want to use the dialectical nesting for orthographical nesting // then we need to skip this (otherwise perfect) match. if (!hastrans && nestedHeading == ln) { node = node.nextSibling; continue; } 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); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + (hastrans ? "," : "") + wt + text.substr(lineend); }) }, span); return resetElements(); } else { hastrans = true; } } node = node.nextSibling; } } } } 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; li.innerHTML = nestedHeading + ":" + "<dl><dd class=\"trans-" + values.lang + "\">" + content + "</dd></dl>"; 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() != 'td') continue; var ln = getLangName(lis[j]); if (ln == nestedHeading) { 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', { 'class': 'trans-' + values.lang }); var dl = newNode('dl', dd); dd.innerHTML = content; addEdit({ 'redo': function () { parent.appendChild(dl); }, 'undo': function () { parent.removeChild(dl); }, 'edit': getEditFunction(values, wikitext, nestedHeading, getLangCode(parent), 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); return resetElements(); } else { var dd = newNode(sublis[0].nodeName, { 'class': 'trans-' + values.lang }); var linestart = dd.nodeName.toLowerCase() == 'dd' ? '\n*: ' : '\n** '; dd.innerHTML = content; for (var k = 0; k < sublis.length; k++) { var subln = getLangName(sublis[k]); var parent = sublis[k]; if (subln == nestedLang) { var span = newNode('span'); span.innerHTML = ", " + content.substr(content.indexOf(':') + 1); addEdit({ 'redo': function () { parent.appendChild(span) }, 'undo': function () { parent.removeChild(span) }, 'edit': getEditFunction(values, wikitext, nestedLang, values.lang, false, function (text, ipos) { // Adding the wikitext to a list of translations that already exists. var lineend = text.indexOf('\n', ipos); var wt = wikitext.replace('subst:#invoke:', ''); wt = wt.substr(wt.indexOf(':') + 1); return text.substr(0, lineend) + "," + wt + text.substr(lineend); }) }, span); return resetElements(); } else if (langmetadata.nestsBefore(nestedLang, subln)) { addEdit({ 'redo': function () { parent.parentNode.insertBefore(dd, parent); }, 'undo': function () { parent.parentNode.removeChild(dd); }, 'edit': getEditFunction(values, wikitext, subln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { // Adding a nested translation in-order var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + linestart + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } } addEdit({ 'redo': function () { parent.parentNode.appendChild(dd); }, 'undo': function () { parent.parentNode.removeChild(dd); }, 'edit': getEditFunction(values, wikitext, subln, getLangCode(parent), util.isTrreq(parent), function (text, ipos) { // Adding a nested translation at the end of its group var lineend = text.indexOf('\n', ipos); return text.substr(0, lineend) + linestart + wikitext + text.substr(lineend); }) }, dd); return resetElements(); } } else if (ln && ln > nestedHeading && (!nextLanguage || ln < nextLanguage)) { 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 nested translation section. var lineend = text.lastIndexOf('\n', ipos); return text.substr(0, lineend) + nestedWikitext + text.substr(lineend); }) }, li]; } } wikitext = nestedHeading + ":\n*: " + wikitext; } li.className = "trans-" + values.lang; 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, insertUl); if (!p) return editor.error("Could not find translation table for '" + values.lang + ":" + values.word + "'. Glosses should be unique"); var stapos = p[0]; var endpos = p[1]; var trreqLegacy = false; if (findLanguage) { var ipos = 0; if (trreq) { ipos = text.substr(stapos).search(RegExp(mw.RegExp.escape(findLanguage) + ":\\s*\\{\\{t-needed(?:\\|" + findLangCode + "}})?")) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{trreq|' + findLanguage + '}}', stapos); if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{trreq|' + findLangCode + '}}', stapos); } // If we have a nested trreq, then we still need to look for the non-trreq form of the heading language if (!trreq || ipos < stapos || ipos > endpos) { var escapedLang = mw.RegExp.escape(findLanguage); //if the translation should not be nested it should not go before any nested language var regexByShouldFindSubLanguage = values.nested != "" ? "[:*]?" : ""; var possibleRegexes = [ RegExp("\\*" + regexByShouldFindSubLanguage + " ?\\[\\[" + escapedLang + "\\]\\]:"), RegExp("\\*" + regexByShouldFindSubLanguage + " ?" + escapedLang + ":"), RegExp("\\*" + regexByShouldFindSubLanguage + " ?\\{\\{ttbc\\|" + escapedLang + "}}:") ]; ipos = text.substr(stapos).search(possibleRegexes[0]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(possibleRegexes[1]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.substr(stapos).search(possibleRegexes[2]) + stapos; if (ipos < stapos || ipos > endpos) ipos = text.indexOf('{{subst:#invoke:languages/templates|getByCode|' + findLangCode + '|getCanonicalName}}:', 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); }; } // 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.replace(/^[\s\n]*/, ''); } // Try to get the language code from an <li> containing { {t t+ or t- // }} function getLangCode(li) { if (li.className.indexOf('trans-') == 0) return li.className.substr(6); var spans = li.getElementsByTagName('span'); for (var i = 0; i < spans.length; i++) { if (spans[i].lang) { return spans[i].lang; } if (spans[i].dataset && spans[i].dataset.lang) { return spans[i].dataset.lang; } } return false; } } function createTranslationAdderRow(li) { var $ul = $("<ul>").append(li); return $("<tr>") .append($("<td>")) .append($("<td>")) .append($("<td>").css("text-align", "left").append($ul)); } $('table.translations').each(function () { if (util.getTransGloss(this) != 'Translations to be checked') { var uls = $(this).find("td > ul").get(); if (uls.length == 0) { this.getElementsByTagName('td')[0].appendChild(newNode('ul')); uls = this.getElementsByTagName('ul'); } if (uls.length == 1) { var td = this.getElementsByTagName('td')[2]; if (td) { td.appendChild(newNode('ul')); uls = this.getElementsByTagName('ul'); } } if (uls) { var li = document.createElement('li'); var ul = uls[uls.length - 1]; $(this).append(createTranslationAdderRow(li)); new AdderWrapper(editor, new TranslationAdder(ul), li); if (true) {// XXX: why not? (new CookiePreferences('EditorJs')).get('labeller') == 'true') { var div = $(this).parent().parent().find('div.NavHead')[0]; if (div) { new TranslationLabeller(div) } } } } }); } function TranslationBalancer(editor, insertTable) { var status; //create the form function init() { var cns = insertTable.getElementsByTagName('tr')[0].childNodes; var tds = []; //Find all three table cells in the translation table. for (var i = 0; i < cns.length; i++) { if (cns[i].nodeName.toUpperCase() == 'TD') tds.push(cns[i]) } //Ensure that there is a <ul> on the left side of the balancer. var left = tds[0].getElementsByTagName('ul'); if (left.length > 0) left = left[0]; else { left = newNode('ul'); tds[0].appendChild(left); } //Ensure that there is a <ul> on the right side of the balancer. var right = tds[2].getElementsByTagName('ul'); if (right.length > 0) right = right[0]; else { right = newNode('ul'); tds[2].appendChild(right); } var moveLeft = newNode('input', { 'type': 'submit', 'name': 'ml', 'value': '←', 'click': function () { return prepareEdits('←', left, right) } }); var moveRight = newNode('input', { 'type': 'submit', 'name': 'mr', 'value': '→', 'click': function () { return prepareEdits('→', left, right) } }); status = newNode('span'); var form = newNode('form', moveLeft, newNode('br'), moveRight, newNode('br'), status); tds[1].appendChild(form); form.onsubmit = function () { return false; } //Must be done after the appendChild for IE :( } function moveOneRight(left, right) { var li = left.lastChild; while (li && li.nodeName.toLowerCase() != 'li') li = li.previousSibling; if (li) right.insertBefore(left.removeChild(li), right.firstChild); } function moveOneLeft(left, right) { var li = right.firstChild; while (li && li.nodeName.toLowerCase() != 'li') li = li.nextSibling; if (li) left.appendChild(right.removeChild(li)); } //store the edit object with the editor function prepareEdits(direction, left, right) { status.innerHTML = "Loading..."; editor.addEdit({ 'redo': function () { (direction == '→' ? moveOneRight : moveOneLeft)(left, right) }, 'undo': function () { (direction == '→' ? moveOneLeft : moveOneRight)(left, right) }, 'edit': function (text) { return editWikitext(right, direction, text); }, 'summary': 't-balance' }); } //get the wikitext modification function editWikitext(insertUl, direction, text) { status.innerHTML = ""; //Find the position of the translation table var p = util.getTransTable(text, insertUl); if (!p) return editor.error("Could not find translation table, please improve glosses."); var stapos = p[0]; var endpos = p[1]; //Find the start and end of the { {trans-mid}} in the table var midpos = text.indexOf('{{trans-mid}}', stapos); var midstart = text.lastIndexOf("\n", midpos); var midend = text.indexOf("\n", midpos); if (midstart < stapos - 1 || midend > endpos) return editor.error("Could not find {{trans-mid}}, please correct page."); if (direction == '→') { // Select the last list item of the left list (may be more than one line if nested translations are present) var linestart = text.lastIndexOf("\n", midstart - 3); while (/^[:*#;]$/.test(text.substr(linestart + 2, 1))) linestart = text.lastIndexOf("\n", linestart - 1); if (linestart < stapos - 1 || linestart >= endpos) return editor.error("No translations to move"); return text.substr(0, linestart) //Everything before the item we are moving + text.substr(midstart, midend - midstart) //Then { {trans-mid}} + text.substr(linestart, midstart - linestart) //Then the item we are moving + text.substr(midend); //Then everything after { {trans-mid}} } else if (direction == '←') { // Select the first list item of the right list (may be more than one line if nested translations are present) var lineend = text.indexOf("\n", midend + 3); while (/^[:*#;]$/.test(text.substr(lineend + 2, 1))) lineend = text.indexOf("\n", lineend + 1); if (lineend < stapos - 1 || lineend >= endpos) return editor.error("No translations to move"); return text.substr(0, midstart) //Everything before { {trans-mid}} + text.substr(midend, lineend - midend) //Then the item we are moving + text.substr(midstart, midend - midstart) //Then { {trans-mid}} + text.substr(lineend); //Then everything after the item we are moving } return text; } init(); } $(function () { // Check if we are on a sensible page var actions = window.location.toString().replace(/.*\?/, '&'); var isOnPrintable = mw.util.getParamValue("printable") !== null; var isDiff = mw.util.getParamValue("diff") !== null || mw.util.getParamValue("oldid") !== null; if (mw.config.get('wgAction') != 'view' || isOnPrintable || isDiff) return; var editor = new Editor(); TranslationAdders(editor); /* // Check that we have not been disabled var prefs = new CookiePreferences('EditorJs'); if (prefs.get('enabled', 'true') == 'true') { if (!window.loadedEditor) { prefs.setDefault('labeller', mw.config.get('wgUserName') ? 'true' : 'false'); window.loadedEditor = true; } } // 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); } var node = document.getElementById("editor-js-labeller-button"); if (node) { node.innerHTML = ""; var toggle2 = newNode('span', { click: function() { if (prefs.get('labeller') == 'true') { toggle2.innerHTML = "Enable"; prefs.set('labeller', 'false'); } else { toggle2.innerHTML = "Disable"; prefs.set('labeller', 'true'); } } }, (prefs.get('labeller') == 'true' ? 'Disable' : 'Enable')) node.appendChild(toggle2); }*/ }); //