JS2 Overview

JS2 is a next-generation framework for MediaWiki, intended to support our increasingly-complex needs to manage and load Javascript.

It contains a script loader that minimizes page loading times by minifying, compressing, and grouping JavaScript files. It provides a unified approach to translation of user messages in JavaScript-based interfaces. It includes JavaScript helpers for dynamically loading JavaScript libraries that provide interfaces as needed rather than the traditional approach of loading all JavaScript in-line. And finally it promotes structuring JavaScript as highly modular reusable components, with clean separation of configuration, invocation binding and interface code.

See also Media Projects Overview, MwEmbed.

Primary motivation
We need a script server to package language text into JavaScript. When a user invokes an interface component, say the add media wizard, we don't want to pull the entire interface code base and all the messages at once. Instead we just want to grab enough to display the current interface interaction. Once the user click on some tab, say the ‘archive.org search’, we then want to import the code to run the archive.org search and the localized messages specific to that interface component. In other words we don't want to package all the message text in the HTML output of the initial page because JavaScript interactions can result in many different interfaces being invoked from that context and we only want to load what is absolutely necessary on initial page display/load.

Another example: say you're on a view page. Then click “edit” on a section and we want to do that edit in-line (without going to another page). We now want to load the toolbar JavaScript all its dependences and localized msg text in a single gziped, minified and indefinitely-client-cached by SVN revision request. (Then we want to grab the actual section wiki-text via the API.)

JS2 Support Extension
The JS2 Support extension includes a ScriptLoader, mwEmbed javascript library and a repository for shared javascript like jquery.ui components.

The js2-work branch has been depreciated.

mwEmbed Stand Alone
You can learn more about mwEmbed and stand alone at kaltura html5 library page

This extension solely supports other extensions, and hence would be a good candidate for inclusion into core. Its built as an extension to enable development to move forward while the core integration is sorted out.

Developing with JS2
To add the base js2 library support simply add the following to your LocalSettings.php:

By default js2 support groups script and css requests. To disable script grouping in your localSettings.php set: $wgEnableScriptLoader = false;

If you want a fresh copy of all the scripts ( and to disable minification in when wgEnableScriptLoader= true you can set )

Using JS2 script-grouping with your extension
Once you include the extension you can use the following:

To add a javascript or css to the named paths ( so that the script loader can load it by name )

This lets you use the named-path for includes and gives you control over script grouping with the grouping argument. If for example your script is included on a set of special pages then you could create a bucket id string for that set to not mangle the cache of each special page.

If important that user-specific js like user-selected gadgets or user-custom pages are put into the user bucket. This is so in the future cookie based request can be issued for javascript browsers enabling us to send the same "cached" page to all logging users that share a base configuration. If you would like to keep compatibility with non-js2 extension support you can use the base outputPage addScriptFile method: This way regardless of if your running the js2support extension or not script-includes will continue to work. But you won't be able to control the script bucket, and the script-loader will have to guess what group to put it in.

Using JS2 with JS-modules
JS Modules are reusable sets of javascript that can be dynamically configured, loaded and executed in arbitrary application contexts. Javascript modules promote a clean separation of configuration, interface, and application flow. These modules define relative paths for assets and can be hosted inside extensions or optionally used in stand-alone javascript interfaces.

The use of "loaders" enables dynamic packaging of modules with the intent of avoiding multiple requests, for dynamically loaded interfaces.

To add a javascript Module to your extension you must supply the relative path to the module in your main extension .php file:

$wgExtensionJavascriptModules[ 'myJsModule' ] = 'extensions/myExtension/MyJsModule';

The root of your module should contain: loader.js ( "module loader" ) {moduleName}.i18n.php ( "mediaWiki localization format localization file" ) {libraryCode.js files} ( "library code" )

JS Module Components Overview
The three components of a js-module are "module loaders", "module activators" and "library code and assets".

for a given interface "module". The set of requested libraries can driven by site configuration, and user preferences. The requested set of modules can include core libraries like jquery.ui helpers.
 * "module loaders" define named paths and build the request set of the javascript and css assets

invoke the interface or application.
 * "module activators" Call the module loaders in a given application context and then

These libraries are driven by a given configuration.
 * "library code and assets" These consist of library code and assets that is the user interface or application.

