אונטערשייד צווישן ווערסיעס פון "מעדיעוויקי:Gadget-TemplateParamWizard.js"

פון המכלול
קפיצה לניווט קפיצה לחיפוש
(בעסער אזוי)
צייכן: אַנולירונג
(/תיעוד, /קוד, /doc)
 
(32 מיטלסטע ווערסיעס פון 2 באַניצער נישט געוויזן.)
שורה 2: שורה 2:
//Written by [[User:קיפודנחש]]
//Written by [[User:קיפודנחש]]
"use strict";
"use strict";
if(($.inArray(mw.config.get('wgAction'), ['edit', 'submit'])+1) && ( !$('#wpTextbox1').prop( 'readonly' ) ) )
if (!$('#wpTextbox1').prop('readonly'))
$(function($) {
    $(function ($) {
// template parameter is an object with the following fields:
        // template parameter is an object with the following fields:
// desc: desciption string
        // desc: desciption string
// defval: default value (optional)
        // defval: default value (optional)
// options: object with optional fields:
        // options: object with optional fields:
//// multiline: number of lines
        //// multiline: number of lines
//// depends: another field's name
        //// depends: another field's name
//// required: boolean
        //// required: boolean
//// date: use JS date widget
        //// date: use JS date widget
//// choices: array of legal values for the field
        //// 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"
        //// extended: this field will not show on initial screen, and will appear once the user selects "show all fields"


var
        var
// templateParams is keyed by paramName.
            // templateParams is keyed by paramName.
templateParams,
            templateParams,
paramsOrder,
            paramsOrder,
// which template are we working on
            // which template are we working on
template,
            template,
// array of pairs - [paramName, inputField]
            // array of pairs - [paramName, inputField]
dialogFields,
            dialogFields,
// table rows keyed by paramName
            // table rows keyed by paramName
rowsBypName,
            rowsBypName,
// the fields, keyed by paramName
            // the fields, keyed by paramName
fieldsBypName,
            fieldsBypName,
// boolean, indicating the source of data is templatedata.
            // boolean, indicating the source of data is templatedata.
tdTemplate,
            tdTemplate,
// boolean, indicating the source of the data is analyzing the template page itself.
            // boolean, indicating the source of the data is analyzing the template page itself.
rawTemplate,
            rawTemplate,
isInline,
            isInline,
rtl = $('body').is('.rtl'),
            rtl = $('body').is('.rtl'),
// test to see if a string contains wikiCode and hence needs parsing, or cen be used as is.
            // test to see if a string contains wikiCode and hence needs parsing, or cen be used as is.
wikiCodeFinder = /[\[\]\{\}<>]/,
            wikiCodeFinder = /[\[\]\{\}<>]/,
globalExplanation = '',
            globalExplanation = '',
extendedParamCssRule,
            extendedParamCssRule,
anyExtended = false,
            anyExtended = false,
localStorageKey = 'templateParamWizard',
            localStorageKey = 'templateParamWizard',
emptiesKey = 'writeEmpties',
            emptiesKey = 'writeEmpties',
oneLineTemplate = 'oneLineTemplate',
            oneLineTemplate = 'oneLineTemplate',
allAliases = [];
            allAliases = [];


function addParam(name) {
        function addParam(name) {
if ($.inArray(name, paramsOrder) == -1)
            if ($.inArray(name, paramsOrder) == -1)
paramsOrder.push(name);
                paramsOrder.push(name);
}
        }


function paramsFromSelection() {
        function paramsFromSelection() {
var selection = $("#wpTextbox1").textSelection('getSelection').replace(/^\s*\{\{|\}\}\s*$/g, ''); //scrap the first {{ and last }}
            var selection = $("#wpTextbox1").textSelection('getSelection').replace(/^\s*\{\{|\}\}\s*$/g, ''); //scrap the first {{ and last }}
var specials = [],
            var specials = [],
match;
                match;
while (true) { //extract inner links, inner templates and inner params - we don't want to split those.
            while (true) { //extract inner links, inner templates and inner params - we don't want to split those.
match = selection.match(/(\{\{[^\{\}\]\[]*\}\}|\[\[[^\{\}\]\[]*\]\]|\[[^\{\}\]\[]*\])/);
                match = selection.match(/(\{\{[^\{\}\]\[]*\}\}|\[\[[^\{\}\]\[]*\]\]|\[[^\{\}\]\[]*\])/);
if (! match || ! match.length)
                if (!match || !match.length)
break;
                    break;
specials.push(match[0]);
                specials.push(match[0]);
selection = selection.replace(match[0], "\0" + specials.length + "\0");
                selection = selection.replace(match[0], "\0" + specials.length + "\0");
}
            }
var params = selection.split(/ *\| */);
            var params = selection.split(/ *\| */);
params.shift(); // remove the template name  
            params.shift(); // remove the template name  
var ordered = 0;
            var ordered = 0;
for (var i in params) {
            for (var i in params) {
var param = params[i];
                var param = params[i];
if ( ! /=/.test(param) ) {
                if (! /=/.test(param)) {
param = ++ordered + '=' + param;
                    param = ++ordered + '=' + param;
}
                }
var paramPair = param.split("=");
                var paramPair = param.split("=");
var name = $.trim(paramPair.shift());
                var name = $.trim(paramPair.shift());
if ( ! isNaN( name ) ) {
                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 }}
                    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('=');
                var val = paramPair.join('=');
while (true) {
                while (true) {
match = val.match(/\0(\d+)\0/);
                    match = val.match(/\0(\d+)\0/);
if (! match || ! match.length)
                    if (!match || !match.length)
break;
                        break;
val = val.replace(match[0], specials[parseInt(match[1], 10)-1]);
                    val = val.replace(match[0], specials[parseInt(match[1], 10) - 1]);
}
                }
if (name && paramPair.length) {
                if (name && paramPair.length) {
var tp = templateParams[name] =  
                    var tp = templateParams[name] =
templateParams[name] ||  
                        templateParams[name] ||
~allAliases.indexOf(name) && { param:{}, options: {isAlias: 1} } ||  
                        ~allAliases.indexOf(name) && { param: {}, options: { isAlias: 1 } } ||
{param: {}, options: { notInParamPage: 1}};
                        { param: {}, options: { notInParamPage: 1 } };
addParam(name);
                    addParam(name);
$.extend( tp.options, { defval: val } );
                    $.extend(tp.options, { defval: val });
if ( /\n/.test( val ) ) $.extend( tp.options, { multiline : 5 } );
                    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.
                    // 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 )
                    if (typeof tp.options.choices === 'string' && tp.options.choices.indexOf(val) < 0)
tp.options.choices += ( ', ' + val );  
                        tp.options.choices += (', ' + val);
}
                }
}
            }
}
        }


function buildParamsRaw(data) {
        function buildParamsRaw(data) {
var
            var
paramExtractor = /{{3,}(.*?)[<|}]/mg,
                paramExtractor = /{{3,}(.*?)[<|}]/mg,
m;
                m;
while (m = paramExtractor.exec(data)) {
            while (m = paramExtractor.exec(data)) {
var paramName = $.trim(m[1]);
                var paramName = $.trim(m[1]);
templateParams[paramName] = { desc: '', options: {multiline: 5}, label: paramName, param:{} };
                templateParams[paramName] = { desc: '', options: { multiline: 5 }, label: paramName, param: {} };
addParam(paramName);
                addParam(paramName);
}
            }
}
        }
function buildParamsTd(data) {
var params = data.params,
paramOrder = data.paramOrder;


function optionsOfParam(param) {
        function buildParamsTd(data) {
var options = {};
            var params = data.params,
if (param.required) options.required = true;
                paramOrder = data.paramOrder;
if (param.suggestedvalues && param.suggestedvalues.length) options.choices = param.suggestedvalues.join(',');
return options;
}


function onemore(name) {
            function optionsOfParam(param) {
var param = params[name];
                var options = {};
if (param.deprecated)  
                if (param.required) options.required = true;
return; // ignore deprecated parameters - pretend they are not in TD.
                if (param.suggestedvalues && param.suggestedvalues.length) options.choices = param.suggestedvalues.join(',');
templateParams[name] = {
                return options;
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
            function onemore(name) {
if (data.maps && data.maps.hasOwnProperty('wikidata') && mw.config.get('wgWikibaseItemId')) {
                var param = params[name];
var wikidataFormattedValues = $('<div>');
                if (param.deprecated)
for (var k in data.maps['wikidata']) {
                    return; // ignore deprecated parameters - pretend they are not in TD.
wikidataFormattedValues.append($('<span>', {id: k, text:'{{#property:' + k + '}}'}))
                templateParams[name] = {
}
                    desc: param.description || '',
$.post(
                    options: optionsOfParam(param),
mw.util.wikiScript('api'),
                    label: param.label || name,
{action: 'parse', text: wikidataFormattedValues.html(), disablelimitreport: 1, format: 'json', prop: 'text', title: mw.config.get('wgPageName')},
                    param: param
function(wbd) {
                };
if (!wbd || !wbd.parse || !wbd.parse.text) return;
                if (param.aliases) $.merge(allAliases, param.aliases); // collect alliases if there are any
for (var k in data.maps['wikidata']) {
                addParam(name);
var wikidataVal = $('#' + k, wbd.parse.text['*']).text(),
            }
field = fieldsBypName[data.maps['wikidata'][k]];
if (field)
field.prop('placeholder', wikidataVal);
}
}
);
}
}


function buildParams(data) {
            isInline = data.format === 'inline';
var
lines = data.split("\n"),
line;


function extractGlobalExplanation() {
            if (paramOrder && paramOrder.length)
line = line.replace(/[!\|][^\|]*\|/, '');
                for (var ind in paramOrder)
if (wikiCodeFinder.test(line))
                    onemore(paramOrder[ind]);
$.post(
            else // no order - take them as they come.
mw.util.wikiScript('api'),
                for (var paramname in params)
{action: 'parse', text: line, disablepp: 1, format: 'json'},
                    onemore(paramname);
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) {
            // derive placeholders for feilds derived from wikidata
line = lines.shift();
            if (data.maps && data.maps.hasOwnProperty('wikidata') && mw.config.get('wgWikibaseItemId')) {
if (!(/^\|-/.test(line))) // look for |- this is wikitext for table row.
                var wikidataFormattedValues = $('<div>');
continue;
                for (var k in data.maps['wikidata']) {
line = lines.shift();
                    wikidataFormattedValues.append($('<span>', { id: k, text: '{{#property:' + k + '}}' }))
if (line.indexOf('globalExplanation') + 1) {
                }
extractGlobalExplanation();
                $.post(
continue;
                    mw.util.wikiScript('api'),
}
                    { action: 'parse', text: wikidataFormattedValues.html(), disablelimitreport: 1, format: 'json', prop: 'text', title: mw.config.get('wgPageName') },
if (! line || ! (/^\|/.test(line))) //wikitext for column
                    function (wbd) {
continue;
                        if (!wbd || !wbd.parse || !wbd.parse.text) return;
line = line.substr(1); // get rid of the leading |
                        for (var k in data.maps['wikidata']) {
var fields = line.split('||');
                            var wikidataVal = $('#' + k, wbd.parse.text['*']).text(),
if (fields.length < 2)
                                field = fieldsBypName[data.maps['wikidata'][k]];
continue;
                            if (field)
var name = $.trim(fields[0]);
                                field.prop('placeholder', wikidataVal);
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;
        function buildParams(data) {
addParam(name);
            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;
            }


function analyzeOptions(str) {
            while (lines && lines.length) {
var res = {},
                line = lines.shift();
avail = ['multiline', 'required', 'depends', 'defval', 'choices', 'date', 'extended'], // maybe we'll have more in the future
                if (!(/^\|-/.test(line))) // look for |- this is wikitext for table row.
tavail = $.map(avail, i18n),
                    continue;
options = str.split(/\s*;\s*/);
                line = lines.shift();
for (var i in options) {
                if (line.indexOf('globalExplanation') + 1) {
var option = options[i].split(/\s*=\s*/);
                    extractGlobalExplanation();
var ind = $.inArray(option[0], tavail);
                    continue;
if (ind + 1)
                }
res[avail[ind]] = option.length > 1 ? option[1] : true;
                if (!line || !(/^\|/.test(line))) //wikitext for column
}
                    continue;
anyExtended = anyExtended || res.extended;
                line = line.substr(1); // get rid of the leading |
return res;
                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]));


function createWikiCode() {
                templateParams[name] = pAttribs;
var par = [template],
                addParam(name);
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);
}
return "{{" + par.join(delim + ($('#' + oneLineTemplate).prop('checked')? "|" : "| ")) + delim + "}}";
}


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() {
        function analyzeOptions(str) {
if (rtl)
            var res = {},
$('.ui-dialog-buttonpane button').css({float: 'right'}); // jQuery has problems with rtl dialogs + ie is braindamaged.
                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 i18n(key, param) {
        function createWikiCode() {
switch (mw.config.get('wgUserLanguage')) {
            var par = [template],
case 'ar':
                delim = $('#' + oneLineTemplate).prop('checked') ? '' : '\n',
switch (key) {
                paramValueDelim = $('#' + oneLineTemplate).prop('checked') ? '=' : ' = ',
case 'explain': return rawTemplate
                createEmpties = $('#createEmpties').prop('checked'),
? 'قالب "' + template + '" ليس له صفحة وسائط فرعية، لذلك فما من وصف لمعطياته.'
                mustNumberNameless,
: 'الوسائط الضرورية محددة بالأحمر والبقية اختيارية.';
                valuedOrdered;
case 'wizard dialog title': return 'وسائط ' + '<a href="' + mw.util.getUrl('قالب:' + template) + '" target="_blank">' + 'قالب:' + template + '</a>';
case 'ok': return 'موافقة';
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 'يلزمه';
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 'عرض كل الوسائط';
default: return key;
}
break;
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 'ur':
switch (key) {
case 'explain': return 'جو خانے لازمی ہیں ان کے گرد سرخ رنگ کی لکیر کھینچ دی گئی ہے، بقیہ خانے اختیاری ہوں گے۔';
case 'wizard dialog title': return 'سانچہ: "' + template + '" میں مطلوبہ معلومات درج کریں۔';
case 'ok': return 'ٹھیک';
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 'اس پر موقوف ہے';
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 'تمام پیرامیٹر دکھائیں';
}
break;
case 'ru':
switch (key) {
case 'explain': return 'поля с красной рамкой обязательны, остальные - по желанию';
case 'wizard dialog title': return 'Настройте параметры для шаблона: ' + template;
case 'ok': return 'OK';
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 'Зависит от';
case 'defval': return 'По умолчанию';
case 'choices': return 'Выбор';
case 'date': return 'Дата';
case 'extended': return 'Расширенный';
case 'button hint': return 'Мастер параметров шаблона';
case 'able templates category name': throw('Необходимо определить название категории для шаблонов с поддержкой мастера');
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 'dateFormat': return 'ММ дд, гг';
case 'extended labels': return 'Показать все параметры';
}
default:
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 filedך';
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';
}
}
return key;
}


function hebExplain() {
            for (var i = dialogFields.length - 1; i >= 0; i--) {
var explanation;
                var field = dialogFields[i],
if (rawTemplate) return 'לתבנית "' + template + '" אין דף פרמטרים, ולכן לשדות אין תיאור.';
                    val = $.trim(field[1].val());
if (anyRequiredParam()) return 'שדות חובה מסומנים במסגרת אדומה';
return '';
}
function anyRequiredParam() {
for (name in templateParams) {
var param = templateParams[name];
if (param.options.required) return true;
}
return false;
}
function templatePage() {return mw.config.get('wgFormattedNamespaces')[10] + ':' + $.trim(template);}


function updateRawPreview(){
                if (isNaN(field[0])) continue; // look only at order-based fields
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);
}
}
$(".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) {
                mustNumberNameless |=
var params = templateParams[paramName],
                    /=/.test(val) // order-based value containing "="
options = params.options || {},
                    || valuedOrdered && !val; // empty ordered w lower index than a non-empty one.
f,
                if (val) valuedOrdered = true;
checkbox = false;
            }


if (options.choices) {
            for (var i in dialogFields) {
var choices = options.choices.split(/\s*,\s*/);
                var
if (choices.length > 1) {
                    field = dialogFields[i],
f = $('<select>').append($('<option>', {text: i18n('options select'), value: '' }));
                    name = $.trim(field[0]),
for (var i in choices) {
                    f = field[1],
var choice = choices[i].trim(); // first and last may carry spaces
                    opts = f.data('options'),
var option = $('<option>', {text: choice, value: choice});
                    param = templateParams[name],
f.append(option);
                    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')
else {
                    val = val.replace(/\|/g, '{{!}}');
checkbox = true;
                if (f.attr('type') == 'checkbox' && !f.prop('checked'))
var choice = choices[0].trim();
                    val = "";
f = $('<input>', {type: 'checkbox', value: choices[0], text: choices[0].trim()})
                if ((!createEmpties || opts.notInParamPage) && $.trim(val) === "")
.css({float: rtl ? 'right' : 'left'});
                    continue;//skip parameters with no value
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.
                var next = mustNumberNameless || isNaN(name)
f.autoCompleteWikiText({positionMy: rtl ? "left top" : "right top"});
                    ? 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;
        }


f.css({width: checkbox ? '1em' : '28em'})
        function showPreview() {
.data({paramName: paramName, options: options})
            var temp = createWikiCode();
.on('paste cut drop input change', updateRawPreview);
            $.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();
                    }
                });
        }


if (options.defval && ! checkbox)
        function circumventRtlBug() {
f.val(options.defval.trim());
            if (rtl)
                $('.ui-dialog-buttonpane button').css({ float: 'right' }); // jQuery has problems with rtl dialogs + ie is braindamaged.
        }


if (options.required)
        function i18n(key, param) {
f.addClass('tpw-required');  
            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;
        }


if (options.date)
        function hebExplain() {
f.datepicker({dateFormat: typeof options.date  == "string" ? options.date : i18n('dateFormat')});
            var explanation;
            if (rawTemplate) return 'לתבנית "' + template + '" אין דף פרמטרים, ולכן לשדות אין תיאור.';
return f;
            if (anyRequiredParam()) return 'שדות חובה מסומנים במסגרת אדומה';
}
            return '';
        }


var
        function anyRequiredParam() {
timer = null,
            for (name in templateParams) {
lastVisited = $('<a>');
                var param = templateParams[name];
                if (param.options.required) return true;
            }
            return false;
        }


function enterTipsy() {
        function templatePage() {
clearTimeout(timer);
            var t = $.trim(template)
$(this).attr('inside', 1);
            return t.match(':') ? t : mw.config.get('wgFormattedNamespaces')[10] + ':' + t;
}
        }


function leaveTipsy() {
        function updateRawPreview() {
var $this = $(this);
            var canOK = 'enable';
if ($this.attr('master') || $this.attr('inside')) {
            for (var i in dialogFields) {
$this.attr('inside', '');
                var df = dialogFields[i][1];
timer = setTimeout(function(){lastVisited.tipsy('hide');}, 500);
                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 tipsyContent() {
        function validate() {
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) {
            function validateField(param, input) {
var
                function markError(msg) {
def = templateParams[paramName],
                    input
inputField = createInputField(paramName),
                        .addClass('tpw-paramvalidation')
nameColor = def.desc
                        .attr('title', i18n(msg));
? 'blue'
                    return false;
: 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() {
                var hasVal = !!input.val();
$("#wpTextbox1").textSelection('encapsulateSelection', {replace: true, peri: createWikiCode()});
                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;
            }


function createExtendedCheckBox() {
            var aOK = true;
return $('<p>')
            for (var i in dialogFields) {
.text(i18n('extended labels'))
                var
.append($('<input>', {type: 'checkbox'})
                    field = dialogFields[i],
.change(function() {
                    name = $.trim(field[0]),
extendedParamCssRule.disabled = $(this).prop('checked');
                    input = field[1].removeClass('tpw-paramvalidation'),
})
                    param = templateParams[name];
);
}


function buildDialog(data) {
                aOK = validateField(param, input) && aOK;
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);


var buttons = {}; // we need to do it this way, because with literal object, the keys must be literal.
            $('#tpw-explain').html(i18n(aOK ? 'explain' : 'explain-pve'));
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);
}


function init() {
            return aOK;
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) {
        function createInputField(paramName) {
var key;
            var params = templateParams[paramName],
if (typeof console != 'undefined') {
                options = params.options || {},
for (key in a)
                f,
if (typeof a[key] != 'function')
                checkbox = false;
console.log(key + '=>' + a[key]);
console.log(b);
console.log(error);
}
alert(i18n('unknown error', error));
}


function pickTemplate(item) {
            if (options.choices) {
function okButtonPressed(e, ui) {
                var choices = options.choices.split(/\s*,\s*/);
template = ui ? ui.item.value : selector.val();
                if (choices.length > 1) {
fireDialog();
                    f = $('<select>').append($('<option>', { text: i18n('options select'), value: '' }));
templateSelector.dialog("close");
                    for (var i in choices) {
}
                        var choice = choices[i].trim(); // first and last may carry spaces
var selector = $('<input>')
                        var option = $('<option>', { text: choice, value: choice });
.css({width: '28em'})
                        f.append(option);
.autocomplete({
                    }
source: function(request, response) {
                }
$.getJSON(
                else {
mw.util.wikiScript('api'),
                    checkbox = true;
{action:'opensearch', search: request.term, namespace: 10},
                    var choice = choices[0].trim();
function(data){
                    f = $('<input>', { type: 'checkbox', value: choices[0], text: choices[0].trim() })
if(data[1])
                        .css({ float: rtl ? 'right' : 'left' });
response($(data[1]).map(function(index,item){return item.replace(/.*:/, '');}));
                    f.prop('checked', options.defval && options.defval.trim() == choices[0]);
}
                }
);
            }
},
            else if (options.multiline) {
select: okButtonPressed
                var rows = options.multiline;
});
                f = $('<textarea>', { rows: 1 })
var templateSelector = $('<div>').dialog({
                    .focus(function () { this.rows = 5; })
title: i18n('template selector title'),
                    .blur(function () { this.rows = 1 });
height: 'auto',
            }
width: 'auto',
            else
modal: true,
                f = $('<input>', { type: 'text' });
buttons: [
{text: i18n('ok'), click: okButtonPressed},
{text: i18n('cancel'), click: function(){templateSelector.dialog("close")}}
]
}).append(selector);
circumventRtlBug();
selector.focus();
}


function fireDialog() {
            if (!checkbox && f.autoCompleteWikiText) // teach the controls to autocomplete.
var readRaw = function() {
                f.autoCompleteWikiText({ positionMy: rtl ? "left top" : "right top" });
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() {
            f.css({ width: checkbox ? '1em' : '28em' })
var selection = $("#wpTextbox1").textSelection('getSelection'),
                .data({ paramName: paramName, options: options })
caretPos, beforeText, afterText, templateStart, templateEnd;
                .on('paste cut drop input change', updateRawPreview);


// trust the user
            if (options.defval && !checkbox)
if ( selection.length > 0 ) {
                f.val(options.defval.trim());
return selection;  
}


caretPos =  $("#wpTextbox1").textSelection('getCaretPosition');
            if (options.required)
beforeText = $("#wpTextbox1").val().substr(0, caretPos);
                f.addClass('tpw-required');
afterText = $("#wpTextbox1").val().substr(caretPos);
templateStart = beforeText.lastIndexOf('{{');
templateEnd = afterText.indexOf('}}') + 2;


// only under opportunistic template context assumptions
            if (options.date)
if ( $("#wpTextbox1").val().split('{').length != $("#wpTextbox1").val().split('}').length ||
                f.datepicker({ dateFormat: typeof options.date == "string" ? options.date : i18n('dateFormat') });
  (beforeText.split('{{').length === beforeText.split('}}').length) ||
  (afterText.split('{{').length === afterText.split('}}').length) )  
return '';  


// determine the start and the end of the template context
            return f;
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)
        var
templateEnd = afterText.indexOf('}}', templateEnd) + 2;
            timer = null,
            lastVisited = $('<a>');


// extend the selection to the current template context
        function enterTipsy() {
$("#wpTextbox1").focus().textSelection('setSelection', {
            clearTimeout(timer);
start: templateStart,
            $(this).attr('inside', 1);
end: caretPos + templateEnd
        }
});
return $("#wpTextbox1").textSelection('getSelection');
}


function doIt() {
        function leaveTipsy() {
mw.loader.using(['jquery.ui','jquery.tipsy','jquery.textSelection', 'mediawiki.api'], function() {
            var $this = $(this);
init();
            if ($this.attr('master') || $this.attr('inside')) {
var match = templateContext().match(/^\{\{([^|}]*)/);
                $this.attr('inside', '');
template = match ? $.trim(match[1]) : null;
                timer = setTimeout(function () { lastVisited.tipsy('hide'); }, 500);
if (template)
            }
fireDialog();
        }
else
 
pickTemplate();
        function tipsyContent() {
});
            var
}
                paramName = $(this).data('paramname'),
function addToWikiEditor(){
                def = templateParams[paramName],
$('#wpTextbox1').wikiEditor('addToToolbar', {
                desc = def && def.desc || '';
section: 'main',
            if (!def) return ''; // early terminate if param name is not valid
group: 'insert',
            if (def.htmlDesc)
tools: {
                return def.htmlDesc;
'templateParamsWizard': {
            if (wikiCodeFinder.test(desc)) // does it need parsing?
label: i18n('button hint'),
                $.ajax({
type: 'button',
                    url: mw.util.wikiScript('api'),
icon: '//upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Template_alt_full_black_22.svg/22px-Template_alt_full_black_22.svg.png',
                    async: false,
action: {type: 'callback', execute: doIt}
                    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' });
if (mw.user.options.get('usebetatoolbar'))
                        def.htmlDesc = div.html();
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
else $( '#wpTextbox1' ).on( 'wikiEditor-toolbar-doneInitialSections', addToWikiEditor);
                def.htmlDesc = desc;
}
            return def.htmlDesc;
});
        }
else
 
$('div #toolbar').append( // "old style"
        function addRow(paramName, table) {
$('<img>', {src: '//upload.wikimedia.org/wikipedia/commons/e/eb/Button_plantilla.png', title: i18n('button hint'), 'class': 'mw-toolbar-editbutton'})
            var
.css({cursor: 'pointer'})
                def = templateParams[paramName],
.click(doIt)
                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($('<label>').text(' רעפערענץ '))
                .append($('<input>', { type: 'checkbox', id: 'asRef' }).change(updateRawPreview))
                .append($('<label>').css({ width: '12em' }).text(' אייטעם אין א ליסטע '))
                .append($('<input>', { type: 'checkbox', id: 'asList' }).change(updateRawPreview))
                .append($('<pre>', { id: 'tpw_preview' }).addClass('tpw-wikicode-preview'));
 
            while (paramsOrder.length)
                addRow(paramsOrder.shift(), table);
 
            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);
            var clicked = false;
            $(document).delegate('.ui-dialog', 'keyup', function (e) {
                if (clicked) return;
                //console.log("keyup");
                var target = e.target;
                console.log("target:", target);
                var tagName = target.tagName.toLowerCase();
 
                tagName = (tagName === 'input' && target.type === 'button')
                    ? 'button'
                    : tagName;
 
                var isClickableTag = tagName !== 'textarea' &&
                    tagName !== 'select' &&
                    tagName !== 'button';
 
                //console.log("tagName:", tagName);
                //console.log("isClickableTag:", isClickableTag);
 
                if (e.which === $.ui.keyCode.ENTER && isClickableTag) {
                    clicked = true;
                    //console.log("enter");
                    $(this).find('.ui-dialog-buttonset button').eq(0).trigger('click');
 
                    //console.log("Clicked button:" + $(this).find('.ui-dialog-buttonset button').eq(0).text());
 
                    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]) {
                                    var filteredArray = Array.from(data[1]).filter(function (str) { return !str.includes("/דאק") && !str.includes("/תיעוד") && !str.includes("/קוד") && !str.toLowerCase().includes("/doc")});
                                    response($(filteredArray).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)
            );
    });

יעצטיגע רעוויזיע זינט 21:58, 29 נאוועמבער 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($('<label>').text(' רעפערענץ '))
                .append($('<input>', { type: 'checkbox', id: 'asRef' }).change(updateRawPreview))
                .append($('<label>').css({ width: '12em' }).text(' אייטעם אין א ליסטע '))
                .append($('<input>', { type: 'checkbox', id: 'asList' }).change(updateRawPreview))
                .append($('<pre>', { id: 'tpw_preview' }).addClass('tpw-wikicode-preview'));

            while (paramsOrder.length)
                addRow(paramsOrder.shift(), table);

            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);
            var clicked = false;
            $(document).delegate('.ui-dialog', 'keyup', function (e) {
                if (clicked) return;
                //console.log("keyup");
                var target = e.target;
                console.log("target:", target);
                var tagName = target.tagName.toLowerCase();

                tagName = (tagName === 'input' && target.type === 'button')
                    ? 'button'
                    : tagName;

                var isClickableTag = tagName !== 'textarea' &&
                    tagName !== 'select' &&
                    tagName !== 'button';

                //console.log("tagName:", tagName);
                //console.log("isClickableTag:", isClickableTag);

                if (e.which === $.ui.keyCode.ENTER && isClickableTag) {
                    clicked = true;
                    //console.log("enter");
                    $(this).find('.ui-dialog-buttonset button').eq(0).trigger('click');

                    //console.log("Clicked button:" + $(this).find('.ui-dialog-buttonset button').eq(0).text());

                    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]) {
                                    var filteredArray = Array.from(data[1]).filter(function (str) { return !str.includes("/דאק") && !str.includes("/תיעוד") && !str.includes("/קוד") && !str.toLowerCase().includes("/doc")});
                                    response($(filteredArray).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)
            );
    });