User:✓/RL 3.0

This page is something like a general overview of my vision of mediawikis javascript infrastructure. It's a working sheet, feel free to contribute and/or discuss.

Symbol support vote.svg Pros
The ResourceLoader is a cool thing, no question, and has brought many improvements (see also requirements):
 * it's easy to use for extension developers
 * it has nice features like CSS Parsing and (debugable) minification
 * it encourages the use of JS namespacing

Symbol oppose vote.svg Contras
But there are also lots of drawbacks, especially when used for user scripts - of course the high traffic of anonymous users is handled already. This list may extend the task list of ResourceLoader/Version 2 Design Specification (better: Version 2.1 todo):
 * no support for loading wiki pages without full-action=raw-url - easy to fix
 * no support for using the RL dependency/load-events in userscripts, even when explicitly called. The current workaround is manual dependency resolving, using  (from de:Benutzer:Schnark/js/imagepopups.js)
 * or undocumented  as in User:PerfektesChaos/js/editToolStrIns/debug.js?
 * no support for internationalisation/customisation, the former only when it's a core/extension-added script. See also
 * no support for packaging userpages
 * the load/ready events for modules are not public. Many scripts could use such hooks: de:Benutzer:Schnark/js/wikieditor.js needs to check for existence of, the extra-editbuttons-gadgets uses very queer magic to execute in the right time, a script that extends the functionality of enhancedRecentChanges and expandedWatchList... just an example how I tried to code the last one:
 * Bug 28995 - Public interface for getting loader state of a ResourcerLoader module (mine :-) was a step in the right direction, but not far enough I had to find out.

deliberations

 * Most scripts are not even needed when loaded. Many begin with something like
 * But still, the whole script is loaded for each request. So two things for better code:
 * define only one function, not two or three event listeners. Don't define a function at all, just write a script which is automatically wrapped in a function.
 * define the rest somwhere else: dependencies, start, requirements


 * contains too much data. This should be split in  and , next to  . Getting a more dynamic page (inline editing, ajax page loader and other stuff), the static site stuff must consist on, while page, "view state" and even user could change
 * we should start providing general hooks for these changes, to prevent uncontrolled proliferation
 * the registration array of modules is already very long, many stay unused. If we're going to enable user modules and external modules, we won't be able to provide them all.
 * What are we going to do with MediaWiki:Common.js/.css, MediaWiki: .js/.css? mw.loader.using will get inefficient, when the module isn't pre-registered.
 * I have no idea how external modules would work. V2 Design says something about ForeignApiGadgetRepo. Might get crowded when we put all userscripts in :-) But I guess at WMF this would be centralised at bits. Elsewhile, there would need to be an interwiki-api for the module list, the usage statistics and message-receiving.

solution?
To come to a conclusion: user scripts and gadgets don't differ really from each other. They have the same aim, only gadgets are more popular. Therefore, gadgets may be presented in a selective list, while userscripts need to be searched for and added dynamically by typing their name into the preferences form.

So I'd propose to set up the following infrastructure:
 * We have a Specialpage "DefineResourceLoaderModule", needing no more rights than autoconfirmed.
 * you can define modules there, prefixed with the namespace "user. ."
 * If you have "gadgeteditor" rights (usually in group sysop, maybe an extra group), you can define modules with the prefix "gadget."
 * not sure whether to kick MediaWiki:gadgets-definition or not and show just all gadget modules. I think it's better to remove all the RL-options from it, and add the possibility to define internal and external gadget-modules. I can see no need for a "Gadget Manager", as proposed, in my vision setup.
 * All module settings are public, editable only by those who have the rights ("own" and "edituserjscss" for user modules, "gadgeteditor" for gadgets).
 * a module definition includes:
 * name: that identifier with the prefix (shouldn't change?)
 * short description: If it's a gadget, that description should be saved in MediaWiki Namespace (as usual, with the "name"), where it can be localised (rights "editinterface", "gadgettranslator"?). Userscripts dont get translations?
 * link to a help page: For userscripts, this defaults to the script/stylesheet subpage without suffix.
 * activation conditions: a set of conditions when to activate the module (see below), might be just a js function
 * list of scripts and stylesheets: Not to be forgotten :-) Their default names are the module name plus ".js"/".css" suffix, in User- respectively MediaWiki namespace.
 * each script has a start/position: in which loading state the function should be executed:
 * head (yea, please let me define that explicitly)
 * bottom
 * onDOMReady - no need for another jQuery(document).ready-bind, do it in RL
 * onSomethingelse
 * do stylesheets need any position information, like notasync?
 * translation: and of course, #3 type of resources; not applicable today. See also
 * you can add native systemmessages, maybe even with wildcards - don't use the MediaWiki ns for tool-specific messages. These messages might get loaded from the requester's wiki, even if the module is used as an external one.
 * add the name[s] of [a] page[s], whose iso-named subpages contain a (JSON) key-value-map. These pagenames must be user subpages or MediaWiki pages for gadgets. The data-pages are editable both with "gadgeteditor", "gadgettranslator" (and "editinterface"/"sysop") rights. There might be a nice frontend for declaring new or deprecating message names and translating, instead of editing json files.
 * To be exakt: for each of the translation definintions you should be able to choose whether the localisation is done on "contentlang" or "uselang".
 * each of the so-defined modules will build a resource-loader-group. It may be merged to another group when the enhance-other-module load condition is set.
 * How to output that? When a page is requested, ResourceLoader will get all addModules and user-activated modules, resolve their dependencies and save that list. On the flush of the output queue, RL will write a script containing the registration (with group, version, depencies, conditions), topmodules and the load call.
 * It might happen, that using or other dependency methods don't find a requested module registered. So then they will complete their work, then file a request with all unknown modules they found. The answer will include the registrations (just as the modules were added in the beginning), after that the methods can go on checking the conditions and eventually load the modules. Will that extra request get caching problems?


 * As said above, all gadgets are available in the respective section of Special:Preferences as a list, with their description, just to select with a checkbox - as already today. Then there is a pref section "custom modules". Here you can add any valid module names - own userscriptmodules (these already listed?), foreign usermodules, external (interwiki) usermodules and gadgets. A nice autocomplete, and when valid the description shows up :-)
 * The old /common.js, / .js, /common.css and / .css might work on. Or we autoconvert them into user modules, being loaded on-skin and in-head.
 * There should be some statistics, if not even public user settings about module usage. Today it is desired to add a out-commented wikilink behind every importScript call, give the script author a) an indication how widespread it is used and b) the possibility to inform users about breaking changes (especially in customisation). To publish the number of uses should be no problem, and we could offer a select for user modules (X) disable chance to get informed show my usage to script author[s]  I'm proud of using this, show it everybody

