TemplateScript

From Meta, a Wikimedia project coordination wiki

TemplateScript is a powerful user script framework for adding custom one-click templates and scripts to your sidebar. Essentially:

  1. create templates (bits of text that can be inserted wherever you choose) or scripts (bits of JavaScript code that are executed);
  2. choose when they appear — always (even when reading), by namespace, action (like 'edit' or 'move'), or arbitrary conditions;
  3. click the sidebar link (or press the keyboard shortcut) to instantly insert your custom template or run your custom script.

It's compatible with all Wikimedia skins, common browsers, and both the standard wiki editor and CodeEditor.

Quick use[edit]

If you just want to use the regex editor, follow the instructions below:

  1. Copy the following code to your global.js page (for all wikis) or your common.js page (for Meta only).
    /**
     * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
     * @see [[meta:TemplateScript]]
     * @update-token [[File:Pathoschild/templatescript.js]]
     */
    mw.loader.load('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js');
    
  2. Refresh your browser to reload the JavaScript. (In Chrome or Firefox, press [CTRL] and [R] at the same time.)

This will add a navigation box labeled 'TemplateScript' at the bottom of your sidebar. (This is the default — you can add as many new links or navigation boxes you want.)

You can click the 'Regex editor' link to activate that example script. This tool lets you apply any number of regular expressions to the text, and save them for later use. For example, you could define a series of changes to close a request or update a template, then save those steps and apply them to any other page later. The regex editor looks like this:

The regex editor is just an example of what you can do — TemplateScript is really meant for you to create your own scripts and templates. A template is really just a bit of text that gets added to the page when you click on it (you can choose where it gets added). A script is a bit of JavaScript that gets run when you click its link, so you can do anything (the regex editor is just a script). You can also assign keyboard shortcuts to templates or scripts to use them more quickly.

Using TemplateScript[edit]

The easiest way to get started is to copy the 'welcome' example from the installation sample code, and change the name and text. To really delve in, you can read this documentation.

Installation[edit]

These steps let you create your own scripts and templates. (If you just want to use the regex editor, see Quick use above.)

  • To use TemplateScript for yourself:
  1. Copy the following code to your global.js page (for all wikis) or your common.js page (for Meta only).
    /**
     * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
     * @see https://meta.wikimedia.org/wiki/TemplateScript
     * @update-token [[File:Pathoschild/templatescript.js]]
     */
    // <nowiki>
    $.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
    	pathoschild.TemplateScript.add([
    		// add your own templates or scripts here
    		{ name: 'welcome', template: '{{subst:welcome}} ~~~~', position: 'after', editSummary: 'welcome!', forNamespaces: 'user talk' },
    	]);
    });
    // </nowiki>
    
  2. Refresh your browser to reload the JavaScript. (In Chrome or Firefox, press [CTRL] and [R] at the same time.)
  • To add it as a wiki gadget instead:
    1. Create MediaWiki:Gadget-Templatescript.js on that wiki with the code shown above.
    2. Add this line to MediaWiki:Gadgets-definition:
      TemplateScript[ResourceLoader|dependencies=mediawiki.util]|TemplateScript.js
    3. Create MediaWiki:Gadget-TemplateScript with this line:
      Add a 'regex editor' sidebar link which lets you write, apply, and save regex patterns ([[m:TemplateScript|documentation]]).

Adding templates[edit]

You add templates by calling pathoschild.TemplateScript.add({...}). For example, this little snippet creates a sidebar with the header "Being nice" and adds a link named "Welcome" to welcome users. It will add "{{subst:welcome}} ~~~~" to the edit box, and set the edit summary to "Welcome!".

pathoschild.TemplateScript.add({
	category: 'Being nice',
	name: 'Welcome',
	template: '{{subst:welcome}} ~~~~',
	position: 'after',
	editSummary: 'Welcome!',
	forNamespaces: 'user talk'
});

You can add many templates at once:

pathoschild.TemplateScript.add([
	{
		category: 'Being nice',
		name: 'Welcome',
		template: '{{subst:welcome}} ~~~~',
		position: 'after',
		editSummary: 'Welcome!',
		forNamespaces: 'user talk'
	},
	{
		category: 'Being nice',
		name: 'Hi',
		template: '{{subst:hi}} ~~~~',
		position: 'after',
		editSummary: 'Hi!',
		forNamespaces: 'user talk'
	}
]);

...and you can save characters by adding repeated fields as a second argument:

pathoschild.TemplateScript.add(
	[
		{ name:'Welcome', template:'{{subst:welcome}} ~~~~', editSummary:'Welcome!' },
		{ name: 'Hi', template:'{{subst:hi}} ~~~~', editSummary:'Hi!' }
	],
	{ category:'Being nice', position:'after', forNamespaces:'user talk' } // common fields
);

See #Options for a full list of options.

Adding scripts[edit]

The main power of TemplateScript is letting you write your own JavaScript using the script: option. This lets you do pretty much anything. Here's a simple script that replaces -- with , updates the edit summary, and clicks the 'show changes' button:

