Talk:ResourceLoader/Core modules

Jump to navigation Jump to search

About this board

Archives 

Archive (until 2012)


Is there any way to callback after using load?

8
Eduemoni (talkcontribs)

I am trying to load a js file under my wiki

mw.loader.load( '/w/index.php?title=MediaWiki:Slick.js&action=raw&ctype=text/javascript' );


It loads the Slick jquery plugin, then after loading it I would like to use it as a gadget, where a wildcard number of classes can become a caroussel, however after loading it I am unable to use it, because the module is not loaded yet

Od1n (talkcontribs)

You could try the following:

mw.loader.implement( 'HackyCustomModuleRegistration', [ '/w/index.php?title=MediaWiki:Slick.js&action=raw&ctype=text/javascript' ] );
mw.loader.using( 'HackyCustomModuleRegistration', function () {
    // ...
} );

However, the mw.loader.implement() method (code) is missing from the documentation, and is to be considered private.

Jack who built the house (talkcontribs)

Won't this work for you?

$.getScript( 'https://.../w/index.php?title=MediaWiki:Slick.js&action=raw&ctype=text/javascript' ).done( function () {
    // your code
} );
Erutuon (talkcontribs)

Or even shorter:

$.getScript( 'https://.../w/index.php?title=MediaWiki:Slick.js&action=raw&ctype=text/javascript', function () {
    // runs if loading was successful
} );

Od1n (talkcontribs)

I thought it was a better solution… but from the jQuery.getScript() documentation (emphasis mine):

« The callback is fired once the script has been loaded but not necessarily executed. »

Erutuon (talkcontribs)

So if $.getScript(url, func) doesn't necessarily run the script before calling func, is the script run before func with $.getScript(url).done(func) or with the mw.loader version? I've used the $.getScript version that I posted without considering this issue; for whatever reason it worked fine.

Od1n (talkcontribs)

Digging inside the code of module mediawiki (and mediawiki.base), I found out the "load+execute script, then callback" code is actually very simple, see:

function addScript( src, callback ) {
    var script = document.createElement( 'script' );
    script.src = src;
    script.onload = script.onerror = function () {
        if ( script.parentNode ) {
            script.parentNode.removeChild( script );
        }
        script = null;
        if ( callback ) {
            callback();
            callback = null;
        }
    };
    document.head.appendChild( script );
}

A few notes about the code:

  • The two = null are for performance, to free memory (otherwise the objects would stay in memory forever)
  • The onerror event is not for request error, but for script execution error


So, I think the best solution would be to reuse the above snippet as standalone. Lightweight, no dependency of any kind :)

Od1n (talkcontribs)

For the sake of refs'ing, this implementation has been introduced in this commit (T192623).

Reply to "Is there any way to callback after using load?"
Prtksxna (talkcontribs)

Modules such as mediawiki.feedback and mediawiki.util have documentation both on this page and on jsDuck. Should we remove the one here, link to the API docs, and copy over stuff that is missing there (or these three things in some other order)?

Od1n (talkcontribs)

