Revision 272473 of "Utilizador:Helder.wiki/Tools/Pathoschild/TemplateScript.js" on ptwikibooks// Copied from https://tools.wmflabs.org/meta/scripts/pathoschild.templatescript.js
// See https://meta.wikimedia.org/wiki/TemplateScript
/*
TemplateScript adds a menu of configurable templates and scripts to the sidebar.
For more information, see <https://github.com/Pathoschild/Wikimedia-contrib#readme>.
*/
/*jshint bitwise:true, eqeqeq:true, forin:false, immed:true, latedef:true, loopfunc:true, noarg:true, noempty:true, nonew:true, smarttabs:true, strict:true, trailing:true, undef:true*/
/*global $:true, mw:true*/
/// <reference path="pathoschild.util.js" />
var pathoschild = pathoschild || {};
(function() {
'use strict';
if (pathoschild.TemplateScript)
return; // already initialized, don't overwrite
/*********
** TemplateScript
*********/
/**
* Singleton responsible for handling user-defined templates available through a sidebar menu.
* @author Pathoschild
* @class
* @property {Template[]} _templates The registered templates.
* @property {string} _defaultHeaderText The sidebar header text label for the default group.
* @property {Object} _menus A hash of menu references indexed by name.
* @property {int} _menuCount The number of registered menus (excluding the default menu).
* @property {boolean} _isReady Whether TemplateScript has been initialized and hooked into the DOM.
* @property {string} _revision The unique revision number, for debug purposes.
* @property {array} _dependencies An internal lookup used to manage asynchronous dependencies.
*/
pathoschild.TemplateScript = {
_version: '0.9.15-alpha',
/*********
** Objects
*********/
/**
* Represents an insertable template schema.
* @property {string} name The name displayed as the sidebar link text.
* @property {boolean} enabled Whether this template is available.
* @property {string} category An arbitrary category name (for grouping templates into multiple sidebars), or null to use the default sidebar.
* @property {string[]} forActions The wgAction values for which the template is enabled, or null to enable for all actions.
* @property {int[]} forNamespaces The namespaces in which the template is enabled, or null to enable in all namespaces.
*
* @property {string} template The template text to insert.
* @property {string} position The position at which to insert the template, matching a {pathoschild.TemplateScript.Position} value. The default value is 'cursor' when editing a page, and 'replace' in all other cases.
* @property {string} editSummary The edit summary to use (if applicable).
* @property {string} editSummaryPosition The position at which to insert the edit summary, matching a {pathoschild.TemplateScript.Position} value. The default value is 'replace'.
* @property {string} headline The subject or headline summary to use (if applicable). This appears when editing a page with §ion=new in the URL.
* @property {string} headlinePosition The position at which to insert the headline, matching a {pathoschild.TemplateScript.Position} value. The default value is 'replace'.
* @property {boolean} isMinorEdit Whether to mark the edit as minor (if applicable).
*
* @property {boolean} autoSubmit Whether to submit the form automatically after insertion.
* @property {function} script An arbitrary JavaScript function that is called after the template and edit summary are applied, but before autoSubmit is applied (if true). It is passed a reference to the context object.
*
* @property {int} id The internal template ID. (Modifying this value may cause unexpected behaviour.)
* @class
*/
Template: {
/* UI options */
name: null,
enabled: true,
category: null,
forActions: null,
forNamespaces: null,
/* template options */
template: null,
position: 'cursor',
editSummary: null,
editSummaryPosition: 'after',
headline: null,
headlinePosition: 'after',
isMinorEdit: false,
/* script options */
autoSubmit: false,
script: null,
/* internal */
id: null
},
/**
* Represents a text insertion method.
* @enum {string}
* @property {string} before Insert before the text.
* @property {string} after Insert after the text.
* @property {string} cursor Insert the template at the current cursor position (replacing any selected text).
* @property {string} replace Replace the current text entirely.
*/
Position: {
before: 'before',
after: 'after',
cursor: 'cursor',
replace: 'replace'
},
/**
* Provides convenient access to singleton properties about the current page. (Changing the values may cause unexpected behaviour.)
* @property {int} namespace The number of the current MediaWiki namespace.
* @property {string} action The string representing the current MediaWiki action.
* @property {pathoschild.TemplateScript} singleton The TemplateScript instance for the page.
* @property {jQuery} $target The primary input element (e.g., the edit textarea) for the current form.
* @property {jQuery} $editSummary The edit summary input element (if relevant to the current form).
*/
Context: {
namespace: mw.config.get('wgNamespaceNumber'),
action: (mw.config.get('wgAction') === 'submit'
? 'edit'
: (mw.config.get('wgCanonicalSpecialPageName') === 'Blockip'
? 'block'
: mw.config.get('wgAction')
)
),
isSectionNew: $('#wpTextbox1, #wpSummary').first().attr('id') === 'wpSummary', // if #wpSummary is first, it's not the edit summary (MediaWiki reused ID)
singleton: null,
$target: null,
$editSummary: null
},
/*********
** Properties
*********/
_isReady: false,
_templates: [],
_defaultHeaderText: 'TemplateScript',
_menus: {},
_menuCount: 0,
_queue: [],
/*********
** Private methods
*********/
/**
* Asynchronously load a script and invoke the callback when loaded.
* @param {string} url The URL of the script to load.
* @param {bool} test Indicates whether the dependency is already loaded.
* @param {function} callback The method to invoke (with no arguments) when the dependencies have been loaded.
*/
_LoadDependency: function(url, test, callback) {
var invokeCallback = function() { callback.call(pathoschild.TemplateScript); };
if (test)
invokeCallback();
else
$.ajax({ url:url, dataType:'script', crossDomain:true, cached:true, success:invokeCallback });
},
/**
* Initialize the template script.
*/
_Initialize: function() {
if (this.Context.singleton)
return;
// initialize
this.Context.singleton = this;
this.Context.$target = $('#wpTextbox1, #wpReason, #wpComment, #mwProtect-reason, #mw-bi-reason').first();
this.Context.$editSummary = $('#wpSummary:first');
// load utilities & hook into page
this._LoadDependency('//pt.wikibooks.org/w/index.php?title=User:Helder.wiki/Tools/Pathoschild/Util.js&action=raw&ctype=text/javascript', pathoschild.util, function() {
this._isReady = true;
for (var i = 0; i < this._queue.length; i++)
this.Add(this._queue[i]);
});
},
/**
* Get the unique ID for a TemplateScript sidebar portlet, creating it if necessary.
* @param {string} [name=null] The display name of the header to retrieve, or null to get the default sidebar.
* @returns {string} Returns the unique ID of the sidebar.
* @private
*/
_GetSidebar: function(name) {
// set default text
if (name === null || typeof(name) === typeof(undefined))
name = this._defaultHeaderText;
// create menu if missing
if (!(name in this._menus)) {
var id = this._menus[name] = 'p-templatescript-' + this._menuCount;
pathoschild.util.mediawiki.AddPortlet(id, name);
++this._menuCount;
}
/* return menu ID */
return this._menus[name];
},
/**
* Create a link in the sidebar that triggers the template.
* @param {pathoschild.TemplateScript.Template} template The template for which to create an entry.
*/
_CreateSidebarEntry: function(template) {
var id = this._GetSidebar(template.category);
pathoschild.util.mediawiki.AddPortletLink(id, template.name, function() { pathoschild.TemplateScript.Apply(template.id); });
},
/*
* Check whether the value is equal to the scalar haystack or in the array haystack.
* @param {Object} value The search value.
* @param {Object | Object[]} haystack The object to compare against, or array to search.
* @returns {boolean} Returns whether the value is equal to or in the haystack.
*/
_IsEqualOrIn: function(value, haystack) {
if ($.isArray(haystack))
return $.inArray(value, haystack) !== -1;
return value === haystack;
},
/*********
** Public methods
*********/
/*****
** Interface
*****/
/**
* Add templates to the sidebar menu.
* @param {pathoschild.TemplateScript.Template | pathoschild.TemplateScript.Template[]} opts The template(s) to add.
*/
Add: function(opts) {
if (!this._isReady) {
this._queue.push(opts);
return;
}
var log = function(message) {
opts = opts || {};
pathoschild.util.Log('pathoschild.TemplateScript::Add(name:"' + (opts.name || 'unnamed') + '"): ' + message);
};
/* handle multiple templates */
if ($.isArray(opts)) {
for (var t = 0; t < opts.length; t++)
this.Add(opts[t]);
return;
}
/* normalize option types */
try {
opts = pathoschild.util.ApplyArgumentSchema('pathoschild.TemplateScript::Add(name:' + (opts.name || 'unnamed') + ')', opts, this.Template);
opts.position = pathoschild.util.ApplyEnumeration('Position', opts.position, pathoschild.TemplateScript.Position);
opts.editSummaryPosition = pathoschild.util.ApplyEnumeration('Position', opts.editSummaryPosition, pathoschild.TemplateScript.Position);
opts.headlinePosition = pathoschild.util.ApplyEnumeration('Position', opts.headlinePosition, pathoschild.TemplateScript.Position);
}
catch (err) {
return log('normalization error: ' + err);
}
/* validate */
if (opts.script && !$.isFunction(opts.script)) {
log('ignoring non-function value passed to "script" option: ' + opts.script);
delete opts.script;
}
if (!opts.name)
return log('template must have a name');
if (!opts.template && !opts.script)
return log('template must have either a template or a script.');
if (!pathoschild.TemplateScript.IsEnabled(opts))
return;
/* set defaults */
if (!opts.position)
opts.position = (pathoschild.TemplateScript.Context.action === 'edit' ? 'cursor' : 'replace');
if (!opts.editSummaryPosition)
opts.editSummaryPosition = 'replace';
if (!opts.headlinePosition)
opts.headlinePosition = 'replace';
/* add template */
opts.id = this._templates.push(opts) - 1;
this._CreateSidebarEntry(opts);
},
/**
* Add templates to the sidebar menu.
* @property {pathoschild.TemplateScript.Template} fields A Template-like object containing fields to merge into the templates.
* @param {pathoschild.TemplateScript.Template | pathoschild.TemplateScript.Template[]} templates The template(s) to add.
* @return {int} Returns the identifier of the added template (or the last added template if given an array), or -1 if the template could not be added.
*/
AddWith: function(fields, templates) {
/* merge templates */
if (!$.isArray(templates))
templates = [templates];
for (var i in templates) {
for (var attr in fields)
templates[i][attr] = fields[attr];
}
/* add templates */
this.Add(templates);
},
/**
* Apply a template to the form.
* @param {int} id The identifier of the template to insert, as returned by Add().
*/
Apply: function(id) {
/* get template */
if (!(id in this._templates)) {
pathoschild.util.Log('pathoschild.TemplateScript::Apply() failed, there is no template with ID "' + id + '".');
return;
}
var opts = this._templates[id];
/* validate target input box */
if (!this.Context.$target.length) {
pathoschild.util.Log('pathoschild.TemplateScript::Apply() failed, no recognized form found.');
return;
}
/* insert template */
if (opts.template) {
this.InsertLiteral(this.Context.$target, opts.template, opts.position);
}
if (opts.editSummary && !this.Context.isSectionNew) {
this.InsertLiteral(this.Context.$editSummary, opts.editSummary, opts.editSummaryPosition);
}
if (opts.headline && this.Context.isSectionNew) {
this.InsertLiteral(this.Context.$editSummary, opts.headline, opts.headlinePosition);
}
if (opts.isMinorEdit) {
$('#wpMinoredit').attr('checked', 'checked');
}
/* invoke script */
if (opts.script) {
opts.script(this.Context);
}
/* perform auto-submission */
if (opts.autoSubmit) {
this.Context.$target.parents('form').first().submit();
}
},
/**
* Check whether the template is enabled for the current page context, based on its for* condition properties. This
* method also accepts an arbitrary object which exposes the for* property names from the Template interface.
* @param {pathoschild.TemplateScript.Template | Object} template
* @returns {boolean} Returns true if all for* conditions were met, or no conditions were found; else false.
*/
IsEnabled: function(template) {
/* check enabled flag */
if ('enabled' in template && template.enabled !== null && !template.enabled) {
return false;
}
/* match context values */
var context = pathoschild.TemplateScript.Context;
var is = pathoschild.TemplateScript._IsEqualOrIn;
if ('forNamespaces' in template && template.forNamespaces !== null && !is(context.namespace, template.forNamespaces)) {
return false;
}
if ('forActions' in template && template.forActions !== null) {
// workaround: moving a page doesn't have its own action
var action = context.action;
if(action == 'view' && $('#movepage').length) {
action = 'move';
}
if(!is(context.action, template.forActions)) {
return false;
}
}
return true;
},
/**
* Set the header text for the default sidebar text.
* @param {string} text The text to use as the sidebar text.
*/
SetDefaultGroupHeader: function(text) {
var id = this._GetSidebar();
this._defaultHeaderText = text;
this._menus[text] = id;
$('#' + id + ' h5').text(text);
},
/*****
** Framework
*****/
/**
* Insert a literal text into a field.
* @param {jQuery} $target The field into which to insert the template.
* @param {string} text The template text to insert, with template format values preparsed.
* @param {string} position The insertion position, matching a {pathoschild.TemplateScript.Position} value.
*/
InsertLiteral: function($target, text, position) {
/* validate */
if (!$target || !$target.length || !text || !text.length) {
return; // nothing to do
}
try {
position = pathoschild.util.ApplyEnumeration('Position', position, pathoschild.TemplateScript.Position);
}
catch (err) {
pathoschild.util.Log('TemplateScript: InsertLiteral failed, discarding literal: ' + err);
}
/* perform insertion */
switch (position) {
case this.Position.before:
$target.val(text + $target.val());
break;
case this.Position.after:
$target.val($target.val() + text);
break;
case this.Position.replace:
$target.val(text);
break;
case this.Position.cursor:
var box = $target.get(0);
box.focus();
/* most browsers */
if (box.selectionStart || box.selectionStart === '0') {
var startPos = box.selectionStart;
var endPos = box.selectionEnd;
var scrollTop = box.scrollTop;
box.value = box.value.substring(0, startPos) + text + box.value.substring(endPos, box.value.length);
box.focus();
box.selectionStart = startPos + text.length;
box.selectionEnd = startPos + text.length;
box.scrollTop = scrollTop;
}
/* Internet Explorer */
else if (document.selection) {
var selection = document.selection.createRange();
selection.text = text;
box.focus();
}
/* Unknown implementation */
else {
pathoschild.util.Log('TemplateScript: unknown browser cursor selection implementation, appending instead.');
box.value += text;
return;
}
break;
default:
pathoschild.util.Log('TemplateScript: insertion failed, unknown position "' + position + '".');
return;
}
}
};
// initialize menu (and wait for Vector if needed)
var init = function() { pathoschild.TemplateScript._Initialize(); };
var vectorModules = mw.config.get('wgVectorEnabledModules');
if (vectorModules && vectorModules.collapsiblenav)
mw.loader.using(['ext.vector.collapsibleNav'], function() { $(init); });
else
$(init);
pathoschild.TemplateScript.Add({
name: 'Regex editor',
script: function(context) {
pathoschild.TemplateScript._LoadDependency('//pt.wikibooks.org/w/index.php?title=User:Helder.wiki/Tools/Pathoschild/RegexEditor.js&action=raw&ctype=text/javascript', pathoschild.RegexEditor, function() {
pathoschild.RegexEditor.Create(context.$target);
});
},
forActions: 'edit'
});
}());All content in the above text box is licensed under the Creative Commons Attribution-ShareAlike license Version 4 and was originally sourced from https://pt.wikibooks.org/w/index.php?oldid=272473.
![]() ![]() This site is not affiliated with or endorsed in any way by the Wikimedia Foundation or any of its affiliates. In fact, we fucking despise them.
|