pathoschild.TemplateScript.add({
	name:'replace -- with —',
	script: function(editor) {
		editor
			.replace(/--/g, '—')
			.appendEditSummary('replaced -- with —')
			.clickDiff();
	}
});

Your script receives an editor object (though you don't have to use it). it helps you simplify your scripts, and let TemplateScript worry about (upcoming) compatibility with CodeEditor and VisualEditor. All the methods return the editor, so you can chain methods as shown above. Here's what it gives you:

Editor fields:
editor.action The action being performed on the page. This is almost equivalent to mw.config.get('wgAction'), except that it provides a more relevant value for some actions:
  • editing a page is edit instead of sometimes being submit;
  • moving a page is move instead of view;
  • Special:Block is block instead of view;
  • Special:EmailUser is emailuser instead of view.
Methods for any action:
editor.contains(search) Gets whether the main input contains a search value (which can be a literal string or regex).
editor.get() Gets the text from the main input.
editor.set(text) Overwrites the text in the main input with the specified text.
editor.prepend(text) Adds the specified text to the top of the main input.
editor.append(text) Adds the specified text to the bottom of the main input.
editor.replace(search, replace) Performs a regex search and replace against the main input.
editor.replaceSelection(text) or
editor.replaceSelection(function)
Replaces the highlighted text in the main input. You can pass in literal text, or a function which accepts the highlighted text and returns the new text. For example, this script wraps the highlighted text with <poem> tags:
editor.replaceSelection(function(selected) {
	return '<poem>' + selected + '</poem>';
});
editor.options({...}) Checks or unchecks options on the page. For example, mark an edit as minor and watch the page with editor.options({ minor: true, watch: true }). The keys can be the checkbox ID (like wpMinoredit) or an alias (one of minor or watch).
editor.escape(search) Replaces all search matches in the text with a unique code (like ~1439674555520.4~), and returns a state object that can be used to reverse the changes. This is useful when you want to exclude certain portions of the page (like templates or <nowiki> tags) from your subsequent changes. For example, this script removes single line breaks, except those within a template:
var escaped = editor.escape(/\{\{[^}]+\}\}/g);
editor
	.replace(/([^\n]+)\n([^\n]+)/g,'$1 $2',10) // remove newline characters in paragraphs (note: + is lazy and there is no backtracking)
	.replace(/(=+.+?=+) *([^\n]+)/g,'$1\n$2'); // place linebreak between headings and text
	.unescape(escaped);
editor.unescape(state) Given the state object returned by editor.escape(search), this restores all escaped portions of the text.
Methods just for editing a page:
editor.appendEditSummary(text) Adds a snippet of text to the edit summary. This will make sure it's only added once, and will try to insert it seamlessly. (For example, /* section */ will become /* section */ new text, but old text will become old text, new text).
editor.setEditSummary(text) Replaces the edit summary.
editor.clickDiff() Clicks the 'show changes' button.
editor.clickPreview() Clicks the 'show preview' button.
Advanced methods:
editor.for(selector) Returns an editor for the specified field, where selector is a jQuery selector or collection. This includes these generic methods describe above: contains(search), get(), set(text), prepend(text), append(text), replace(search, replace), and replaceSelection(...). For example, the English Wikisource can use it to edit the header input:
editor.for('#wpHeaderTextbox')
   .append('{{running header}}');

If selector matches several fields, only the first one will be edited.

See #Options for a full list of options.

Options[edit]

These are the options you can specify when adding a template/script. Only the name and template/script are required.

User interface and enabling:
option type default value purpose
name string (required) The name displayed as the sidebar link text.
enabled boolean true Whether this template is available.
category string 'TemplateScript' An arbitrary category name (for grouping templates into multiple sidebars), or null to use the default sidebar.
forActions string or string[] 'edit' The page action for which the template is enabled. You can enable it for one action (like forActions: 'edit'), several actions (like forActions: ['edit', 'move']), or any action (like forActions: '*').
forNamespaces mixed[] or int or string
(all namespaces) The namespaces in which the template is enabled. You can specify each namespace as a number (like 3), canonical name (like 'user talk'), or translated name (like '使用者'). You can specify one namespace (like forNamespaces: 'user talk') or multiple (like forNamespaces: ['user', 'user talk']).
accessKey string none A keyboard shortcut that will instantly apply the template or script. This should be a single key like 'x' or '1', which will be combined with your browser's shortcut sequence (for example, in Chrome you'd press ALT+x). See w:Wikipedia:Keyboard shortcuts for your browser's keyboard shortcut sequence.
tooltip string none A short explanation of the template or script, typically shown when you hover your cursor over the link.
Behaviour:
option type default value purpose
template string null The text to insert into the main input box.
position string 'cursor'
or 'replace'
The position at which to insert the template. The default value is 'cursor' when editing a page, and 'replace' in all other cases.
isMinorEdit boolean false Whether to mark the edit as minor (if applicable).
editSummary string null The edit summary to use (if applicable).
editSummaryPosition string 'replace' The position at which to insert the edit summary.
headline string null The subject or headline to use (if applicable). This appears when editing a page with &section=new in the URL.
headlinePosition string 'replace' The position at which to insert the headline.
Scripting:
option type default value purpose
script function null An arbitrary JavaScript function that is called after the template and edit summary are applied, but before autoSubmit. It is passed a reference to the script object.
scriptUrl string null The URL (or page name on the local wiki) of a JavaScript file to load before launching the script. This will only be loaded when the user activates the template, so you should wrap the script function if you're calling a loaded method directly:
pathoschild.TemplateScript.add({
	name: 'clean up',
	scriptUrl: 'User:Example/cleanup.js',
	script: function(editor) {
		cleanup(editor);
	}
});

