Page MenuHomePhabricator

Add support for URLs to mw.loader.using
Closed, ResolvedPublic

Description

Hi!

It would be useful if RL could have a function similar to importScript() but which accepted two parameters:

  1. the page where the script is; and
  2. a callback function which is executed after the script is imported

mw.loader.load() supports urls but has no callback. mw.loader.using() has a callback but supports no urls.

Workaround
$.ajax( 'https// ...', { dataType: 'script', cache: true } ).then( .. )

Or

$.getScript( { url: 'https:// ...', cache: true } ).then( .. )

Event Timeline

bzimport raised the priority of this task from to Lowest.Nov 21 2014, 11:23 PM
bzimport set Reference to bz25962.
bzimport added a subscriber: Unknown Object (MLST).

mdale wrote:

to refine on that proposal, maybe resource loader supports name-spaced wikititles so its easy to load lots of them at once via the existing mw.load function. The old resource loader supported wiki titles by looking for the pretext "WT:" followed by the Title Name ... so you can do something like mw.load( ['WT:PageA', 'WT:PageB' ], callback ); and get all those wiki titles in a single resource loader request.

Would that work also for importing in one request scripts from two wikis, say one from wikisource.org and other from en.wikipedia.org?

mdale wrote:

I suppose you could namespace the wikititles... but that could become complicated to maintain and be a bit of a security nightmear. ie an admin on wiki X is not nessesarally an admin on wiki Y if script Z breaks on X wiki coming from Y wiki admin X cant update script :P

If we ever get to the point of having a "wikidata" site that hosts shared templates, then it would probably be a good place to host shared scripts as well. ( and limit shared user scripts to that domain ) ... Since interfaces and interactions could be built around the interconnection of templates with named dynamic named dom elements so it makes sense if we are sharing templates to be able to share user scripts as well.

In the mean time we could potentially make "commons" the shared host for scripts since most of the types of user scripts you would want to share currently scripts have to do with media files ( image Annotator, mwEmbed video subtitles etc )

I think this functionality will be best at home in the planned changes to mediaWiki.loader.load, which currently accepts one or more module names or a url (must start with http://) but is planned to be changed to accept one or more module names or an object which contains information about what to load, such as a url, wiki page, etc.

Back in the present live deployed environment, it's possible to use jQuery's getScript() which is comparable to importScriptURI(), but with a callback function.

Example:

$.getScript('http://meta.wikimedia.org/?title=User:Krinkle/Scripts/Countervandalism.js&action=raw&ctype=text/javascript', function() {

alert('Hello, script load was performed.');

});
See also: http://api.jquery.com/jQuery.getScript/

As for ResourceLoader, I don't know exactly what is going to change but the following works for modules that are defined:

mw.loader.using( 'module.name', funciton(){

// script loaded OK

}, function(){
// script loaded with Error
});

If not already the case, perhaps we can expand using() to also accept a URL and remember which urls are loaded already

mw.loader.using( 'http://meta.wikimedia.org/?title=User:Krinkle/Scripts/Countervandalism.js&action=raw&ctype=text/javascript', funciton(){

// script loaded OK

}, function(){
// script loaded with Error
});

Or, if not already, allow registering of new modules in the front-end and then load them with callback using using() like:

mw.loader.registerModle( 'krinkle.sample', 'http://meta.wikimedia.org/?title=User:Krinkle/Sample.js&action=raw&ctype=text/javascript', 'jquery.ui');
// jquery.ui being the dependancy

mw.loader.using( 'krinkle.sample', funciton(){

// script loaded OK

}, function(){
// script loaded with Error
});

Lots of ideas :)

There's already a complete system for registering modules, we just need to extend it to support loading external scripts too. All the dependency and versioning is already setup though.

The callback stuff is already in mediaWiki.loader.using( [ 'module1', 'module2' ], function() { callback code } ); . We'd just need to extend that to somehow accept URLs too.

mdale wrote:

Per Roan's latest comment, added 27023 as a dependent since loader.using callback will have to work for mediaWiki.loader.using to be useful in this context.

  • bug 27023 has been fixed (callback on loader functions is working now)
  • r88053 rewrote the structure the loading structure

Next step is to add support to mw.loader.using to use URLs right away.

As of r112665:

  • mw.loader.load accept a callback function[1]; and
  • mw.loader.using[2] doesn't accept urls

Per comments on
http://thread.gmane.org/gmane.science.linguistics.wikipedia.technical/52291
and on bug 27281 comment 2, I also don't see the point in sending more code to the users to duplicate only part of jQuery.getScript functionality (which is already sent to them).
Maybe the use of full urls on mw.loader.load should just be deprecated in favor of jQuery.getScript and keep mw.loader.load only for modules...

[1] http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/resources/mediawiki/mediawiki.js?revision=112665&view=markup#l1212

[2] http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/resources/mediawiki/mediawiki.js?revision=112665&view=markup#l1173

