מדיה ויקי:Gadget-TemplateParamWizard.js
הערה: לאחר השמירה, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.
- פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload), או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
- גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
- אינטרנט אקספלורר: להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh), או ללחוץ על צירוף המקשים Ctrl-F5.
- אופרה: לפתוח תפריט ← הגדרות (במחשב מק: Opera ← העדפות) ואז ללחוץ על פרטיות ואבטחה ← מחק היסטוריית גלישה ← Cached images and files.
//Template parameters wizard //Written by [[User:קיפודנחש]] "use strict"; if(($.inArray(mw.config.get('wgAction'), ['edit', 'submit'])+1) && ( !$('#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 onemore(name) { var param = params[name]; templateParams[name] = { desc: param.description || '', options: { required: param.required }, 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. valuedOrdered |= val; } 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() { 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 'ar': switch (key) { case 'explain': return rawTemplate ? 'قالب "' + template + '" ليس له صفحة وسائط فرعية، لذلك فما من وصف لمعطياته.' : 'الوسائط الضرورية محددة بالأحمر والبقية اختيارية.'; 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; 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() { 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() {return mw.config.get('wgFormattedNamespaces')[10] + ':' + $.trim(template);} 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); } } $(".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) f.append($('<option>', {text: choices[i], value: choices[i]})); } else { checkbox = true; f = $('<input>', {type: 'checkbox', value: choices[0], text: choices[0]}) .css({float: rtl ? 'right' : 'left'}); f.prop('checked', options.defval && options.defval == 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) f.val(options.defval); 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).text(), 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}) .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) { $('.tpw_disposable').remove(); if (rawTemplate) buildParamsRaw(data); else if (tdTemplate) buildParamsTd(data); paramsFromSelection(); var table = $('<table>'); var dialog = $('<div>', {'class': 'tpw_disposable'}) .dialog({height: 'auto', title: i18n('wizard dialog title', template), 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. 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() { template = null; templateParams = {}; paramsOrder = []; dialogFields = []; rowsBypName = {}; fieldsBypName = {}; mw.util.addCSS(".tpw_hidden{display:none;}"); anyExtended = false; extendedParamCssRule = extendedParamCssRule || mw.util.addCSS(".tpw_extended{display:none;}"); } function reportError(a,b,error) { var key; if (typeof console != 'undefined') { for (key in a) if (typeof a[key] != 'function') console.log(key + '=>' + a[key]); console.log(b); console.log(error); } alert(i18n('unknown error', error)); } function pickTemplate(item) { function okButtonPressed(e, ui) { template = ui ? ui.item.value : selector.val(); fireDialog(); templateSelector.dialog("close"); } var selector = $('<input>') .css({width: '28em'}) .autocomplete({ source: function(request, response) { $.getJSON( mw.util.wikiScript('api'), {action:'opensearch', search: request.term, namespace: 10}, function(data){ if(data[1]) response($(data[1]).map(function(index,item){return item.replace(/.*:/, '');})); } ); }, select: okButtonPressed }); var templateSelector = $('<div>').dialog({ title: i18n('template selector title'), height: 'auto', width: 'auto', modal: true, buttons: [ {text: i18n('ok'), click: okButtonPressed}, {text: i18n('cancel'), click: function(){templateSelector.dialog("close")}} ] }).append(selector); circumventRtlBug(); selector.focus(); } function fireDialog() { var readRaw = function() { rawTemplate = true; $.ajax({ url: mw.util.wikiScript(), data: {title: templatePage(), action: 'raw'}, dataType: 'text', success: buildDialog, error: reportError }); }, readTemplateData = function() { $.ajax({ url: mw.util.wikiScript('api'), data: {action: 'templatedata', titles: templatePage(), redirects: true, format: 'json', lang: mw.config.get('wgUserLanguage') }, dataType: 'json', success: function(data) { var found = false; if (data && data.pages) for (var pageid in data.pages) { tdTemplate = true; found = true; buildDialog(data.pages[pageid]); break; } if (! found) readRaw(); }, error: readRaw }); }; rawTemplate = false; readTemplateData(); } function templateContext() { var selection = $("#wpTextbox1").textSelection('getSelection'), caretPos, beforeText, afterText, templateStart, templateEnd; // trust the user if ( selection.length > 0 ) { return selection; } caretPos = $("#wpTextbox1").textSelection('getCaretPosition'); beforeText = $("#wpTextbox1").val().substr(0, caretPos); afterText = $("#wpTextbox1").val().substr(caretPos); templateStart = beforeText.lastIndexOf('{{'); templateEnd = afterText.indexOf('}}') + 2; // only under opportunistic template context assumptions if ( $("#wpTextbox1").val().split('{').length != $("#wpTextbox1").val().split('}').length || (beforeText.split('{{').length === beforeText.split('}}').length) || (afterText.split('{{').length === afterText.split('}}').length) ) return ''; // 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: '//upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Template_alt_full_black_22.svg/22px-Template_alt_full_black_22.svg.png', 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) ); } );