The load and execution conditions may contain: → or simply define a js function directly instead of the last three points, as any gui-definable logic won't be complex enough for some things. Otherwise a js function would be built out of that gui-defined logic.
 * nothing, to indicate the module is to be loaded always, or:
 * just a pointer to another module which we want to enhance, i.e. load alongside when it gets loaded
 * the dependencies to be fulfilled before execution (handle onReady as a dependency?)
 * the usual $wgPageState: wgPageName, wgSkin, wgCanonicalSpecialPageName, wgAction, wgNamespaceId etc
 * user.options user.customisation, I mean - options sounds useless
 * user.rights - interesting when I dynamically switch to my bot account

You might want to have a look at Schnarks jsmodules, a nice workaround for RL. In de:Benutzer:Schnark/js/modules.js you find the module definitions: version, link, description, dependencies, and some load condition functions.

customisation
I'm the sort of guy who wants to be able to change everything. From different toolbar icons up to a fully converted skin, it should be 1 script, many options. A really great example is User:PerfektesChaos/js/editToolStrIns. It does not only have everything you want, it runs into any problems you could run in (and survives :-).

I figured out that there are two directions: internationalisation/localisation and generalisation/customisation. You also have two types of variables in your script: messages and options. Sometimes, it might happen that especially external, imported messages need an site-scoped "update". I'm not sure if we could implement that with the same translation mechanism - any onwiki-defintion would be another module, maybe with dependencies? -, but there must to be a way to integrate some customised messages. At last, users would like to set up a script/module to customise messages on a per-user-basis; maybe not even language-specific but for all translations.
 * Messages
 * come from wfGetMessage respectively api.php?action=query&meta=allmessages of the current wiki, if they are system messages; which means that they are automatically fall-backed (unfortunately first from project to MW-default, then from bar to de - I'm not really lucky with that, nor anyone else is) and can be edited in site (wiki) scope. But modules may also store tool-specific messages in their own structures (described above). I'd propose them to be simple, complete JSON files, but when we allowed partial translation with fallbacks that would need an extra API / RL feature.

If the options were just one simple object, you might call  on it, done. If we had subobjects, we might use something like, as this doesn't overwrite object properties. But still it isn't suitable for maps (key-value-pairs), where we might want to remove keys but hold their values, in case the keys are added again by a more specific customisation. Experienced scripters would have made the value Object one setting (to merge in), and the keys another setting, an (ordered!) Array to overwrite/manipulate.
 * Options
 * are any other values that do not need to be translated. That could make it much easier, but it isn't, because options usually are complex objects. The default options can be hardcoded into the module logic, if the script is well-modularized they are exposed as a config object. The situation is quite the same, both at wiki and user scope there are settings to be integrated. But exactly that's what makes it difficult: integrate, not overwrite (as like for messages).

These config manipulations and language-fallback operations have to be handled by every script that does more than serving a library, and is imho the reason why scripts are not translated and shared. Particularly a config object might have more than 3 different setting integrations, e.g. a foreign script is translated to a different wiki, adapted by User:A, improved by User:B and specialised by User:C.

Especially because RessourceLoader makes the loading of different scripts (containing the setting options) asynchronous, a user script (most specific) can't be sure any more to be the last to manipulate a config object. Therefore, I think RL must include an interface to create such customisable configurations more easy, staying asynchronous and respect the priorities of different manipulations.