User:Evad37/Script modules
Draft proposal for reusable Javascript code to be stored in MediaWiki: namespace and be easily used in userscripts.
How it would work
Suppose you want some code to parse wikitext for templates, and return an array of nicely formatted objects like:
{
name: 'nameOfTemplate',
wikitext: '{{nameOfTemplate|foo|2=1+1=2|bar=qux}}',
parameters: [
{name: 1, value:'foo'},
{name:'2', value:'1+1=2'},
{name:'bar', value:'qux'}
]
}
The module code would stored at MediaWiki:Modules/templateParser.js and contain something like:
Window.exports.templateParser = function() {
var templateParser = function(wikitext) {
// ... lots of lines omitted ...
return result;
};
return templateParser;
})();
The Window.exports.moduleName defines what will be available to scripts that import the module. moduleName shall be the same as the subpage name but without the ".js". The value is set by an IIFE, which is wrapped around the whole module to prevent scope leakage. It would usually be either a function, or an object containing functions.
A userscript would access the template parser using code like this:
importScriptModule('templateParser').then(function(tParser) {
// `tParser` is the name we want to use for the module's `templateParser` function. We can choose any name we want.
// We can now use the code defined in that module, e.g.
var templateInfo = tParser('==See also==\n{{Commons category}}\n{{Portal-inline|JavaScript|size=tiny}}\n*[[JavaScript templating]]');
/* `templateInfo` now evaluates to:
[
{
name: 'Commons category',
wikitext: '{{Commons category}}',
parameters: []
},
{
name: 'Portal-inline',
wikitext: '{{Portal-inline|JavaScript|size=tiny}}',
parameters: [
{name: 1, value:'JavaScript'},
{name:'size', value:'tiny'}
]
}
]
*/
};
// `tParser` is not available out here.
To load several modules, use $.when()
. Access error message by using failFilter function in .then() e.g.
$.when(
importScriptModule('templateParser'),
importScriptModule('foobar')
).then(
function(tParser, foo) {
/* ... code using these modules goes here ... */
},
function(failMessage) {
/* Show an error message to the user. Perhaps using bubble notifications from mw.notify */
}
);
The code for the script enabling the importScriptModule function would be
window.exports = {};
window.importScriptModule = function(module) {
return mw.loader.using('mediawiki.util').then(function() {
if ( Window.exports[module] === undefined ) {
// Load module
return $.getScript(
'https://en.wikipedia.org/w/index.php?title=MediaWiki:Module/' +
mw.util.wikiUrlencode(module) +
'.js&action=raw&ctype=text/javascript'
);
}
// else module has already been loaded
return true;
)
.then( function() {
if ( Window.exports[module] === undefined ) {
throw new Error("Script module "+module" does not export anything!");
}
return Window.exports[module];
}, function() {
throw new Error("Failed to load script module "+module);
});
};
This should probably be an on-by-default gadget, as it is only useful for registered users.