אונטערשייד צווישן ווערסיעס פון "מעדיעוויקי:Gadget-TemplateParamWizard.js"
קפיצה לניווט
קפיצה לחיפוש
(לאז פלאץ פאר "1=") |
אין תקציר עריכה |
||
שורה 2: | שורה 2: | ||
//Written by [[User:קיפודנחש]] | //Written by [[User:קיפודנחש]] | ||
"use strict"; | "use strict"; | ||
if(!$( '#wpTextbox1' ).prop( 'readonly' ) ) | if (!$('#wpTextbox1').prop('readonly')) | ||
$(function($) { | $(function ($) { | ||
// template parameter is an object with the following fields: | |||
// desc: desciption string | |||
// defval: default value (optional) | |||
// options: object with optional fields: | |||
//// multiline: number of lines | |||
//// depends: another field's name | |||
//// required: boolean | |||
//// date: use JS date widget | |||
//// choices: array of legal values for the field | |||
//// extended: this field will not show on initial screen, and will appear once the user selects "show all fields" | |||
var | |||
// templateParams is keyed by paramName. | |||
templateParams, | |||
paramsOrder, | |||
// which template are we working on | |||
template, | |||
// array of pairs - [paramName, inputField] | |||
dialogFields, | |||
// table rows keyed by paramName | |||
rowsBypName, | |||
// the fields, keyed by paramName | |||
fieldsBypName, | |||
// boolean, indicating the source of data is templatedata. | |||
tdTemplate, | |||
// boolean, indicating the source of the data is analyzing the template page itself. | |||
rawTemplate, | |||
isInline, | |||
rtl = $('body').is('.rtl'), | |||
// test to see if a string contains wikiCode and hence needs parsing, or cen be used as is. | |||
wikiCodeFinder = /[\[\]\{\}<>]/, | |||
globalExplanation = '', | |||
extendedParamCssRule, | |||
anyExtended = false, | |||
localStorageKey = 'templateParamWizard', | |||
emptiesKey = 'writeEmpties', | |||
oneLineTemplate = 'oneLineTemplate', | |||
allAliases = []; | |||
function addParam(name) { | |||
if ($.inArray(name, paramsOrder) == -1) | |||
paramsOrder.push(name); | |||
} | |||
function paramsFromSelection() { | |||
var selection = $("#wpTextbox1").textSelection('getSelection').replace(/^\s*\{\{|\}\}\s*$/g, ''); //scrap the first {{ and last }} | |||
var specials = [], | |||
match; | |||
while (true) { //extract inner links, inner templates and inner params - we don't want to split those. | |||
match = selection.match(/(\{\{[^\{\}\]\[]*\}\}|\[\[[^\{\}\]\[]*\]\]|\[[^\{\}\]\[]*\])/); | |||
if (!match || !match.length) | |||
break; | |||
specials.push(match[0]); | |||
selection = selection.replace(match[0], "\0" + specials.length + "\0"); | |||
} | |||
var params = selection.split(/ *\| */); | |||
params.shift(); // remove the template name | |||
var ordered = 0; | |||
for (var i in params) { | |||
var param = params[i]; | |||
if (! /=/.test(param)) { | |||
param = ++ordered + '=' + param; | |||
} | |||
var paramPair = param.split("="); | |||
var name = $.trim(paramPair.shift()); | |||
if (!isNaN(name)) { | |||
ordered = parseInt(name); // this still won't work as advertise when template contains explicit parameter 2 before implicit 1: {{x | 2 = hey | ho }} | |||
} | |||
var val = paramPair.join('='); | |||
while (true) { | |||
match = val.match(/\0(\d+)\0/); | |||
if (!match || !match.length) | |||
break; | |||
val = val.replace(match[0], specials[parseInt(match[1], 10) - 1]); | |||
} | |||
if (name && paramPair.length) { | |||
var tp = templateParams[name] = | |||
templateParams[name] || | |||
~allAliases.indexOf(name) && { param: {}, options: { isAlias: 1 } } || | |||
{ param: {}, options: { notInParamPage: 1 } }; | |||
addParam(name); | |||
$.extend(tp.options, { defval: val }); | |||
if (/\n/.test(val)) $.extend(tp.options, { multiline: 5 }); | |||
// next line is for the case where there are "choices"' but current value is not one of them: add it as a new choice. | |||
if (typeof tp.options.choices === 'string' && tp.options.choices.indexOf(val) < 0) | |||
tp.options.choices += (', ' + val); | |||
} | |||
} | |||
} | |||
function buildParamsRaw(data) { | |||
var | |||
paramExtractor = /{{3,}(.*?)[<|}]/mg, | |||
m; | |||
while (m = paramExtractor.exec(data)) { | |||
var paramName = $.trim(m[1]); | |||
templateParams[paramName] = { desc: '', options: { multiline: 5 }, label: paramName, param: {} }; | |||
addParam(paramName); | |||
} | |||
} | |||
function buildParamsTd(data) { | |||
var params = data.params, | |||
paramOrder = data.paramOrder; | |||
function optionsOfParam(param) { | |||
var options = {}; | |||
if (param.required) options.required = true; | |||
if (param.suggestedvalues && param.suggestedvalues.length) options.choices = param.suggestedvalues.join(','); | |||
return options; | |||
} | |||
function onemore(name) { | |||
var param = params[name]; | |||
if (param.deprecated) | |||
return; // ignore deprecated parameters - pretend they are not in TD. | |||
templateParams[name] = { | |||
desc: param.description || '', | |||
options: optionsOfParam(param), | |||
label: param.label || name, | |||
param: param | |||
}; | |||
if (param.aliases) $.merge(allAliases, param.aliases); // collect alliases if there are any | |||
addParam(name); | |||
} | |||
isInline = data.format === 'inline'; | |||
if (paramOrder && paramOrder.length) | |||
for (var ind in paramOrder) | |||
onemore(paramOrder[ind]); | |||
else // no order - take them as they come. | |||
for (var paramname in params) | |||
onemore(paramname); | |||
// derive placeholders for feilds derived from wikidata | |||
if (data.maps && data.maps.hasOwnProperty('wikidata') && mw.config.get('wgWikibaseItemId')) { | |||
var wikidataFormattedValues = $('<div>'); | |||
for (var k in data.maps['wikidata']) { | |||
wikidataFormattedValues.append($('<span>', { id: k, text: '{{#property:' + k + '}}' })) | |||
} | |||
$.post( | |||
mw.util.wikiScript('api'), | |||
{ action: 'parse', text: wikidataFormattedValues.html(), disablelimitreport: 1, format: 'json', prop: 'text', title: mw.config.get('wgPageName') }, | |||
function (wbd) { | |||
if (!wbd || !wbd.parse || !wbd.parse.text) return; | |||
for (var k in data.maps['wikidata']) { | |||
var wikidataVal = $('#' + k, wbd.parse.text['*']).text(), | |||
field = fieldsBypName[data.maps['wikidata'][k]]; | |||
if (field) | |||
field.prop('placeholder', wikidataVal); | |||
} | |||
} | |||
); | |||
} | |||
} | |||
function buildParams(data) { | |||
var | |||
lines = data.split("\n"), | |||
line; | |||
function extractGlobalExplanation() { | |||
line = line.replace(/[!\|][^\|]*\|/, ''); | |||
if (wikiCodeFinder.test(line)) | |||
$.post( | |||
mw.util.wikiScript('api'), | |||
{ action: 'parse', text: line, disablepp: 1, format: 'json' }, | |||
function (data) { | |||
var html = data.parse.text['*']; | |||
globalExplanation = html; | |||
$('#tpw_globalExplanation').html(html).find('a').attr({ target: '_blank' }); | |||
} | |||
); | |||
else | |||
globalExplanation = line; | |||
} | |||
while (lines && lines.length) { | |||
line = lines.shift(); | |||
if (!(/^\|-/.test(line))) // look for |- this is wikitext for table row. | |||
continue; | |||
line = lines.shift(); | |||
if (line.indexOf('globalExplanation') + 1) { | |||
extractGlobalExplanation(); | |||
continue; | |||
} | |||
if (!line || !(/^\|/.test(line))) //wikitext for column | |||
continue; | |||
line = line.substr(1); // get rid of the leading | | |||
var fields = line.split('||'); | |||
if (fields.length < 2) | |||
continue; | |||
var name = $.trim(fields[0]); | |||
if (!name) | |||
continue; | |||
var desc = $.trim(fields[1]); | |||
var pAttribs = { desc: desc }; | |||
if (fields.length > 2) | |||
pAttribs.options = analyzeOptions($.trim(fields[2])); | |||
templateParams[name] = pAttribs; | |||
addParam(name); | |||
} | |||
} | |||
function analyzeOptions(str) { | |||
var res = {}, | |||
avail = ['multiline', 'required', 'depends', 'defval', 'choices', 'date', 'extended'], // maybe we'll have more in the future | |||
tavail = $.map(avail, i18n), | |||
options = str.split(/\s*;\s*/); | |||
for (var i in options) { | |||
var option = options[i].split(/\s*=\s*/); | |||
var ind = $.inArray(option[0], tavail); | |||
if (ind + 1) | |||
res[avail[ind]] = option.length > 1 ? option[1] : true; | |||
} | |||
anyExtended = anyExtended || res.extended; | |||
return res; | |||
} | |||
function createWikiCode() { | |||
var par = [template], | |||
delim = $('#' + oneLineTemplate).prop('checked') ? '' : '\n', | |||
paramValueDelim = $('#' + oneLineTemplate).prop('checked') ? '=' : ' = ', | |||
createEmpties = $('#createEmpties').prop('checked'), | |||
mustNumberNameless, | |||
valuedOrdered; | |||
for (var i = dialogFields.length - 1; i >= 0; i--) { | |||
var field = dialogFields[i], | |||
val = $.trim(field[1].val()); | |||
if (isNaN(field[0])) continue; // look only at order-based fields | |||
mustNumberNameless |= | |||
/=/.test(val) // order-based value containing "=" | |||
|| valuedOrdered && !val; // empty ordered w lower index than a non-empty one. | |||
if (val) valuedOrdered = true; | |||
} | |||
for (var i in dialogFields) { | |||
var | |||
field = dialogFields[i], | |||
name = $.trim(field[0]), | |||
f = field[1], | |||
opts = f.data('options'), | |||
param = templateParams[name], | |||
hidden = f.parents('.tpw_hidden').length, | |||
val = f.val().replace(/\s+$/, ''); // leave leading newlines, for lists etc., but remove trailing. | |||
if (param && param.param && param.param.type === 'url') | |||
val = val.replace(/\|/g, '{{!}}'); | |||
if (f.attr('type') == 'checkbox' && !f.prop('checked')) | |||
val = ""; | |||
if ((!createEmpties || opts.notInParamPage) && $.trim(val) === "") | |||
continue;//skip parameters with no value | |||
var next = mustNumberNameless || isNaN(name) | |||
? name + paramValueDelim + $.trim(val) | |||
: $.trim(val); | |||
par.push(next); | |||
} | |||
var combined = "{{" + par.join(delim + ($('#' + oneLineTemplate).prop('checked') ? "|" : "| ")) + delim + "}}"; | |||
if ($('#asRef').prop('checked')) | |||
return "{{הערה|" + combined + "}}"; | |||
if ($('#asList').prop('checked')) | |||
return "\n* " + combined + "\n"; | |||
return combined; | |||
} | |||
function showPreview() { | |||
var temp = createWikiCode(); | |||
$.post(mw.util.wikiScript('api'), | |||
{ | |||
action: 'parse', | |||
title: mw.config.get('wgPageName'), | |||
prop: 'text', | |||
text: temp, | |||
format: 'json' | |||
}, | |||
function (data) { | |||
if (data && data.parse && data.parse.text) { | |||
var buttons = [{ text: i18n('close'), click: function () { $(this).dialog('close'); } }], | |||
div = $('<div>').html(data.parse.text['*']); | |||
$('a', div).attr('target', '_blank'); // we don't want people to click on links in preview - they'll lose their work. | |||
$('<div>') | |||
.dialog( | |||
{ | |||
title: i18n('preview'), | |||
modal: true, | |||
position: [60, 60], | |||
buttons: buttons | |||
}) | |||
.append(div); | |||
circumventRtlBug(); | |||
} | |||
}); | |||
} | |||
function circumventRtlBug() { | |||
if (rtl) | |||
$('.ui-dialog-buttonpane button').css({ float: 'right' }); // jQuery has problems with rtl dialogs + ie is braindamaged. | |||
} | |||
function i18n(key, param) { | |||
switch (mw.config.get('wgUserLanguage')) { | |||
case 'he': | |||
switch (key) { | |||
case 'explain': return hebExplain(); | |||
case 'wizard dialog title': return 'מילוי הפרמטרים עבור ' + '<a href="' + mw.util.getUrl('מוסטער:' + template) + '" target="_blank">' + 'מוסטער:' + template + '</a>'; | |||
case 'ok': return 'אישור'; | |||
case 'cancel': return 'ביטול'; | |||
case 'preview': return 'תצוגה מקדימה'; | |||
case 'options select': return 'בחרו ערך מהרשימה'; | |||
case 'multiline': return 'מספר שורות'; | |||
case 'close': return 'סגור'; | |||
case 'required': return 'שדה חובה'; | |||
case 'depends': return 'תלוי'; | |||
case 'defval': return 'ברירת מחדל'; | |||
case 'choices': return 'אפשרויות'; | |||
case 'date': return 'תאריך'; | |||
case 'extended': return 'משני'; | |||
case 'button hint': return 'אשף מילוי תבניות'; | |||
case 'template selector title': return 'אנא הזינו את שם התבנית:'; | |||
case 'notInParamPage': return 'השדה "' + param + '" לא מופיע ברשימת הפרמטרים של התבנית'; | |||
case 'editParamPage': return 'לעריכת דף הפרמטרים'; | |||
case 'unknown error': return 'טעות בהפעלת האשף.\n' + param; | |||
case 'please select template': return 'שם התבנית'; | |||
case 'oneliner': return 'תבנית בשורה אחת'; | |||
case 'createempties': return 'רשום שדות ריקים'; | |||
case 'dateFormat': return 'd בMM yy'; | |||
case 'extended labels': return 'הראה את כל הפרמטרים'; | |||
case 'pve-required-empty': return 'התבנית דורשת שפרמטר זה יקבל ערך'; | |||
case 'pve-deprecated': return 'שימוש בפרמטר מיושן'; | |||
case 'pve-incompatible': return 'שדה זה מצפה לערך מספרי'; | |||
case 'pve-no-such-name': return 'שדה זה לא קיים בתבנית'; | |||
case 'explain-pve': return 'שדות עם שגיאה מסומנים ברקע ורוד'; | |||
case 'pve-approve-close': return 'יש בתבנית שגיאות. אנא אשרו יציאה מהאשף'; | |||
} | |||
break; | |||
case 'en': | |||
switch (key) { | |||
case 'explain': return 'fields with red border are required, the rest are optional'; | |||
case 'wizard dialog title': return 'Set up parameters for template: ' + template; | |||
case 'ok': return 'OK'; | |||
case 'cancel': return 'Cancel'; | |||
case 'params subpage': return 'Parameters'; | |||
case 'preview': return 'Preview'; | |||
case 'options select': return 'Select one:'; | |||
case 'multiline': return 'Multiline'; | |||
case 'close': return 'Close'; | |||
case 'required': return 'Required'; | |||
case 'depends': return 'Depends on'; | |||
case 'defval': return 'Default'; | |||
case 'choices': return 'Choices'; | |||
case 'date': return 'Date'; | |||
case 'extended': return 'Extended'; | |||
case 'button hint': return 'Template parameters wizard'; | |||
case 'template selector title': return 'Please enter the template name'; | |||
case 'notInParamPage': return 'field "' + param + '" does not appear in the template\'s parameters list'; | |||
case 'editParamPage': return 'Edit paramters page'; | |||
case 'unknown error': return 'Error occured: \n' + param; | |||
case 'please select template': return 'Please enter template name'; | |||
case 'oneliner': return 'Single-line template'; | |||
case 'createempties': return 'Write empty parameters to page'; | |||
case 'dateFormat': return 'MM d, yy'; | |||
case 'extended labels': return 'Show all parameters'; | |||
case 'pve-required-empty': return 'The template requires a value for this field'; | |||
case 'pve-deprecated': return 'deprecated parameter'; | |||
case 'pve-incompatible': return 'expaects numteric value'; | |||
case 'pve-no-such-name': return 'undercgonzed parameter'; | |||
case 'explain-pve': return 'fields with errors are marked with pink background'; | |||
case 'pve-approve-close': return 'Template contains errors. Please confim exit'; | |||
} | |||
default: | |||
switch (key) { | |||
case 'explain': return 'פעלדער מיט רויט ראַם זענען פארלאנגט, די איבריגע זענען אַפּציאנאַל'; | |||
case 'wizard dialog title': return 'שטעל אן פאראמעטער פארן ' + '<a href="' + mw.util.getUrl('מוסטער:' + template) + '" target="_blank">' + 'מוסטער:' + template + '</a>'; | |||
case 'cancel': return 'אנוליר'; | |||
case 'params subpage': return 'פאראמעטער'; | |||
case 'preview': return 'פאראויסקוק'; | |||
case 'options select': return 'וועל אויס איינס:'; | |||
case 'multiline': return 'מולטי שורה'; | |||
case 'close': return 'פארמאך'; | |||
case 'required': return 'פארלאנגט'; | |||
case 'depends': return 'Depends on'; | |||
case 'defval': return 'דיפאָלט'; | |||
case 'choices': return 'אפּציעס'; | |||
case 'date': return 'דאטום'; | |||
case 'extended': return 'Extended'; | |||
case 'button hint': return 'מוסטער פּאראמעטער וויזערד'; | |||
case 'template selector title': return 'ביטע אריינלייגן מוסטער נאמען'; | |||
case 'notInParamPage': return 'פעלד "' + param + '" ערשיינט נישט אין מוסטער\'ס פּאראמעטער ליסטע'; | |||
case 'editParamPage': return 'רעדאַגירט פּאַראַמעטער בלאַט'; | |||
case 'unknown error': return 'פעלער געשען: \n' + param; | |||
case 'please select template': return 'מוסטער נאמען'; | |||
case 'oneliner': return 'איינצלנע-שורה מוסטער'; | |||
case 'createempties': return 'שרייב ליידיגע פאראמעטער צום בלאט'; | |||
case 'dateFormat': return 'MM d, yy'; | |||
case 'extended labels': return 'ווייז אלע פאראמעטער'; | |||
case 'pve-required-empty': return 'דער מוסטער פארלאנגט א ווערד פאר דעם פעלד'; | |||
case 'pve-deprecated': return 'deprecated parameter'; | |||
case 'pve-incompatible': return 'ערווארטעט נומערישע ווערט'; | |||
case 'pve-no-such-name': return 'אומאַנערקענטע פאראמעטער'; | |||
case 'explain-pve': return 'פעלדער מיט פעלערן זענען אנגעצייכנט מיט ראָזעווע הינטערגרונט'; | |||
case 'pve-approve-close': return 'מוסטער אנטהאלט פעלערן. ביטע באשטעטיג ארויסגאנג'; | |||
} | |||
} | |||
return key; | |||
} | |||
function hebExplain() { | |||
var explanation; | |||
if (rawTemplate) return 'לתבנית "' + template + '" אין דף פרמטרים, ולכן לשדות אין תיאור.'; | |||
if (anyRequiredParam()) return 'שדות חובה מסומנים במסגרת אדומה'; | |||
return ''; | |||
} | |||
function anyRequiredParam() { | |||
for (name in templateParams) { | |||
var param = templateParams[name]; | |||
if (param.options.required) return true; | |||
} | |||
return false; | |||
} | |||
function templatePage() { | |||
var t = $.trim(template) | |||
return t.match(':') ? t : mw.config.get('wgFormattedNamespaces')[10] + ':' + t; | |||
} | |||
function updateRawPreview() { | |||
var canOK = 'enable'; | |||
for (var i in dialogFields) { | |||
var df = dialogFields[i][1]; | |||
var opts = df.data('options'); | |||
if (opts && opts.required && $.trim(df.val()).length == 0) | |||
canOK = 'disable'; | |||
if (opts && opts.depends) { | |||
var dep = fieldsBypName[opts.depends]; | |||
var depEmpty = (dep && dep.val() && $.trim(dep.val())) ? false : true; | |||
var row = rowsBypName[df.data('paramName')]; | |||
if (row) | |||
row.toggleClass('tpw_hidden', depEmpty); | |||
} | |||
} | |||
$('#asList').attr('disabled', $('#asRef').prop('checked'));//disable list if ref | |||
$('#asRef').attr('disabled', $('#asList').prop('checked'));//disable ref if list | |||
$(".ui-dialog-buttonpane button:contains('" + i18n('ok') + "')").button(canOK); | |||
$('#tpw_preview').text(createWikiCode()); | |||
localStorage.setItem(localStorageKey + '.' + emptiesKey, $('#createEmpties').prop('checked')); | |||
validate(); | |||
} | |||
function validate() { | |||
function validateField(param, input) { | |||
function markError(msg) { | |||
input | |||
.addClass('tpw-paramvalidation') | |||
.attr('title', i18n(msg)); | |||
return false; | |||
} | |||
var hasVal = !!input.val(); | |||
if (param.options.notInParamPage && hasVal) return markError('pve-no-such-name'); | |||
if (param.param.required && !hasVal) return markError('pve-required-empty'); | |||
if (param.param.deprecated && hasVal) return markError('pve-deprecated'); | |||
if (param.param.type === 'number' && isNaN(Number(input.val().replace(/,/g, '')))) return markError('pve-incompatible'); | |||
return true; | |||
} | |||
var aOK = true; | |||
for (var i in dialogFields) { | |||
var | |||
field = dialogFields[i], | |||
name = $.trim(field[0]), | |||
input = field[1].removeClass('tpw-paramvalidation'), | |||
param = templateParams[name]; | |||
aOK = validateField(param, input) && aOK; | |||
} | |||
$('#tpw-explain').html(i18n(aOK ? 'explain' : 'explain-pve')); | |||
return aOK; | |||
} | |||
function createInputField(paramName) { | |||
var params = templateParams[paramName], | |||
options = params.options || {}, | |||
f, | |||
checkbox = false; | |||
if (options.choices) { | |||
var choices = options.choices.split(/\s*,\s*/); | |||
if (choices.length > 1) { | |||
f = $('<select>').append($('<option>', { text: i18n('options select'), value: '' })); | |||
for (var i in choices) { | |||
var choice = choices[i].trim(); // first and last may carry spaces | |||
var option = $('<option>', { text: choice, value: choice }); | |||
f.append(option); | |||
} | |||
} | |||
else { | |||
checkbox = true; | |||
var choice = choices[0].trim(); | |||
f = $('<input>', { type: 'checkbox', value: choices[0], text: choices[0].trim() }) | |||
.css({ float: rtl ? 'right' : 'left' }); | |||
f.prop('checked', options.defval && options.defval.trim() == choices[0]); | |||
} | |||
} | |||
else if (options.multiline) { | |||
var rows = options.multiline; | |||
f = $('<textarea>', { rows: 1 }) | |||
.focus(function () { this.rows = 5; }) | |||
.blur(function () { this.rows = 1 }); | |||
} | |||
else | |||
f = $('<input>', { type: 'text' }); | |||
if (!checkbox && f.autoCompleteWikiText) // teach the controls to autocomplete. | |||
f.autoCompleteWikiText({ positionMy: rtl ? "left top" : "right top" }); | |||
f.css({ width: checkbox ? '1em' : '28em' }) | |||
.data({ paramName: paramName, options: options }) | |||
.on('paste cut drop input change', updateRawPreview); | |||
if (options.defval && !checkbox) | |||
f.val(options.defval.trim()); | |||
if (options.required) | |||
f.addClass('tpw-required'); | |||
if (options.date) | |||
f.datepicker({ dateFormat: typeof options.date == "string" ? options.date : i18n('dateFormat') }); | |||
return f; | |||
} | |||
var | |||
timer = null, | |||
lastVisited = $('<a>'); | |||
function enterTipsy() { | |||
clearTimeout(timer); | |||
$(this).attr('inside', 1); | |||
} | |||
var | function leaveTipsy() { | ||
var $this = $(this); | |||
if ($this.attr('master') || $this.attr('inside')) { | |||
$this.attr('inside', ''); | |||
timer = setTimeout(function () { lastVisited.tipsy('hide'); }, 500); | |||
} | |||
} | |||
function tipsyContent() { | |||
var | |||
paramName = $(this).data('paramname'), | |||
def = templateParams[paramName], | |||
desc = def && def.desc || ''; | |||
if (!def) return ''; // early terminate if param name is not valid | |||
if (def.htmlDesc) | |||
return def.htmlDesc; | |||
if (wikiCodeFinder.test(desc)) // does it need parsing? | |||
$.ajax({ | |||
url: mw.util.wikiScript('api'), | |||
async: false, | |||
type: 'post', | |||
data: { action: 'parse', text: desc, disablepp: 1, format: 'json' }, // parse it. | |||
success: function (data) { | |||
var div = $('<div>').html(data.parse.text['*']); | |||
$('a', div).attr({ target: '_blank' }); | |||
def.htmlDesc = div.html(); | |||
} | |||
}); | |||
else | |||
def.htmlDesc = desc; | |||
return def.htmlDesc; | |||
} | |||
return false; | function addRow(paramName, table) { | ||
var | |||
def = templateParams[paramName], | |||
inputField = createInputField(paramName), | |||
nameColor = def.desc | |||
? 'blue' | |||
: def.options.notInParamPage | |||
? 'red' | |||
: def.options.isAlias | |||
? 'green' | |||
: 'black', | |||
tr = $('<tr>') | |||
.append( | |||
$('<td>', { width: 120 }) | |||
.css({ fontWeight: 'bold', color: nameColor }) | |||
.data({ paramname: paramName }) | |||
.text(templateParams[paramName].label || paramName) | |||
.tipsy({ html: true, trigger: 'manual', title: tipsyContent }) | |||
.mouseenter(function () { | |||
clearTimeout(timer); | |||
$('.tipsy').remove(); | |||
lastVisited = $(this); | |||
lastVisited.tipsy('show'); | |||
}) | |||
.mouseleave(leaveTipsy) | |||
.attr('master', 'true') | |||
) | |||
.append($('<td>').css({ width: '30em' }).append(inputField)); | |||
dialogFields.push([paramName, inputField]); | |||
if (def.options.extended) | |||
tr.addClass('tpw_extended'); | |||
table.append(tr); | |||
rowsBypName[paramName] = tr; | |||
fieldsBypName[paramName] = inputField; | |||
} | |||
function injectResults() { | |||
$("#wpTextbox1").textSelection('encapsulateSelection', { replace: true, peri: createWikiCode() }); | |||
} | |||
function createExtendedCheckBox() { | |||
return $('<p>') | |||
.text(i18n('extended labels')) | |||
.append($('<input>', { type: 'checkbox' }) | |||
.change(function () { | |||
extendedParamCssRule.disabled = $(this).prop('checked'); | |||
}) | |||
); | |||
} | |||
function buildDialog(data) { | |||
var title = $('<span>').html(i18n('wizard dialog title', template)); | |||
$('.tpw_disposable').remove(); | |||
if (rawTemplate) | |||
buildParamsRaw(data); | |||
else if (tdTemplate) { | |||
buildParamsTd(data); | |||
if (data.description) title.find('a').attr({ title: data.description }); | |||
} | |||
paramsFromSelection(); | |||
var table = $('<table>'); | |||
var dialog = $('<div>', { 'class': 'tpw_disposable' }) | |||
.dialog({ | |||
height: 'auto', | |||
title: title.html(), | |||
width: 'auto', | |||
overflow: 'auto', | |||
position: [$('body').width() * 0.2, $('body').height() * 0.1], | |||
open: function () { $(this).css({ 'max-height': Math.round($('body').height() * 0.7) }); } | |||
}) | |||
.append($('<div>', { id: 'tpw_globalExplanation' }).html(globalExplanation)) | |||
.append($('<p>', { id: 'tpw-explain' }).html(i18n('explain'))) | |||
.append(anyExtended ? createExtendedCheckBox() : '') | |||
.append(table) | |||
.append($('<p>') | |||
.append(i18n('oneliner')) | |||
.append($('<input>', { type: 'checkbox', id: oneLineTemplate }).prop('checked', isInline).change(updateRawPreview) | |||
) | |||
) | |||
.append($('<p>') | |||
.append(i18n('createempties')) | |||
.append($('<input>', { type: 'checkbox', id: 'createEmpties' }) | |||
.change(updateRawPreview) | |||
.prop('checked', localStorage.getItem(localStorageKey + '.' + emptiesKey) == "true") | |||
) | |||
) | |||
.append($('<pre>', { id: 'tpw_preview' }).addClass('tpw-wikicode-preview')); | |||
while (paramsOrder.length) | |||
addRow(paramsOrder.shift(), table); | |||
dialog.append($('<label>').text(' רעפערענץ ')) | |||
.append($('<input>', {type: 'checkbox', id: 'asRef'}).change(updateRawPreview)) | |||
.append($('<label>').css({width: '12em'}).text( ' אייטעם אין א ליסטע ')) | |||
.append($('<input>', {type: 'checkbox', id: 'asList'}).change(updateRawPreview)); | |||
var buttons = {}; // we need to do it this way, because with literal object, the keys must be literal. | |||
buttons[i18n('ok')] = function () { | |||
if (!validate() && !confirm(i18n('pve-approve-close'))) return; | |||
injectResults(); | |||
dialog.dialog('close'); | |||
}; | |||
buttons[i18n('cancel')] = function () { dialog.dialog('close'); }; | |||
buttons[i18n('preview')] = showPreview; | |||
dialog.dialog('option', 'buttons', buttons); | |||
circumventRtlBug(); | |||
updateRawPreview(); | |||
$('.tipsy').hover(enterTipsy, leaveTipsy); | |||
$(document).delegate('.ui-dialog', 'keyup', function (e) { | |||
var target = e.target; | |||
var tagName = target.tagName.toLowerCase(); | |||
tagName = (tagName === 'input' && target.type === 'button') | |||
? 'button' | |||
: tagName; | |||
var isClickableTag = tagName !== 'textarea' && | |||
tagName !== 'select' && | |||
tagName !== 'button'; | |||
if (e.which === $.ui.keyCode.ENTER && isClickableTag) { | |||
$(this).find('.ui-dialog-buttonset button').eq(0).trigger('click'); | |||
return false; | |||
} | |||
}); | |||
} | |||
function init() { | |||
template = null; | |||
templateParams = {}; | |||
paramsOrder = []; | |||
dialogFields = []; | |||
rowsBypName = {}; | |||
fieldsBypName = {}; | |||
mw.util.addCSS(".tpw_hidden{display:none;}"); | |||
anyExtended = false; | |||
extendedParamCssRule = extendedParamCssRule || mw.util.addCSS(".tpw_extended{display:none;}"); | |||
} | |||
function reportError(a, b, error) { | |||
var key; | |||
if (typeof console != 'undefined') { | |||
for (key in a) | |||
if (typeof a[key] != 'function') | |||
console.log(key + '=>' + a[key]); | |||
console.log(b); | |||
console.log(error); | |||
} | |||
alert(i18n('unknown error', error)); | |||
} | |||
function pickTemplate(item) { | |||
function okButtonPressed(e, ui) { | |||
template = ui ? ui.item.value : selector.val(); | |||
fireDialog(); | |||
templateSelector.dialog("close"); | |||
} | |||
var selector = $('<input>') | |||
.css({ width: '28em' }) | |||
.autocomplete({ | |||
source: function (request, response) { | |||
$.getJSON( | |||
mw.util.wikiScript('api'), | |||
{ action: 'opensearch', search: request.term, namespace: 10 }, | |||
function (data) { | |||
if (data[1]) | |||
response($(data[1]).map(function (index, item) { return item.replace(/.*:/, ''); })); | |||
} | |||
); | |||
}, | |||
select: okButtonPressed | |||
}); | |||
var templateSelector = $('<div>').dialog({ | |||
title: i18n('template selector title'), | |||
height: 'auto', | |||
width: 'auto', | |||
modal: true, | |||
buttons: [ | |||
{ text: i18n('ok'), click: okButtonPressed }, | |||
{ text: i18n('cancel'), click: function () { templateSelector.dialog("close") } } | |||
] | |||
}).append(selector); | |||
circumventRtlBug(); | |||
selector.focus(); | |||
} | } | ||
function fireDialog() { | |||
var readRaw = function () { | |||
rawTemplate = true; | |||
$.ajax({ | |||
url: mw.util.wikiScript(), | |||
data: { title: templatePage(), action: 'raw' }, | |||
dataType: 'text', | |||
success: buildDialog, | |||
error: reportError | |||
}); | |||
}, | |||
readTemplateData = function () { | |||
$.ajax({ | |||
url: mw.util.wikiScript('api'), | |||
data: { action: 'templatedata', titles: templatePage(), redirects: true, format: 'json', lang: mw.config.get('wgUserLanguage') }, | |||
dataType: 'json', | |||
success: function (data) { | |||
var found = false; | |||
if (data && data.pages) | |||
for (var pageid in data.pages) { | |||
tdTemplate = true; | |||
found = true; | |||
buildDialog(data.pages[pageid]); | |||
break; | |||
} | |||
if (!found) | |||
readRaw(); | |||
}, | |||
error: readRaw | |||
}); | |||
}; | |||
rawTemplate = false; | |||
readTemplateData(); | |||
} | |||
function templateContext() { | |||
var selection = $("#wpTextbox1").textSelection('getSelection'), | |||
caretPos, beforeText, afterText, templateStart, templateEnd; | |||
// trust the user | |||
if (selection.length > 0) { | |||
return selection; | |||
} | |||
caretPos = $("#wpTextbox1").textSelection('getCaretPosition'); | |||
beforeText = $("#wpTextbox1").val().substr(0, caretPos); | |||
afterText = $("#wpTextbox1").val().substr(caretPos); | |||
templateStart = beforeText.lastIndexOf('{{'); | |||
templateEnd = afterText.indexOf('}}') + 2; | |||
// only under opportunistic template context assumptions | |||
if ($("#wpTextbox1").val().split('{').length != $("#wpTextbox1").val().split('}').length || | |||
(beforeText.split('{{').length === beforeText.split('}}').length) || | |||
(afterText.split('{{').length === afterText.split('}}').length)) | |||
return ''; | |||
if (beforeText.substr(templateStart, caretPos) == '{{הערה|' && templateEnd <= 4) // '1=}}' | |||
return ''; | |||
// determine the start and the end of the template context | |||
while (beforeText.substr(templateStart).split('{{').length <= beforeText.substr(templateStart).split('}}').length) | |||
templateStart = beforeText.lastIndexOf('{{', templateStart - 1) | |||
while (afterText.substr(0, templateEnd).split('{{').length >= afterText.substr(0, templateEnd).split('}}').length) | |||
templateEnd = afterText.indexOf('}}', templateEnd) + 2; | |||
// extend the selection to the current template context | |||
$("#wpTextbox1").focus().textSelection('setSelection', { | |||
start: templateStart, | |||
end: caretPos + templateEnd | |||
}); | |||
return $("#wpTextbox1").textSelection('getSelection'); | |||
} | |||
function doIt() { | |||
mw.loader.using(['jquery.ui', 'jquery.tipsy', 'jquery.textSelection', 'mediawiki.api'], function () { | |||
init(); | |||
var match = templateContext().match(/^\{\{([^|}]*)/); | |||
template = match ? $.trim(match[1]) : null; | |||
if (template) | |||
fireDialog(); | |||
else | |||
pickTemplate(); | |||
}); | |||
} | |||
function addToWikiEditor() { | |||
$('#wpTextbox1').wikiEditor('addToToolbar', { | |||
section: 'main', | |||
group: 'insert', | |||
tools: { | |||
'templateParamsWizard': { | |||
label: i18n('button hint'), | |||
type: 'button', | |||
icon: '//yi.hamichlol.org.il/w/load.php?modules=oojs-ui.styles.icons-editing-advanced&image=puzzle&format=rasterized&lang=yi', | |||
action: { type: 'callback', execute: doIt } | |||
} | |||
} | |||
}); | |||
} | |||
if (mw.user.options.get('usebetatoolbar')) | |||
mw.loader.using(['ext.wikiEditor'], function () { | |||
if (typeof $.wikiEditor != 'undefined') { | |||
if ($('#wikiEditor-ui-toolbar').length === 1) addToWikiEditor();//in case it loaded after toolbar initaliztion | |||
else $('#wpTextbox1').on('wikiEditor-toolbar-doneInitialSections', addToWikiEditor); | |||
} | |||
}); | |||
else | |||
$('div #toolbar').append( // "old style" | |||
$('<img>', { src: '//upload.wikimedia.org/wikipedia/commons/e/eb/Button_plantilla.png', title: i18n('button hint'), 'class': 'mw-toolbar-editbutton' }) | |||
.css({ cursor: 'pointer' }) | |||
.click(doIt) | |||
); | |||
} ); | }); |
רעוויזיע פון 11:15, 21 סעפטעמבער 2023
//Template parameters wizard
//Written by [[User:קיפודנחש]]
"use strict";
if (!$('#wpTextbox1').prop('readonly'))
$(function ($) {
// template parameter is an object with the following fields:
// desc: desciption string
// defval: default value (optional)
// options: object with optional fields:
//// multiline: number of lines
//// depends: another field's name
//// required: boolean
//// date: use JS date widget
//// choices: array of legal values for the field
//// extended: this field will not show on initial screen, and will appear once the user selects "show all fields"
var
// templateParams is keyed by paramName.
templateParams,
paramsOrder,
// which template are we working on
template,
// array of pairs - [paramName, inputField]
dialogFields,
// table rows keyed by paramName
rowsBypName,
// the fields, keyed by paramName
fieldsBypName,
// boolean, indicating the source of data is templatedata.
tdTemplate,
// boolean, indicating the source of the data is analyzing the template page itself.
rawTemplate,
isInline,
rtl = $('body').is('.rtl'),
// test to see if a string contains wikiCode and hence needs parsing, or cen be used as is.
wikiCodeFinder = /[\[\]\{\}<>]/,
globalExplanation = '',
extendedParamCssRule,
anyExtended = false,
localStorageKey = 'templateParamWizard',
emptiesKey = 'writeEmpties',
oneLineTemplate = 'oneLineTemplate',
allAliases = [];
function addParam(name) {
if ($.inArray(name, paramsOrder) == -1)
paramsOrder.push(name);
}
function paramsFromSelection() {
var selection = $("#wpTextbox1").textSelection('getSelection').replace(/^\s*\{\{|\}\}\s*$/g, ''); //scrap the first {{ and last }}
var specials = [],
match;
while (true) { //extract inner links, inner templates and inner params - we don't want to split those.
match = selection.match(/(\{\{[^\{\}\]\[]*\}\}|\[\[[^\{\}\]\[]*\]\]|\[[^\{\}\]\[]*\])/);
if (!match || !match.length)
break;
specials.push(match[0]);
selection = selection.replace(match[0], "\0" + specials.length + "\0");
}
var params = selection.split(/ *\| */);
params.shift(); // remove the template name
var ordered = 0;
for (var i in params) {
var param = params[i];
if (! /=/.test(param)) {
param = ++ordered + '=' + param;
}
var paramPair = param.split("=");
var name = $.trim(paramPair.shift());
if (!isNaN(name)) {
ordered = parseInt(name); // this still won't work as advertise when template contains explicit parameter 2 before implicit 1: {{x | 2 = hey | ho }}
}
var val = paramPair.join('=');
while (true) {
match = val.match(/\0(\d+)\0/);
if (!match || !match.length)
break;
val = val.replace(match[0], specials[parseInt(match[1], 10) - 1]);
}
if (name && paramPair.length) {
var tp = templateParams[name] =
templateParams[name] ||
~allAliases.indexOf(name) && { param: {}, options: { isAlias: 1 } } ||
{ param: {}, options: { notInParamPage: 1 } };
addParam(name);
$.extend(tp.options, { defval: val });
if (/\n/.test(val)) $.extend(tp.options, { multiline: 5 });
// next line is for the case where there are "choices"' but current value is not one of them: add it as a new choice.
if (typeof tp.options.choices === 'string' && tp.options.choices.indexOf(val) < 0)
tp.options.choices += (', ' + val);
}
}
}
function buildParamsRaw(data) {
var
paramExtractor = /{{3,}(.*?)[<|}]/mg,
m;
while (m = paramExtractor.exec(data)) {
var paramName = $.trim(m[1]);
templateParams[paramName] = { desc: '', options: { multiline: 5 }, label: paramName, param: {} };
addParam(paramName);
}
}
function buildParamsTd(data) {
var params = data.params,
paramOrder = data.paramOrder;
function optionsOfParam(param) {
var options = {};
if (param.required) options.required = true;
if (param.suggestedvalues && param.suggestedvalues.length) options.choices = param.suggestedvalues.join(',');
return options;
}
function onemore(name) {
var param = params[name];
if (param.deprecated)
return; // ignore deprecated parameters - pretend they are not in TD.
templateParams[name] = {
desc: param.description || '',
options: optionsOfParam(param),
label: param.label || name,
param: param
};
if (param.aliases) $.merge(allAliases, param.aliases); // collect alliases if there are any
addParam(name);
}
isInline = data.format === 'inline';
if (paramOrder && paramOrder.length)
for (var ind in paramOrder)
onemore(paramOrder[ind]);
else // no order - take them as they come.
for (var paramname in params)
onemore(paramname);
// derive placeholders for feilds derived from wikidata
if (data.maps && data.maps.hasOwnProperty('wikidata') && mw.config.get('wgWikibaseItemId')) {
var wikidataFormattedValues = $('<div>');
for (var k in data.maps['wikidata']) {
wikidataFormattedValues.append($('<span>', { id: k, text: '{{#property:' + k + '}}' }))
}
$.post(
mw.util.wikiScript('api'),
{ action: 'parse', text: wikidataFormattedValues.html(), disablelimitreport: 1, format: 'json', prop: 'text', title: mw.config.get('wgPageName') },
function (wbd) {
if (!wbd || !wbd.parse || !wbd.parse.text) return;
for (var k in data.maps['wikidata']) {
var wikidataVal = $('#' + k, wbd.parse.text['*']).text(),
field = fieldsBypName[data.maps['wikidata'][k]];
if (field)
field.prop('placeholder', wikidataVal);
}
}
);
}
}
function buildParams(data) {
var
lines = data.split("\n"),
line;
function extractGlobalExplanation() {
line = line.replace(/[!\|][^\|]*\|/, '');
if (wikiCodeFinder.test(line))
$.post(
mw.util.wikiScript('api'),
{ action: 'parse', text: line, disablepp: 1, format: 'json' },
function (data) {
var html = data.parse.text['*'];
globalExplanation = html;
$('#tpw_globalExplanation').html(html).find('a').attr({ target: '_blank' });
}
);
else
globalExplanation = line;
}
while (lines && lines.length) {
line = lines.shift();
if (!(/^\|-/.test(line))) // look for |- this is wikitext for table row.
continue;
line = lines.shift();
if (line.indexOf('globalExplanation') + 1) {
extractGlobalExplanation();
continue;
}
if (!line || !(/^\|/.test(line))) //wikitext for column
continue;
line = line.substr(1); // get rid of the leading |
var fields = line.split('||');
if (fields.length < 2)
continue;
var name = $.trim(fields[0]);
if (!name)
continue;
var desc = $.trim(fields[1]);
var pAttribs = { desc: desc };
if (fields.length > 2)
pAttribs.options = analyzeOptions($.trim(fields[2]));
templateParams[name] = pAttribs;
addParam(name);
}
}
function analyzeOptions(str) {
var res = {},
avail = ['multiline', 'required', 'depends', 'defval', 'choices', 'date', 'extended'], // maybe we'll have more in the future
tavail = $.map(avail, i18n),
options = str.split(/\s*;\s*/);
for (var i in options) {
var option = options[i].split(/\s*=\s*/);
var ind = $.inArray(option[0], tavail);
if (ind + 1)
res[avail[ind]] = option.length > 1 ? option[1] : true;
}
anyExtended = anyExtended || res.extended;
return res;
}
function createWikiCode() {
var par = [template],
delim = $('#' + oneLineTemplate).prop('checked') ? '' : '\n',
paramValueDelim = $('#' + oneLineTemplate).prop('checked') ? '=' : ' = ',
createEmpties = $('#createEmpties').prop('checked'),
mustNumberNameless,
valuedOrdered;
for (var i = dialogFields.length - 1; i >= 0; i--) {
var field = dialogFields[i],
val = $.trim(field[1].val());
if (isNaN(field[0])) continue; // look only at order-based fields
mustNumberNameless |=
/=/.test(val) // order-based value containing "="
|| valuedOrdered && !val; // empty ordered w lower index than a non-empty one.
if (val) valuedOrdered = true;
}
for (var i in dialogFields) {
var
field = dialogFields[i],
name = $.trim(field[0]),
f = field[1],
opts = f.data('options'),
param = templateParams[name],
hidden = f.parents('.tpw_hidden').length,
val = f.val().replace(/\s+$/, ''); // leave leading newlines, for lists etc., but remove trailing.
if (param && param.param && param.param.type === 'url')
val = val.replace(/\|/g, '{{!}}');
if (f.attr('type') == 'checkbox' && !f.prop('checked'))
val = "";
if ((!createEmpties || opts.notInParamPage) && $.trim(val) === "")
continue;//skip parameters with no value
var next = mustNumberNameless || isNaN(name)
? name + paramValueDelim + $.trim(val)
: $.trim(val);
par.push(next);
}
var combined = "{{" + par.join(delim + ($('#' + oneLineTemplate).prop('checked') ? "|" : "| ")) + delim + "}}";
if ($('#asRef').prop('checked'))
return "{{הערה|" + combined + "}}";
if ($('#asList').prop('checked'))
return "\n* " + combined + "\n";
return combined;
}
function showPreview() {
var temp = createWikiCode();
$.post(mw.util.wikiScript('api'),
{
action: 'parse',
title: mw.config.get('wgPageName'),
prop: 'text',
text: temp,
format: 'json'
},
function (data) {
if (data && data.parse && data.parse.text) {
var buttons = [{ text: i18n('close'), click: function () { $(this).dialog('close'); } }],
div = $('<div>').html(data.parse.text['*']);
$('a', div).attr('target', '_blank'); // we don't want people to click on links in preview - they'll lose their work.
$('<div>')
.dialog(
{
title: i18n('preview'),
modal: true,
position: [60, 60],
buttons: buttons
})
.append(div);
circumventRtlBug();
}
});
}
function circumventRtlBug() {
if (rtl)
$('.ui-dialog-buttonpane button').css({ float: 'right' }); // jQuery has problems with rtl dialogs + ie is braindamaged.
}
function i18n(key, param) {
switch (mw.config.get('wgUserLanguage')) {
case 'he':
switch (key) {
case 'explain': return hebExplain();
case 'wizard dialog title': return 'מילוי הפרמטרים עבור ' + '<a href="' + mw.util.getUrl('מוסטער:' + template) + '" target="_blank">' + 'מוסטער:' + template + '</a>';
case 'ok': return 'אישור';
case 'cancel': return 'ביטול';
case 'preview': return 'תצוגה מקדימה';
case 'options select': return 'בחרו ערך מהרשימה';
case 'multiline': return 'מספר שורות';
case 'close': return 'סגור';
case 'required': return 'שדה חובה';
case 'depends': return 'תלוי';
case 'defval': return 'ברירת מחדל';
case 'choices': return 'אפשרויות';
case 'date': return 'תאריך';
case 'extended': return 'משני';
case 'button hint': return 'אשף מילוי תבניות';
case 'template selector title': return 'אנא הזינו את שם התבנית:';
case 'notInParamPage': return 'השדה "' + param + '" לא מופיע ברשימת הפרמטרים של התבנית';
case 'editParamPage': return 'לעריכת דף הפרמטרים';
case 'unknown error': return 'טעות בהפעלת האשף.\n' + param;
case 'please select template': return 'שם התבנית';
case 'oneliner': return 'תבנית בשורה אחת';
case 'createempties': return 'רשום שדות ריקים';
case 'dateFormat': return 'd בMM yy';
case 'extended labels': return 'הראה את כל הפרמטרים';
case 'pve-required-empty': return 'התבנית דורשת שפרמטר זה יקבל ערך';
case 'pve-deprecated': return 'שימוש בפרמטר מיושן';
case 'pve-incompatible': return 'שדה זה מצפה לערך מספרי';
case 'pve-no-such-name': return 'שדה זה לא קיים בתבנית';
case 'explain-pve': return 'שדות עם שגיאה מסומנים ברקע ורוד';
case 'pve-approve-close': return 'יש בתבנית שגיאות. אנא אשרו יציאה מהאשף';
}
break;
case 'en':
switch (key) {
case 'explain': return 'fields with red border are required, the rest are optional';
case 'wizard dialog title': return 'Set up parameters for template: ' + template;
case 'ok': return 'OK';
case 'cancel': return 'Cancel';
case 'params subpage': return 'Parameters';
case 'preview': return 'Preview';
case 'options select': return 'Select one:';
case 'multiline': return 'Multiline';
case 'close': return 'Close';
case 'required': return 'Required';
case 'depends': return 'Depends on';
case 'defval': return 'Default';
case 'choices': return 'Choices';
case 'date': return 'Date';
case 'extended': return 'Extended';
case 'button hint': return 'Template parameters wizard';
case 'template selector title': return 'Please enter the template name';
case 'notInParamPage': return 'field "' + param + '" does not appear in the template\'s parameters list';
case 'editParamPage': return 'Edit paramters page';
case 'unknown error': return 'Error occured: \n' + param;
case 'please select template': return 'Please enter template name';
case 'oneliner': return 'Single-line template';
case 'createempties': return 'Write empty parameters to page';
case 'dateFormat': return 'MM d, yy';
case 'extended labels': return 'Show all parameters';
case 'pve-required-empty': return 'The template requires a value for this field';
case 'pve-deprecated': return 'deprecated parameter';
case 'pve-incompatible': return 'expaects numteric value';
case 'pve-no-such-name': return 'undercgonzed parameter';
case 'explain-pve': return 'fields with errors are marked with pink background';
case 'pve-approve-close': return 'Template contains errors. Please confim exit';
}
default:
switch (key) {
case 'explain': return 'פעלדער מיט רויט ראַם זענען פארלאנגט, די איבריגע זענען אַפּציאנאַל';
case 'wizard dialog title': return 'שטעל אן פאראמעטער פארן ' + '<a href="' + mw.util.getUrl('מוסטער:' + template) + '" target="_blank">' + 'מוסטער:' + template + '</a>';
case 'cancel': return 'אנוליר';
case 'params subpage': return 'פאראמעטער';
case 'preview': return 'פאראויסקוק';
case 'options select': return 'וועל אויס איינס:';
case 'multiline': return 'מולטי שורה';
case 'close': return 'פארמאך';
case 'required': return 'פארלאנגט';
case 'depends': return 'Depends on';
case 'defval': return 'דיפאָלט';
case 'choices': return 'אפּציעס';
case 'date': return 'דאטום';
case 'extended': return 'Extended';
case 'button hint': return 'מוסטער פּאראמעטער וויזערד';
case 'template selector title': return 'ביטע אריינלייגן מוסטער נאמען';
case 'notInParamPage': return 'פעלד "' + param + '" ערשיינט נישט אין מוסטער\'ס פּאראמעטער ליסטע';
case 'editParamPage': return 'רעדאַגירט פּאַראַמעטער בלאַט';
case 'unknown error': return 'פעלער געשען: \n' + param;
case 'please select template': return 'מוסטער נאמען';
case 'oneliner': return 'איינצלנע-שורה מוסטער';
case 'createempties': return 'שרייב ליידיגע פאראמעטער צום בלאט';
case 'dateFormat': return 'MM d, yy';
case 'extended labels': return 'ווייז אלע פאראמעטער';
case 'pve-required-empty': return 'דער מוסטער פארלאנגט א ווערד פאר דעם פעלד';
case 'pve-deprecated': return 'deprecated parameter';
case 'pve-incompatible': return 'ערווארטעט נומערישע ווערט';
case 'pve-no-such-name': return 'אומאַנערקענטע פאראמעטער';
case 'explain-pve': return 'פעלדער מיט פעלערן זענען אנגעצייכנט מיט ראָזעווע הינטערגרונט';
case 'pve-approve-close': return 'מוסטער אנטהאלט פעלערן. ביטע באשטעטיג ארויסגאנג';
}
}
return key;
}
function hebExplain() {
var explanation;
if (rawTemplate) return 'לתבנית "' + template + '" אין דף פרמטרים, ולכן לשדות אין תיאור.';
if (anyRequiredParam()) return 'שדות חובה מסומנים במסגרת אדומה';
return '';
}
function anyRequiredParam() {
for (name in templateParams) {
var param = templateParams[name];
if (param.options.required) return true;
}
return false;
}
function templatePage() {
var t = $.trim(template)
return t.match(':') ? t : mw.config.get('wgFormattedNamespaces')[10] + ':' + t;
}
function updateRawPreview() {
var canOK = 'enable';
for (var i in dialogFields) {
var df = dialogFields[i][1];
var opts = df.data('options');
if (opts && opts.required && $.trim(df.val()).length == 0)
canOK = 'disable';
if (opts && opts.depends) {
var dep = fieldsBypName[opts.depends];
var depEmpty = (dep && dep.val() && $.trim(dep.val())) ? false : true;
var row = rowsBypName[df.data('paramName')];
if (row)
row.toggleClass('tpw_hidden', depEmpty);
}
}
$('#asList').attr('disabled', $('#asRef').prop('checked'));//disable list if ref
$('#asRef').attr('disabled', $('#asList').prop('checked'));//disable ref if list
$(".ui-dialog-buttonpane button:contains('" + i18n('ok') + "')").button(canOK);
$('#tpw_preview').text(createWikiCode());
localStorage.setItem(localStorageKey + '.' + emptiesKey, $('#createEmpties').prop('checked'));
validate();
}
function validate() {
function validateField(param, input) {
function markError(msg) {
input
.addClass('tpw-paramvalidation')
.attr('title', i18n(msg));
return false;
}
var hasVal = !!input.val();
if (param.options.notInParamPage && hasVal) return markError('pve-no-such-name');
if (param.param.required && !hasVal) return markError('pve-required-empty');
if (param.param.deprecated && hasVal) return markError('pve-deprecated');
if (param.param.type === 'number' && isNaN(Number(input.val().replace(/,/g, '')))) return markError('pve-incompatible');
return true;
}
var aOK = true;
for (var i in dialogFields) {
var
field = dialogFields[i],
name = $.trim(field[0]),
input = field[1].removeClass('tpw-paramvalidation'),
param = templateParams[name];
aOK = validateField(param, input) && aOK;
}
$('#tpw-explain').html(i18n(aOK ? 'explain' : 'explain-pve'));
return aOK;
}
function createInputField(paramName) {
var params = templateParams[paramName],
options = params.options || {},
f,
checkbox = false;
if (options.choices) {
var choices = options.choices.split(/\s*,\s*/);
if (choices.length > 1) {
f = $('<select>').append($('<option>', { text: i18n('options select'), value: '' }));
for (var i in choices) {
var choice = choices[i].trim(); // first and last may carry spaces
var option = $('<option>', { text: choice, value: choice });
f.append(option);
}
}
else {
checkbox = true;
var choice = choices[0].trim();
f = $('<input>', { type: 'checkbox', value: choices[0], text: choices[0].trim() })
.css({ float: rtl ? 'right' : 'left' });
f.prop('checked', options.defval && options.defval.trim() == choices[0]);
}
}
else if (options.multiline) {
var rows = options.multiline;
f = $('<textarea>', { rows: 1 })
.focus(function () { this.rows = 5; })
.blur(function () { this.rows = 1 });
}
else
f = $('<input>', { type: 'text' });
if (!checkbox && f.autoCompleteWikiText) // teach the controls to autocomplete.
f.autoCompleteWikiText({ positionMy: rtl ? "left top" : "right top" });
f.css({ width: checkbox ? '1em' : '28em' })
.data({ paramName: paramName, options: options })
.on('paste cut drop input change', updateRawPreview);
if (options.defval && !checkbox)
f.val(options.defval.trim());
if (options.required)
f.addClass('tpw-required');
if (options.date)
f.datepicker({ dateFormat: typeof options.date == "string" ? options.date : i18n('dateFormat') });
return f;
}
var
timer = null,
lastVisited = $('<a>');
function enterTipsy() {
clearTimeout(timer);
$(this).attr('inside', 1);
}
function leaveTipsy() {
var $this = $(this);
if ($this.attr('master') || $this.attr('inside')) {
$this.attr('inside', '');
timer = setTimeout(function () { lastVisited.tipsy('hide'); }, 500);
}
}
function tipsyContent() {
var
paramName = $(this).data('paramname'),
def = templateParams[paramName],
desc = def && def.desc || '';
if (!def) return ''; // early terminate if param name is not valid
if (def.htmlDesc)
return def.htmlDesc;
if (wikiCodeFinder.test(desc)) // does it need parsing?
$.ajax({
url: mw.util.wikiScript('api'),
async: false,
type: 'post',
data: { action: 'parse', text: desc, disablepp: 1, format: 'json' }, // parse it.
success: function (data) {
var div = $('<div>').html(data.parse.text['*']);
$('a', div).attr({ target: '_blank' });
def.htmlDesc = div.html();
}
});
else
def.htmlDesc = desc;
return def.htmlDesc;
}
function addRow(paramName, table) {
var
def = templateParams[paramName],
inputField = createInputField(paramName),
nameColor = def.desc
? 'blue'
: def.options.notInParamPage
? 'red'
: def.options.isAlias
? 'green'
: 'black',
tr = $('<tr>')
.append(
$('<td>', { width: 120 })
.css({ fontWeight: 'bold', color: nameColor })
.data({ paramname: paramName })
.text(templateParams[paramName].label || paramName)
.tipsy({ html: true, trigger: 'manual', title: tipsyContent })
.mouseenter(function () {
clearTimeout(timer);
$('.tipsy').remove();
lastVisited = $(this);
lastVisited.tipsy('show');
})
.mouseleave(leaveTipsy)
.attr('master', 'true')
)
.append($('<td>').css({ width: '30em' }).append(inputField));
dialogFields.push([paramName, inputField]);
if (def.options.extended)
tr.addClass('tpw_extended');
table.append(tr);
rowsBypName[paramName] = tr;
fieldsBypName[paramName] = inputField;
}
function injectResults() {
$("#wpTextbox1").textSelection('encapsulateSelection', { replace: true, peri: createWikiCode() });
}
function createExtendedCheckBox() {
return $('<p>')
.text(i18n('extended labels'))
.append($('<input>', { type: 'checkbox' })
.change(function () {
extendedParamCssRule.disabled = $(this).prop('checked');
})
);
}
function buildDialog(data) {
var title = $('<span>').html(i18n('wizard dialog title', template));
$('.tpw_disposable').remove();
if (rawTemplate)
buildParamsRaw(data);
else if (tdTemplate) {
buildParamsTd(data);
if (data.description) title.find('a').attr({ title: data.description });
}
paramsFromSelection();
var table = $('<table>');
var dialog = $('<div>', { 'class': 'tpw_disposable' })
.dialog({
height: 'auto',
title: title.html(),
width: 'auto',
overflow: 'auto',
position: [$('body').width() * 0.2, $('body').height() * 0.1],
open: function () { $(this).css({ 'max-height': Math.round($('body').height() * 0.7) }); }
})
.append($('<div>', { id: 'tpw_globalExplanation' }).html(globalExplanation))
.append($('<p>', { id: 'tpw-explain' }).html(i18n('explain')))
.append(anyExtended ? createExtendedCheckBox() : '')
.append(table)
.append($('<p>')
.append(i18n('oneliner'))
.append($('<input>', { type: 'checkbox', id: oneLineTemplate }).prop('checked', isInline).change(updateRawPreview)
)
)
.append($('<p>')
.append(i18n('createempties'))
.append($('<input>', { type: 'checkbox', id: 'createEmpties' })
.change(updateRawPreview)
.prop('checked', localStorage.getItem(localStorageKey + '.' + emptiesKey) == "true")
)
)
.append($('<pre>', { id: 'tpw_preview' }).addClass('tpw-wikicode-preview'));
while (paramsOrder.length)
addRow(paramsOrder.shift(), table);
dialog.append($('<label>').text(' רעפערענץ '))
.append($('<input>', {type: 'checkbox', id: 'asRef'}).change(updateRawPreview))
.append($('<label>').css({width: '12em'}).text( ' אייטעם אין א ליסטע '))
.append($('<input>', {type: 'checkbox', id: 'asList'}).change(updateRawPreview));
var buttons = {}; // we need to do it this way, because with literal object, the keys must be literal.
buttons[i18n('ok')] = function () {
if (!validate() && !confirm(i18n('pve-approve-close'))) return;
injectResults();
dialog.dialog('close');
};
buttons[i18n('cancel')] = function () { dialog.dialog('close'); };
buttons[i18n('preview')] = showPreview;
dialog.dialog('option', 'buttons', buttons);
circumventRtlBug();
updateRawPreview();
$('.tipsy').hover(enterTipsy, leaveTipsy);
$(document).delegate('.ui-dialog', 'keyup', function (e) {
var target = e.target;
var tagName = target.tagName.toLowerCase();
tagName = (tagName === 'input' && target.type === 'button')
? 'button'
: tagName;
var isClickableTag = tagName !== 'textarea' &&
tagName !== 'select' &&
tagName !== 'button';
if (e.which === $.ui.keyCode.ENTER && isClickableTag) {
$(this).find('.ui-dialog-buttonset button').eq(0).trigger('click');
return false;
}
});
}
function init() {
template = null;
templateParams = {};
paramsOrder = [];
dialogFields = [];
rowsBypName = {};
fieldsBypName = {};
mw.util.addCSS(".tpw_hidden{display:none;}");
anyExtended = false;
extendedParamCssRule = extendedParamCssRule || mw.util.addCSS(".tpw_extended{display:none;}");
}
function reportError(a, b, error) {
var key;
if (typeof console != 'undefined') {
for (key in a)
if (typeof a[key] != 'function')
console.log(key + '=>' + a[key]);
console.log(b);
console.log(error);
}
alert(i18n('unknown error', error));
}
function pickTemplate(item) {
function okButtonPressed(e, ui) {
template = ui ? ui.item.value : selector.val();
fireDialog();
templateSelector.dialog("close");
}
var selector = $('<input>')
.css({ width: '28em' })
.autocomplete({
source: function (request, response) {
$.getJSON(
mw.util.wikiScript('api'),
{ action: 'opensearch', search: request.term, namespace: 10 },
function (data) {
if (data[1])
response($(data[1]).map(function (index, item) { return item.replace(/.*:/, ''); }));
}
);
},
select: okButtonPressed
});
var templateSelector = $('<div>').dialog({
title: i18n('template selector title'),
height: 'auto',
width: 'auto',
modal: true,
buttons: [
{ text: i18n('ok'), click: okButtonPressed },
{ text: i18n('cancel'), click: function () { templateSelector.dialog("close") } }
]
}).append(selector);
circumventRtlBug();
selector.focus();
}
function fireDialog() {
var readRaw = function () {
rawTemplate = true;
$.ajax({
url: mw.util.wikiScript(),
data: { title: templatePage(), action: 'raw' },
dataType: 'text',
success: buildDialog,
error: reportError
});
},
readTemplateData = function () {
$.ajax({
url: mw.util.wikiScript('api'),
data: { action: 'templatedata', titles: templatePage(), redirects: true, format: 'json', lang: mw.config.get('wgUserLanguage') },
dataType: 'json',
success: function (data) {
var found = false;
if (data && data.pages)
for (var pageid in data.pages) {
tdTemplate = true;
found = true;
buildDialog(data.pages[pageid]);
break;
}
if (!found)
readRaw();
},
error: readRaw
});
};
rawTemplate = false;
readTemplateData();
}
function templateContext() {
var selection = $("#wpTextbox1").textSelection('getSelection'),
caretPos, beforeText, afterText, templateStart, templateEnd;
// trust the user
if (selection.length > 0) {
return selection;
}
caretPos = $("#wpTextbox1").textSelection('getCaretPosition');
beforeText = $("#wpTextbox1").val().substr(0, caretPos);
afterText = $("#wpTextbox1").val().substr(caretPos);
templateStart = beforeText.lastIndexOf('{{');
templateEnd = afterText.indexOf('}}') + 2;
// only under opportunistic template context assumptions
if ($("#wpTextbox1").val().split('{').length != $("#wpTextbox1").val().split('}').length ||
(beforeText.split('{{').length === beforeText.split('}}').length) ||
(afterText.split('{{').length === afterText.split('}}').length))
return '';
if (beforeText.substr(templateStart, caretPos) == '{{הערה|' && templateEnd <= 4) // '1=}}'
return '';
// determine the start and the end of the template context
while (beforeText.substr(templateStart).split('{{').length <= beforeText.substr(templateStart).split('}}').length)
templateStart = beforeText.lastIndexOf('{{', templateStart - 1)
while (afterText.substr(0, templateEnd).split('{{').length >= afterText.substr(0, templateEnd).split('}}').length)
templateEnd = afterText.indexOf('}}', templateEnd) + 2;
// extend the selection to the current template context
$("#wpTextbox1").focus().textSelection('setSelection', {
start: templateStart,
end: caretPos + templateEnd
});
return $("#wpTextbox1").textSelection('getSelection');
}
function doIt() {
mw.loader.using(['jquery.ui', 'jquery.tipsy', 'jquery.textSelection', 'mediawiki.api'], function () {
init();
var match = templateContext().match(/^\{\{([^|}]*)/);
template = match ? $.trim(match[1]) : null;
if (template)
fireDialog();
else
pickTemplate();
});
}
function addToWikiEditor() {
$('#wpTextbox1').wikiEditor('addToToolbar', {
section: 'main',
group: 'insert',
tools: {
'templateParamsWizard': {
label: i18n('button hint'),
type: 'button',
icon: '//yi.hamichlol.org.il/w/load.php?modules=oojs-ui.styles.icons-editing-advanced&image=puzzle&format=rasterized&lang=yi',
action: { type: 'callback', execute: doIt }
}
}
});
}
if (mw.user.options.get('usebetatoolbar'))
mw.loader.using(['ext.wikiEditor'], function () {
if (typeof $.wikiEditor != 'undefined') {
if ($('#wikiEditor-ui-toolbar').length === 1) addToWikiEditor();//in case it loaded after toolbar initaliztion
else $('#wpTextbox1').on('wikiEditor-toolbar-doneInitialSections', addToWikiEditor);
}
});
else
$('div #toolbar').append( // "old style"
$('<img>', { src: '//upload.wikimedia.org/wikipedia/commons/e/eb/Button_plantilla.png', title: i18n('button hint'), 'class': 'mw-toolbar-editbutton' })
.css({ cursor: 'pointer' })
.click(doIt)
);
});