(In reply to comment #10)

As of r112665:

  • mw.loader.load accept a callback function[1]; and

I mean, it DOESN'T.

mdale wrote:

(In reply to comment #10)

Maybe the use of full urls on mw.loader.load should just be deprecated in favor
of jQuery.getScript and keep mw.loader.load only for modules...

I think it would be valuable to use a single entry point, you never know in the future some usages of the resource loader ( ie for external plugins ) may want to support both minified and non-minified access to external urls. Think about a wiki loading some modules from mediaWiki.org and wanting to be able to debug and or load things minified via a resource loader flag that lets you load external resources.

And so then guys?(In reply to comment #9)

  • bug 27023 has been fixed (callback on loader functions is working now)
  • r88053 rewrote the structure the loading structure

Next step is to add support to mw.loader.using to use URLs right away.

Has passed more than a year. When the support URLs will be possible?

As said before, it isn't a high priority because there is no need for it in the current ResourceLoader environment. Everything is module based.

Urls in mw.loader.load is only used by legacy wikibits.js code coming from importScriptURI and importStylesheetURI, with mw.loader.load(url, 'text/css').

And for anything that does need urls, $.getScript can be used with a nice Promise interface, which can be multiplexed with $.when to callback multiple urls.

(In reply to comment #10)

Maybe the use of full urls on mw.loader.load should just be deprecated in favor
of jQuery.getScript and keep mw.loader.load only for modules...

We probably won't remove it in MediaWiki as there is no gain in removing it, as we'd need a replacement somewhere else to still cover legacy importScriptURI and importStylesheetURI. But discouraging use of it, sounds good to me.

This would be useful for on-wiki user scripts. While we can do it with jQuery alone, it's not pretty:

$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', { dataType:'script', cache:true }).then(function() {
    ...
});

($.getScript isn't a suitable replacement, because it bypasses the browser's cache on every fetch.)

Krinkle renamed this task from Add support for URLs to mw.loader.using or callback to mw.loader.load to Add support for URLs to mw.loader.using.Nov 18 2016, 7:38 PM
Krinkle set Security to None.
Krinkle moved this task from Backlog to Accepted Enhancement on the MediaWiki-ResourceLoader board.
Krinkle removed a subscriber: wikibugs-l-list.
Peter removed Peter as the assignee of this task.Dec 22 2016, 8:42 PM

Is it possible to do smth like mw.loader.load( '//ru.wikipedia.org/w/load.php?modules=ext.gadget.editpageSummaryButtons' ); but for mw.loader.using?

I also ran into this issue. A (bad) workaround is to add the JavaScript code itself to MediaWiki:Common.js.

How are we supposed to add external JavaScript code that is a requirement for other code?

How are we supposed to add external JavaScript code that is a requirement for other code?

This is how you can load external code:

MediaWiki:Gadget-example.js

function init() {
  /* Code that depends on external script. */
}

$.ajax(
  'https://meta.wikimedia.org/w/index.php?title=MediaWiki:External-example.js&action=raw&ctype=text/javascript',
  { dataType: 'script', cache: true }
).then( init );
MediaWiki:Gadget-example.js

function init() {
  /* Code that depends on document-ready, external script, and some modules. */
}

$.when(
  $.ajax( 'https://meta.wikimedia.org/w/index.php?title=MediaWiki:External-example.js&action=raw&ctype=text/javascript', { dataType: 'script', cache: true } ),
  mw.loader.using([ 'mediawiki.util', 'oojs' ]),
  $.ready
).then( init );

Note that the request in this task is not about adding new functionality. You can already request external code (with callback) via $.ajax(), as shown above. This task is about creating an alias to that function under a different name so that it visually matches the other ways we load code (via "mw.loader"). I've accepted this feature request, but cannot currently prioritise it myself. It is also non-trivial in complexity due to how things work internally.

Change 487566 had a related patch set uploaded (by Evad37; owner: Evad37):
[mediawiki/core@master] Add support for script URLs to mw.loader.using

https://gerrit.wikimedia.org/r/487566

Krinkle edited projects, added Performance-Team; removed Performance-Team (Radar).

Moving to our workboard given it has now changed its assigned scope from authoring to reviewing, which is in-scope. Self-triaging as low priority (same as before) and in the backlog as a small thing to do whenever I have time.

Update: Per discussion on gerrit, the latest patch sets add a new mw.loader.usingScript(), rather than adding functionality for a separate use case to mw.loader.using.
With the proposed code, to specify a dependency on a external script you would use:

MediaWiki:Gadget-example1.js

function init() {
  /* Code that depends on external script. */
}

mw.loader.usingScript(
  'https://meta.wikimedia.org/w/index.php?title=MediaWiki:External-example.js&action=raw&ctype=text/javascript'
).then( init );
MediaWiki:Gadget-example2.js

function init() {
  /* Code that depends on document-ready, external script, and some modules. */
}

$.when(
  mw.loader.usingScript( 'https://meta.wikimedia.org/w/index.php?title=MediaWiki:External-example.js&action=raw&ctype=text/javascript' ),
  mw.loader.using( [ 'mediawiki.util', 'oojs' ] ),
  $.ready
).then( init );
Krinkle reassigned this task from Krinkle to Evad37.
Krinkle removed a project: Patch-For-Review.

Change 487566 merged by jenkins-bot:
[mediawiki/core@master] resourceloader: Add getScript() method for loading scripts with callback

https://gerrit.wikimedia.org/r/487566