I was about to post the same thing, about mediawiki.api.* submodules. Documenting the individual methods (mw.Api#isCategory, etc.) here is cluttering, cumbersome, unmaintained and outdated. Whereas we could link to specific API pages (category, etc.) which is simple to do, more convenient to read on jsDuck, and always up-to-date. Ping Krinkle (by the way, I've done a handful of edits on this page today).

Krinkle (talkcontribs)

Yeah, any outdated or duplicated documentation here is fine to remove. I've been doing that for years, but it's a slow process.

If you find any method/class documentation or usage examples that missing from doc.wikimedia.org, they should be added there before removing here.

If you find any migration instructions on this page that are missing from RL/MGU, they should be added there before removing here.

Reply to "Duplicating documentation"
Erutuon (talkcontribs)

I tested this code on Wiktionary and it doesn't work.

Legoktm (talkcontribs)

Can you be more specific about what you tried and what isn't working? I just tested it and it works for me.

Erutuon (talkcontribs)

I copied the code from the above link verbatim into the Wiktionary user script sandbox, and called mw.notify on the return value. Error in the console: Uncaught TypeError: api.parse is not a function.

קיפודנחש (talkcontribs)

note that even though the code says

new mw.Api();

it's not enough to load module mediawiki.api: you need to load mediawiki.api.parse, like so:

1 mw.loader.using( 'mediawiki.api.parse' )
2 .done( function() {
3     new mw.Api().parse( {
4         // like the example.
5     });
6 }); // using..done

note that loading this module, will automatically load its dependencies i.e. mediawiki.api, so you don't have to load it explicitly, though it won't harm anything to do so anyway.

peace.

Erutuon (talkcontribs)

Thanks! That solved the problem. I'm puzzled, because I had loaded mw.api, but the function parse was still not present in the mw.Api object...

קיפודנחש (talkcontribs)

mediawiki.api has several such sub-modules, e.g., edit, watch, options, and some more (and prolly more to come).

each brings some specific set of functions, to make the interaction with specific area of the api more convenient to use.

to use them, you need to load the one you need specifically. loading any of them pulls mediawiki.api with it.

peace.

Collapse and Expand buttons do not show in mw-collapsible

2
Ken Roy (talkcontribs)

I am testing an upgrade of MW from 1.16.5 to 1.23.10. Previously we used ToggleDisplay2 to Collapse or Expand text sections on a page. I am trying to use the jQuery:makeCollapsible replacement, but I am not getting the [Collapse] and [Expand] button links.

What am I doing wrong? Do I need to add anything the MediaWiki:common.js? or to LocalSettings.php for the jQuery:makeCollapsible to work?

Ken Roy (talkcontribs)

This appears to be an issue in the Wikitext/Preview tab only, so I have disabled the WikiEditor preview.

Reply to "Collapse and Expand buttons do not show in mw-collapsible"
Danmichaelo (talkcontribs)

Should oojs be included in the list, or is it non-default?

Legoktm (talkcontribs)

Yes, it should be included in the list, it has been included in MediaWiki core since 1.23.

Mattflaschen-WMF (talkcontribs)

Done

Reply to "oojs"
124.181.108.69 (talkcontribs)

Can anyone explain why this is a constructor? As far as I understand, it's just a convenient wrapper for $.ajax, which isn't a constructor.

Also, what is the correct way to use this when there's multiple requests? Do I have to make a variable for each request (lest jshint whine at me for using new for "side effects"), or can I just use the one? Eg:

var api = new mw.Api();
api.get('foo');
api.get('bar');

(which seems to work fine, by the way)

Mattflaschen (talkcontribs)

The class is a wrapper around $.ajax. However, one of the pieces of functionality it adds is being able to store options that apply to all requests using the object (unless overridden by the individual request). See https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api . Your example above is not using new for side effects. In fact, the constructor really doesn't have side effects. It creates a mw.Api object, but to use that object for a network request, you need to call further methods (which the example above does).

This post was posted by Mattflaschen, but signed as Superm401.

124.181.106.190 (talkcontribs)

Alright, that seems useful in some cases. Thanks.

Reply to "mw.Api"

Can't tell what is a module name and what not

7
TMg (talkcontribs)

From this documentation I can't tell if I should write

  • mw.loader.using('mediawiki.user.options', fn),
  • mw.loader.using('mediaWiki.user.options', fn),
  • mw.loader.using('mw.user.options', fn),
  • mw.loader.using('user.options', fn), maybe
  • mw.loader.using('mediawiki.user', fn) or possibly
  • mw.loader.using('options', fn) (I'm pretty sure I saw this somewhere).

In short, the list is a mess. I can't tell the difference between module names and function names that are part of a module. Or is this the same? Can I use 'mediawiki.util.addCSS' as a module name even if it is a function? I can't tell. My proposed solution is to mark function calls with mediaWiki.a.b() and module names with 'mediawiki.a.b' (without the color, of course).

Also from what I know mw is a shortcut for mediaWiki and shouldn't be used in this list except for a single hint in the introduction. Or the other way around. But don't mix it, please.

Also I'm confused because it seems many of these mw.loader.using() calls are pointless. Things like mw.user.options.get() or mw.config.get() work anyway, everywhere. Under what circumstances do they not work? How to replicate these circumstances?

Mattflaschen (talkcontribs)

Bottom line, if it's a level three heading, it's a module. In the TOC, that's every heading like "d.dd some.module" (example: "1.4 mediawiki.api"). The number (1.4) is generated by the TOC, and doesn't matter except to tell you the heading depth. In the wikitext source, these have three equals signs on each side.

user.options is a little bit of an odd man odd in terms of the naming convention. However, you can see there is such a heading (currently "1.2 user.options"), and "user.options" is the module.

You can only use using with a module name, so you can not do things like using('mediawiki.util.addCSS'). Also, 'user.options' only works everywhere because something else on the page is depending on it. You get lucky like this sometimes. However, I try to explicitly depend on everything I need except two modules, 'mediawiki' and 'jquery'. Those two are always present.

The module names do look as you proposed in the TOC (except for quotes). I'm fine with adding () to the method headings. However, I don't want to invest too much work into this, since the goal is to replace it with auto-generated documentation relatively soon.

This post was posted by Mattflaschen, but signed as Superm401.

TMg (talkcontribs)

It would be very helpful to make the headings something like "Module <code>"mediawiki.api"</code>" to make things clear. Currently I can't tell the difference between the heading levels. They all look the same except for a slightly different font size. Even worse, things like "mediaWiki.config" are neither a module nor a function. "mediaWiki.config()" would be wrong. Please remove such stuff if it's neither an usable function name nor an usable module name. It doesn't add anything. It's just confusing. Also an overview of the dependencies would be helpful.

I'm not a friend of the resource loader stuff. It makes things so insanely complicated without adding much use. (It worked for years. Why change it? Do our Internet connections get slower?) Sometimes I consider the resource loader "broken by design". If no average user is able to write valid user scripts any more something must be broken.

Mattflaschen (talkcontribs)

That heading would break existing links, but you could do it if you add {{anchor}} with the old values. You kind of have a point about mediaWiki.config, but it is an object and needs to be documented somewhere.

The dependencies are in Resources.php, but generally you don't need to worry about that. You just depend on what you need. If you need to add stuff to the watchlist, you depend on mediawiki.api.watch. You don't need to worry about what it depends on.

I think the ResourceLoader is quite useful. There are two big reasons:

  • It handles minification and concatenation quite well, and some MediaWiki message (for i18n) cases (I am working on improving this).
  • It handles dependencies properly, and if you're writing an extension, or in MW core, the dependency interface is nice (you just specify an array of dependencies in a module definition). It is currently a bit of a pain for user scripts, though you can still pass an array of dependencies to using if there's more than one you need at the same time. Improving the user script and gadget experience is an important goal.

Since the good ol' days, MW has added a lot of useful scripts with various dependency chains. Further, other major sites have gotten faster through techniques like minification, and we need to do the same. RL also has other useful side features like flipping CSS automatically for right-to-left languages.

This post was posted by Mattflaschen, but signed as Superm401.

TMg (talkcontribs)

Thank you very much for the nice answer. After fighting every possible problem while maintaining my user script (which is also used by many other users) I think I understand most parts of that crazy nesting hell. (Except for the ready() stuff. I would really like to understand that.) Everything there is required for some reason: Make sure the options are loaded. Check one of the options. If it's enabled make sure an other module is loaded. Wait for it (I think that's what the ready() does but I don't understand how). Apply the button.

However, to make this usable for an average user there needs to be a simplified way to write it like this without loosing any functionality:

import('user.options');
if (mw.user.options.get('usebetatoolbar'))
{
    import('ext.wikiEditor.toolbar');
    $('#wpTextbox1').wikiEditor('addToToolbar', /* … */);
}
קיפודנחש (talkcontribs)

first, you don't import "user.options", but rather the module: "mediawiki.user", which, in turn, makes the *object* mw.user.options available to you.

second, because these resources are pulled from the web, it is usually not such a great idea to serialize it the way you suggest. in principle it *is* possible to do it the way you outlined (one would have to write a "synchronized import" function, which is totally possible), but it would mean that the browser will "freeze", and do nothing else (it might be responsive to user input, but it won't be able to execute any other JS stuff) while the browser goes and pulls the module off the server, however long that takes.

in the current mode (using the "using" method), the browser sends a request to the server to pull the module "mediawiki.user", and while the server prepares and sends the module, the browser is free to go and play elsewhere and do other stuff, such as figuring out what *else* is needed, and ask for it. once the module arrives from the server, the "using" triggers execution of the inside function.

think about it like this: javascript is single-threaded. the "using" and similar methods (such as "ready") allow it to pretend to be multithreaded, in the sense that while waiting for something to happen, it can go and do other stuff instead of wait idly.

peace.

TMg (talkcontribs)

I'm sorry but I do not care. All I want to do is to add a damn button to a toolbar. It has to wait anyway no matter how this stuff is loaded. This was a single (!) line of code with the old toolbar. Add button. Done. The current copy and paste garbage required to do the same is simply insane. It's not my job to put code that clearly belongs to the MediaWiki core into my user script.

Reply to "Can't tell what is a module name and what not"
He7d3r (talkcontribs)

I was wondering if the names of the modules on (section names on) this page shouldn't be using the same capitalization which is defined at /resources/Resources.php.

For example, "mediawiki.api" is the module name which should be used on e.g. mw.loader.using, but "mediaWiki.Api" is what someone would need to use inside of a JS code to access what is defined on that module.

Krinkle (talkcontribs)

I know what you mean. However this page primarily documents the code, not the module.

Main reason being that not all objects are in individual modules. Some modules provide multiple objects, others only extend existing ones.

Once we have migrated to a proper documentation system (RFC), we could include a piece of data showing which module(s) are required to use a function.

For now it is mainly documentation of the javascript code, not the module structure. But feel free to add that information :)

Mattflaschen (talkcontribs)

I'd certainly like to move to autogenerated (parsed along the lines of Doxygen) documention too. But until that happens, this should in fact document the modules. That means there should be a section for every module listed in Resources.php. Within that section, we should document any objects added or extended.

We should also fix the capitalization and spelling whenever discrepancies are noted.

This post was posted by Mattflaschen, but signed as Superm401.

Krinkle (talkcontribs)

@Superm401: Thanks for your recent reorganisation of the page. However a few minor points:

Your edits left the page in an inconsistent state. It used to be consistent. The section headings were capitalised after the javascript API they expose (e.g. Heading mediaWiki.Title is that way because the global variable is lowerCamelCase (window.mediaWiki) and the mediawiki.Title module defines mediaWiki.Title. These were not broken or discrepant.

You supposedly "fixed" some of them by changing them to their module namen and the result is an inconsistent mess where some are javascript identifiers, some are module names, and some are self-invented. Anchor links from other pages also stopped working properly (e.g. RL/DM#mediaWiki.Title no longer works).

Renaming headings like "api.get" to "mw.Api.get" introduced an incorrect and confusing image. Identifier "mw.Api.get" resolves to nothing. It is defined as "mw.Api.prototype.get". Referred to as "api.get" or "mw.Api#get" (where dot is a property, and hash a member of an instance, the constructed object from mw.Api) but not mw.Api.get since that is undefined.

Also don't include "?" or stuff "citation needed". If you're not sure, ask on the Talk page (this is not Wikipedia, we only deal with simple and verifiable facts).

I've fixed it now because it was easier to finish then to revert and let you fix it.

Mattflaschen (talkcontribs)

It's a work in progress, and I appreciate you continuing it.

There actually were some inconsistencies before. In this revision, I noticed (but there could have been more):

  • Some single-method scripts (mw.log) had nested headings while others did not (e.g. autoEllipsis, placeholder).
  • Some method headings had context (e.g. api.get) while others did not (e.g. addCSS).
  • Some method names weren't even headings (still true).
  • There was one random example heading, which I see you fixed.

Note that I've been adding modules and other information as well, which is part of what has been taking the time. There are still some missing modules. I may add them when I have an opportunity, but if I am able to get auto-generated documentation working, it will not be necessary.

I suggest we expand the TOC depth, perhaps to 4. I think there are some important methods (e.g. log, the loader methods) that are not shown currently. I realize this will make the TOC longer, but I think it's worth it.

Anyway, I'm glad we have been able to make it more usable.

This post was posted by Mattflaschen, but signed as Superm401.

Reply to "Capitalization of module names"
Krinkle (talkcontribs)
Krinkle (talkcontribs)

I tried to test this (on huwiki), but mw.user.tokens.get("editToken") returns "null". :( Any explanation is welcome. Winston 11:07, 22 January 2012 (UTC)

This post was posted by Krinkle, but signed as Winston.

Krinkle (talkcontribs)
Krinkle (talkcontribs)
50.34.49.172 (talkcontribs)

"See a live example..." at the bottom -- followed the link and it says "404 - Cannot find file" 50.34.49.172 00:55, 13 July 2012 (UTC)

Reply to "user.tokens"

jquery.jStorage saved data lost on logout

1
Cumbril (talkcontribs)

When user logs out of Wikipedia and in again, all data that was saved in browser locally through jquery.jStorage module is gone. Try the example code below. It saves Date() values at the page loading time and displays all saved values. Everything is perfect until you log out.

mw.loader.load( 'jquery.jStorage' );
$(document).ready(function(){
	var value = new Date();
	var key = value.getTime();	
	$.jStorage.set( key, value.toString() );
	var jSindex = $.jStorage.index();	
	var i;
	var txt = "You have loaded the script at following times:\n\n";	
	for	(i = 0; i < jSindex.length; i++) {
		txt += (i + 1) + ". " + $.jStorage.get(jSindex[i]) + ",\n";
	}
	alert (txt);
});
Reply to "jquery.jStorage saved data lost on logout"