Example Flow and File Contents
When an application wants to use a interface component it calls the module loader from its activator. The module loader checks relevant configuration, it then issues a single script-loader request that checks javascript application state for existing satisfied dependencies or native browser support it then retrieves all the needed javascript, css and localized message text for that interface. The returned javascript will be minfied and gziped and cached on the server. The activator gets a callback that the interface library is loaded, and can then use that interface.

Example Loader loader.js:
Loaders should define named class paths, named "module loader" functions and default configuration if appropriate. Style sheet assets should be named mw.style[ {styleName} ] this is so we can register the presence of style sheets in javascript and libraries can dynamically share style sheet components.

Example Library Code
The key thing to remember about library code is that it defines a named class ie: a file by name 'mw.Foo.js' would define a object named 'mw.Foo' ie something like:

Library code should operate off of global configuration mw.getConfig( 'configurationOption' ) and or local configuration ( where appropriate ) ie the constructor gets passed an options object that defines named value pairs of configuration or callbacks.

The other key thing to remember about library code is to handle localization in some way. The localization options are presented bellow

Localization
Each javascript module hosts a {moduleName}.i18n.php file that works with the existing mediaWiki translate system. Note when the script-loader populates the msg replacements it uses mediaWiki's wfGetMsg function so any database MediaWiki namespace strings will be included in your javascript messages.

You have three options for packaging messages in your javascript module

1) If your javascript module is simple and your interface is mostly set in a single file you may want to load all your msgs at once. You can get all the msgs in your javascript module's localization file by simply running: Putting this function call at the top of your primary library code javascript file will be replaced with all the msgs in your modules php localization file in the current language. NOTE you won't be able to pull in msgKeys that are hosted outside of your extension ( to do that you must list the keys you want at the top of the javascript file with localization option 2 )

2) If your code includes many sub-modules and you may want fine grain control over what messages are packaged when. You can define the set of msg keys it at the top of any javascript file. For example: Will be replaced by the script-loader with the localized msgs for every listed key.

3) If you are doing a lot of stand alone testing it can be faster to use a json array at the top of your javascript file.  Your javascript file then becomes your developer reference English messages. A maintenance scripts then copy your English fallbacks into the php localization file for the translate wiki scripts to work with.  Running the JS2Support maintenance script "mergeJavascriptMsgs.php" will sync javascript into phpt files. This is the most complicated setup, if your unsure use the first option and call: mw.includeAllModuleMessages; In your primary library code javascript.

Accessing Msgs in Javascript
The JS2 Localization system works similar to its php counterpart. It includes support for NaN undefineds transforms.

To get a message simply issue the call: Tight integration with jQuery means you can pass in jQuery replacements like so:

Plurals work the same way as in mediawiki. mwEmbed maintains a copy of every PLURAL transformation ported to javascript and dynamically packages the transformation as part of the localization script-loader request. A test suite of mediawiki vs javascript transformation for all 356 language keys is available. For more documentation see: mwEmbed/languages/mw.Language.js and mwEmbed/languages/mw.Parser.js

mwEmbed as a Gadget
mwEmbed works as a stand alone package as a gadget. The mwEmbed gadget description list the major parts of the gadget.

Debugging mwEmbed Gadget
By default mwEbed Gadget is optimized for a small package and few round trips to the server which can make it difficult to debug. To debug the mwEmbed gadget you will want to do the following:


 * 1) Disable the gadget and reference the script in your user js file.
 * 2) Add the &debug param to the script request and include it in your user javascript. ie:

Working on mwEmbed-Gadget
1) Like with debugging you will want to disable the gadget and move to a user-script include. But instead of referencing prototype server you should setup your own local server with a check out of mwEmbed Stand alone ie: 2) Once your user script file has been update, you should be able to directly modify the scripts in your code editor and run it directly on commons or en wiki with full source path preservation.

Developing a Gadget using mwEmbed
MwEmbed offers many convenient functions for mediaWiki javascript interfaces, and provied a shared repository of jquery.ui and useful jquery plugins.
 * 1) To use mwEmbed in your gadget you should first include the mwEmbed gadget ( try and use the exact same url as the gadget )
 * 1) Now once mwEmbed is ready, you can start using the mwEmbed functions

Example Gadget using mwEmbed
To quickly illustrate how mwEmbed streamlines mediaWiki javascript development, lets assume a gadget on commons wants to leave a message on a users en.wikipedia talk page.