Position values[edit]

The Position represents how text is added to an input.

value meaning
before Insert before the text.
after Insert after the text.
cursor Insert the template at the current cursor position (replacing the selected text, if any).
replace Replace the current text entirely.

As a gadget or framework[edit]

TemplateScript is designed to work well in gadgets and scripts. You can simply import it the same way, and it will cache itself and extend the first instance. This makes it well suited as a framework for your own scripts — it will take care of creating a navigation box and links for you, and the user can enable many similar gadgets and have all their tools neatly organised together without conflict.

For example, your amazing-gadget.js page might look like this:

/**
 * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
 * @see https://meta.wikimedia.org/wiki/TemplateScript
 * @update-token [[File:Pathoschild/templatescript.js]]
 */
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
	pathoschild.TemplateScript.add([
		{ category: 'Amazing Gadget', name: 'Do cool stuff', script: MyGadget.DoStuff }
	]);
});

And the user would load your script the normal way without knowing anything about TemplateScript:

/**
 * Amazing Gadget does some pretty cool stuff.
 * @see https://example.com/amazing-gadget
 */
mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:Example/amazing-gadget.js&action=raw&ctype=text/javascript');

And here's what the user would see:

Troubleshooting[edit]

  1. If something isn't working, try again with your browser's JavaScript console open. TemplateScript will log a warning if it detects a configuration issue, and errors may break any script on the page (even if they're from a different script).
  2. Ideally, you shouldn't deal with $('#wpTextbox1') directly; when CodeEditor and VisualEditor are on the page, that's not the main input! If the script helpers don't do what you need, use editor.get() to get the raw text and editor.set(text) to save new text.
  3. Don't use $element.text() or $element.html() to edit input boxes.
    Always use $element.val() to change input box content. The $element.text() or $element.html() methods modify the element HTML directly, not the current value — these will cause the user's changes to be lost.

Translation[edit]

TemplateScript can be translated into any language by loading a translation file before the main script. For example, this will load TemplateScript in French:

/**
 * TemplateScript adds configurable templates and scripts to the sidebar, and adds an example regex editor.
 * @see https://meta.wikimedia.org/wiki/TemplateScript
 * @update-token [[File:Pathoschild/templatescript.js]]
 */
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/fr.js');
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js');

TemplateScript has been translated into these languages:

language usage translators
bn/Bengali
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/bn.js');
Aftabuzzaman
ca/Catalan
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/ca.js');
Aleator
de/German
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/de.js');
Speravir
en/English no translation needed
es/Spanish
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/es.js');
MarcoAurelio
fr/French
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/fr.js');
Pathoschild
it/Italian
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/it.js');
Samuele Papa
ja/Japanese
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/ja.js');
CES1596
pt/Portuguese
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/pt.js');
He7d3r
ru/Russian
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/ru.js');
KPu3uC B Poccuu
sr-ec/Serbian (Cyrillic)
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/sr-ec.js');
Zoranzoki21
sr-el/Serbian (Latin)
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/sr-el.js');
Zoranzoki21
th/Thai
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/th.js');
ptsgrn
ur/Urdu
mw.loader.load('//tools-static.wmflabs.org/meta/scripts/i18n/ur.js');
محمد شعیب

If you'd like to add or correct a translation, follow the instructions in the sample file or contact Pathoschild for help.

Extending TemplateScript[edit]

Disabling the regex editor[edit]

TemplateScript includes a default tool called the regex editor (see live example), which lets you define any number of custom regular expressions and apply them to the text. You can disable this feature by adding the following code before TemplateScript:

mw.config.set('userjs-templatescript', { regexEditor: false });

This will apply everywhere. Don't do this in a gadget or shared script, because you'll override users' personal preferences.

Changing how the UI is rendered[edit]

TemplateScript adds template links to the MediaWiki sidebar by default, but you can add your own renderer plugins that generate alternative UIs. (You can have any number of plugins side-by-side.)

For example, let's say you want to add tools to the Visual Editor toolbar instead:

  1. Register a function that accepts a template object, adds the UI to the page, and returns a reference to the generated element. (Look at _renderSidebar in the source code for a good example — that's the entire default renderer.)
    pathoschild.TemplateScript.addRenderer('toolbar', function(template, instance) {
       // custom rendering logic
    });
    
  2. Specify your new renderer when adding a template or script:
    pathoschild.TemplateScript.add({
    	name:'...',
    	script: function(context) { ... },
    	renderer: 'toolbar'
    });
    

See also[edit]