მედიავიკი:Gadget-TemplateParamWizard.js
იერსახე
შენიშვნა: შენახვის შემდეგ შესაძლოა დაგჭირდეთ ბრაუზერის ქეშის გაწმენდა ცვლილებების სანახავად. Google Chrome, Firefox, Microsoft Edge და Safari: დააჭირეთ ⇧ Shift ღილაკს და შემდეგ - ღილაკს Reload.
// 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 we did not find "Parameters" page, so the parameters are extracted from template page itself. rawTemplate, 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; 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 = []; while ( true ) { // extract inner links, inner templates and inner params - we don't want to sptit those. var 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( /\s*\|\s*/ ); for ( var i in params ) { var param = params[ i ]; while ( true ) { var match = param.match( /\0(\d+)\0/ ); if ( !match || !match.length ) { break; } param = param.replace( match[ 0 ], specials[ parseInt( match[ 1 ], 10 ) - 1 ] ); } var paramPair = param.split( '=' ); var name = $.trim( paramPair.shift() ); if ( name && paramPair.length ) { templateParams[ name ] = templateParams[ name ] || { options: { notInParamPage: 1 } }; addParam( name ); $.extend( templateParams[ name ].options, { defval: paramPair.join( '=' ) } ); } } } function buildParamsRaw( data ) { var paramExtractor = /{{3,}(.*?)[<|}]/mg, m; while ( ( m = paramExtractor.exec( data ) ) ) { templateParams[ m[ 1 ] ] = { desc: '', options: { multiline: 5 } }; addParam( m[ 1 ] ); } } 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(); // look for |- this is wikitext for table row. if ( !( /^\|-/.test( line ) ) ) { continue; } line = lines.shift(); if ( line.indexOf( 'globalExplanation' ) + 1 ) { extractGlobalExplanation(); continue; } // wikitext for column if ( !line || !( /^\|/.test( line ) ) ) { 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'; for ( var i in dialogFields ) { var field = dialogFields[ i ], name = $.trim( field[ 0 ] ), f = field[ 1 ], hidden = f.parents( '.tpw_hidden' ).length, val = $.trim( f.val() ); if ( val == '' && f.attr( 'type' ) != 'checkbox' ) { continue; }// skip parameters with no value if ( f.attr( 'type' ) == 'checkbox' && !f.prop( 'checked' ) ) { val = ''; } par.push( name + '=' + val ); } return '{{' + par.join( delim + '|' ) + 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 'ka': 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 'კარგი'; 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 'Extended'; case 'button hint': return 'معالج وسائط القالب'; case 'able templates category name': 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 '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 'able templates category name': throw new Error( 'Must define category name for wizard-capable templates' ); 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 'dateFormat': return 'MM d, yy'; case 'extended labels': return 'Show all parameters'; } break; } return key; } function paramPage() { return mw.config.get( 'wgFormattedNamespaces' )[ 10 ] + ':' + $.trim( template ) + '/' + i18n( 'params subpage' ); } 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() ) ) ); 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() ); } function createInputField( paramName ) { var options = templateParams[ paramName ].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 } ) .data( { dispRows: isNaN( parseInt( rows ) ) ? 5 : rows } ) .focus( function () { this.rows = $( this ).data( 'dispRows' ); } ) .blur( function () { this.rows = 1; } ); } else { f = $( '<input>', { type: 'text' } ); } // teach the controls to autocomplete. if ( !checkbox && f.autoCompleteWikiText ) { 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' ).css( { border: '1px red solid' } ); } if ( options.date ) { f.datepicker( { dateFormat: typeof options.date === 'string' ? options.date : i18n( 'dateFormat' ) } ); } return f; } var timer = null, lastVisited = $( '<a>' ); function addRow( paramName, table ) { var def = templateParams[ paramName ], inputField = createInputField( paramName ), nameColor = def.desc ? 'blue' : ( def.options.notInParamPage ? 'red' : 'black' ), tr = $( '<tr>' ) .append( $( '<td>', { width: 120 } ) .css( { fontWeight: 'bold', color: nameColor } ) .text( paramName ) .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 { buildParams( 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>' ).html( i18n( 'explain' ) ) ) .append( anyExtended ? createExtendedCheckBox() : '' ) .append( table ) .append( $( '<p>' ) .append( i18n( 'oneliner' ) ) .append( $( '<input>', { type: 'checkbox', id: 'oneLineTemplate' } ).change( updateRawPreview ) ) ) .append( $( '<pre>', { id: 'tpw_preview' } ) .css( { backgroundColor: 'lightGreen', maxWidth: '40em', maxHeight: '8em', overflow: 'auto' } ) ); 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 () { injectResults(); dialog.dialog( 'close' ); }; buttons[ i18n( 'cancel' ) ] = function () { dialog.dialog( 'close' ); }; buttons[ i18n( 'preview' ) ] = showPreview; dialog.dialog( 'option', 'buttons', buttons ); circumventRtlBug(); updateRawPreview(); } 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 ) { 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() { function okButtonPressed() { template = 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() { rawTemplate = false; $.ajax( { url: mw.util.wikiScript(), data: { title: paramPage(), action: 'raw', ctype: 'text/x-wiki' }, success: buildDialog, cache: false, error: function () { rawTemplate = true; $.ajax( { url: mw.util.wikiScript(), data: { title: templatePage(), action: 'raw', ctype: 'text/x-wiki' }, success: buildDialog, error: reportError } ); } } ); } function doIt() { mw.loader.using( [ 'jquery.ui', 'jquery.textSelection'], function () { init(); var match = $( '#wpTextbox1' ).textSelection( 'getSelection' ).match( /^\{\{([^|}]*)/ ); template = match ? $.trim( match[ 1 ] ) : null; if ( template ) { fireDialog(); } else { pickTemplate(); } } ); } if ( mw.user.options.get( 'usebetatoolbar' ) ) { mw.loader.using( [ 'ext.wikiEditor' ], function () { if ( typeof $.wikiEditor !== 'undefined' ) { $( '#wpTextbox1' ).wikiEditor( 'addToToolbar', { section: 'advanced', groups: { wizards: { tools: { linkTemplatewizard: { label: i18n( 'button hint' ), type: 'button', icon: '//upload.wikimedia.org/wikipedia/commons/d/dd/Vector_toolbar_template_button.png', action: { type: 'callback', execute: doIt } } } } } } ); } } ); } 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 ) ); } } ); }