Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
/*!
|
2015-12-10 16:07:50 +00:00
|
|
|
* VisualEditor MediaWiki ArticleTargetLoader.
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
*
|
2018-01-03 00:54:47 +00:00
|
|
|
* @copyright 2011-2018 VisualEditor Team and others; see AUTHORS.txt
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Target loader.
|
|
|
|
*
|
|
|
|
* Light-weight loader that loads ResourceLoader modules for VisualEditor
|
|
|
|
* and HTML and page data from the API. Also handles plugin registration.
|
|
|
|
*
|
|
|
|
* @class mw.libs.ve.targetLoader
|
|
|
|
* @singleton
|
|
|
|
*/
|
|
|
|
( function () {
|
|
|
|
var prefName, prefValue,
|
2016-12-31 17:02:33 +00:00
|
|
|
uri = new mw.Uri(),
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
conf = mw.config.get( 'wgVisualEditorConfig' ),
|
|
|
|
pluginCallbacks = [],
|
2017-02-27 16:13:56 +00:00
|
|
|
modules = [ 'ext.visualEditor.articleTarget' ]
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
// Add modules from $wgVisualEditorPluginModules
|
2016-07-13 14:47:30 +00:00
|
|
|
.concat( conf.pluginModules.filter( mw.loader.getState ) );
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
|
2016-09-01 19:04:54 +00:00
|
|
|
// Provide the new wikitext editor
|
2016-10-04 22:48:43 +00:00
|
|
|
if (
|
|
|
|
conf.enableWikitext &&
|
|
|
|
(
|
|
|
|
mw.user.options.get( 'visualeditor-newwikitext' ) ||
|
2016-12-31 17:02:33 +00:00
|
|
|
uri.query.veaction === 'editsource'
|
2016-11-05 05:50:32 +00:00
|
|
|
) &&
|
|
|
|
mw.loader.getState( 'ext.visualEditor.mwwikitext' )
|
2016-10-04 22:48:43 +00:00
|
|
|
) {
|
2016-05-26 12:08:26 +00:00
|
|
|
modules.push( 'ext.visualEditor.mwwikitext' );
|
|
|
|
}
|
|
|
|
|
2015-11-08 17:05:33 +00:00
|
|
|
// Allow signing posts in select namespaces
|
|
|
|
if ( conf.signatureNamespaces.length ) {
|
|
|
|
modules.push( 'ext.visualEditor.mwsignature' );
|
|
|
|
}
|
|
|
|
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
// Add preference modules
|
|
|
|
for ( prefName in conf.preferenceModules ) {
|
|
|
|
prefValue = mw.user.options.get( prefName );
|
|
|
|
// Check "0" (T89513)
|
|
|
|
if ( prefValue && prefValue !== '0' ) {
|
2015-08-19 17:33:02 +00:00
|
|
|
modules.push( conf.preferenceModules[ prefName ] );
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-18 00:38:29 +00:00
|
|
|
mw.libs.ve = mw.libs.ve || {};
|
|
|
|
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
mw.libs.ve.targetLoader = {
|
|
|
|
/**
|
|
|
|
* Add a plugin module or callback.
|
|
|
|
*
|
|
|
|
* If a module name is passed, that module will be loaded alongside the other modules.
|
|
|
|
*
|
|
|
|
* If a callback is passed, it will be executed after the modules have loaded. The callback
|
|
|
|
* may optionally return a jQuery.Promise; if it does, loading won't be complete until
|
|
|
|
* that promise is resolved.
|
|
|
|
*
|
|
|
|
* @param {string|Function} plugin Plugin module name or callback
|
|
|
|
*/
|
|
|
|
addPlugin: function ( plugin ) {
|
|
|
|
if ( typeof plugin === 'string' ) {
|
|
|
|
modules.push( plugin );
|
|
|
|
} else if ( $.isFunction( plugin ) ) {
|
|
|
|
pluginCallbacks.push( plugin );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load modules needed for VisualEditor, as well as plugins.
|
|
|
|
*
|
|
|
|
* This loads the base VE modules as well as any registered plugin modules.
|
|
|
|
* Once those are loaded, any registered plugin callbacks are executed,
|
|
|
|
* and we wait for all promises returned by those callbacks to resolve.
|
|
|
|
*
|
2017-12-07 11:14:00 +00:00
|
|
|
* @param {string} mode Initial editor mode, for tracking
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
* @return {jQuery.Promise} Promise resolved when the loading process is complete
|
|
|
|
*/
|
2017-12-07 11:14:00 +00:00
|
|
|
loadModules: function ( mode ) {
|
|
|
|
ve.track( 'trace.moduleLoad.enter', { mode: mode } );
|
2015-04-03 20:38:39 +00:00
|
|
|
return mw.loader.using( modules )
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
.then( function () {
|
2017-12-07 11:14:00 +00:00
|
|
|
ve.track( 'trace.moduleLoad.exit', { mode: mode } );
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
pluginCallbacks.push( ve.init.platform.getInitializedPromise.bind( ve.init.platform ) );
|
|
|
|
// Execute plugin callbacks and collect promises
|
|
|
|
return $.when.apply( $, pluginCallbacks.map( function ( callback ) {
|
|
|
|
return callback();
|
|
|
|
} ) );
|
|
|
|
} );
|
2015-03-13 15:50:23 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2017-01-02 18:40:07 +00:00
|
|
|
* Request the page data and various metadata from the MediaWiki API (which will use
|
2015-09-14 16:13:31 +00:00
|
|
|
* Parsoid or RESTBase).
|
2015-08-19 18:21:01 +00:00
|
|
|
*
|
2016-05-26 12:08:26 +00:00
|
|
|
* @param {string} mode Target mode: 'visual' or 'source'
|
2015-11-10 17:50:19 +00:00
|
|
|
* @param {string} pageName Page name to request
|
2017-09-11 14:53:50 +00:00
|
|
|
* @param {Object} [options] Options
|
2018-02-21 22:58:50 +00:00
|
|
|
* @param {boolean} [options.sessionStore] Store result in session storage (by page+mode+section) for auto-save
|
2017-09-11 14:53:50 +00:00
|
|
|
* @param {number|string} [options.section] Section to edit, number or 'new' (currently just source mode)
|
|
|
|
* @param {number} [options.oldId] Old revision ID. Current if omitted.
|
|
|
|
* @param {string} [options.targetName] Optional target name for tracking
|
|
|
|
* @param {boolean} [options.modified] The page was been modified before loading (e.g. in source mode)
|
|
|
|
* @param {string} [options.wikitext] Wikitext to convert to HTML. The original document is fetched if undefined.
|
2017-09-14 20:08:09 +00:00
|
|
|
* @param {string} [preload] Name of a page to use as preloaded content if pageName is empty
|
|
|
|
* @param {Array} [preloadparams] Parameters to substitute into preload if it's used
|
2015-03-13 15:50:23 +00:00
|
|
|
* @return {jQuery.Promise} Abortable promise resolved with a JSON object
|
|
|
|
*/
|
2017-09-11 14:53:50 +00:00
|
|
|
requestPageData: function ( mode, pageName, options ) {
|
2018-05-20 10:53:19 +00:00
|
|
|
var sessionState, request, dataPromise, apiRequest;
|
|
|
|
|
|
|
|
options = options || {};
|
|
|
|
apiRequest = mode === 'source' ?
|
|
|
|
this.requestWikitext.bind( this, pageName, options ) :
|
|
|
|
this.requestParsoidData.bind( this, pageName, options );
|
2018-02-21 22:58:50 +00:00
|
|
|
|
|
|
|
if ( options.sessionStore ) {
|
|
|
|
try {
|
|
|
|
// ve.init.platform.getSession is not available yet
|
|
|
|
sessionState = JSON.parse( mw.storage.session.get( 've-docstate' ) );
|
|
|
|
} catch ( e ) {}
|
|
|
|
|
|
|
|
if ( sessionState ) {
|
2018-02-27 16:00:21 +00:00
|
|
|
request = sessionState.request || {};
|
2018-02-21 22:58:50 +00:00
|
|
|
// Check the requested page, mode and section match the stored one
|
|
|
|
if (
|
|
|
|
request.pageName === pageName &&
|
|
|
|
request.mode === mode &&
|
|
|
|
// Only check sections in source mode
|
|
|
|
( request.mode !== 'source' || request.section === options.section )
|
|
|
|
// NB we don't cache by oldid so that cached results can be recovered
|
|
|
|
// even if the page has been since edited
|
|
|
|
) {
|
2018-03-13 12:51:44 +00:00
|
|
|
dataPromise = $.Deferred().resolve( {
|
2018-02-21 22:58:50 +00:00
|
|
|
visualeditor: $.extend(
|
|
|
|
{ content: mw.storage.session.get( 've-dochtml' ) },
|
|
|
|
sessionState.response,
|
|
|
|
{ recovered: true }
|
|
|
|
)
|
|
|
|
} ).promise();
|
2018-03-13 12:51:44 +00:00
|
|
|
// If the document hasn't been edited since the user first loaded it, recover
|
|
|
|
// their changes automatically.
|
|
|
|
if ( sessionState.response.oldid === mw.config.get( 'wgCurRevisionId' ) ) {
|
|
|
|
return dataPromise;
|
|
|
|
} else {
|
|
|
|
// Otherwise, prompt them if they want to recover, or reload the document
|
|
|
|
// to see the latest version
|
|
|
|
// This prompt will throw off all of our timing data, so just disable tracking
|
|
|
|
// for this session
|
|
|
|
ve.track = function () {};
|
|
|
|
return mw.loader.using( 'oojs-ui-windows' ).then( function () {
|
|
|
|
return OO.ui.confirm( mw.msg( 'visualeditor-autosave-modified-prompt-message' ), {
|
|
|
|
title: mw.msg( 'visualeditor-autosave-modified-prompt-title' ),
|
|
|
|
actions: [
|
|
|
|
{ action: 'accept', label: mw.msg( 'visualeditor-autosave-modified-prompt-accept' ), flags: [ 'primary', 'progressive' ] },
|
|
|
|
{ action: 'reject', label: mw.msg( 'visualeditor-autosave-modified-prompt-reject' ), flags: 'destructive' }
|
|
|
|
] }
|
|
|
|
).then( function ( confirmed ) {
|
|
|
|
if ( confirmed ) {
|
|
|
|
return dataPromise;
|
|
|
|
} else {
|
|
|
|
// If they requested the latest version, invalidate the autosave state
|
|
|
|
mw.storage.session.remove( 've-docstate' );
|
|
|
|
return apiRequest();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
}
|
2018-02-21 22:58:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 12:51:44 +00:00
|
|
|
return apiRequest();
|
2016-05-26 12:08:26 +00:00
|
|
|
},
|
|
|
|
|
2017-01-02 18:40:07 +00:00
|
|
|
/**
|
|
|
|
* Request the page HTML and various metadata from the MediaWiki API (which will use
|
|
|
|
* Parsoid or RESTBase).
|
|
|
|
*
|
2017-09-11 14:53:50 +00:00
|
|
|
* @param {string} pageName See #requestPageData
|
|
|
|
* @param {Object} [options] See #requestPageData
|
2017-01-02 18:40:07 +00:00
|
|
|
* @return {jQuery.Promise} Abortable promise resolved with a JSON object
|
|
|
|
*/
|
2017-09-11 14:53:50 +00:00
|
|
|
requestParsoidData: function ( pageName, options ) {
|
2018-05-20 10:53:19 +00:00
|
|
|
var start, apiXhr, restbaseXhr, apiPromise, restbasePromise, dataPromise, pageHtmlUrl, headers, data,
|
2016-04-04 16:31:39 +00:00
|
|
|
switched = false,
|
2018-05-20 10:53:19 +00:00
|
|
|
fromEditedState = false;
|
2015-03-13 15:50:23 +00:00
|
|
|
|
2017-09-11 14:53:50 +00:00
|
|
|
options = options || {};
|
2018-05-20 10:53:19 +00:00
|
|
|
data = {
|
|
|
|
action: 'visualeditor',
|
|
|
|
paction: ( conf.fullRestbaseUrl || conf.restbaseUrl ) ? 'metadata' : 'parse',
|
|
|
|
page: pageName,
|
|
|
|
uselang: mw.config.get( 'wgUserLanguage' ),
|
|
|
|
editintro: uri.query.editintro,
|
|
|
|
preload: options.preload,
|
|
|
|
preloadparams: options.preloadparams
|
|
|
|
};
|
2017-09-11 14:53:50 +00:00
|
|
|
|
2015-03-13 15:50:23 +00:00
|
|
|
// Only request the API to explicitly load the currently visible revision if we're restoring
|
|
|
|
// from oldid. Otherwise we should load the latest version. This prevents us from editing an
|
|
|
|
// old version if an edit was made while the user was viewing the page and/or the user is
|
|
|
|
// seeing (slightly) stale cache.
|
2017-09-11 14:53:50 +00:00
|
|
|
if ( options.oldId !== undefined ) {
|
|
|
|
data.oldid = options.oldId;
|
2015-03-13 15:50:23 +00:00
|
|
|
}
|
|
|
|
// Load DOM
|
|
|
|
start = ve.now();
|
2017-12-07 11:14:00 +00:00
|
|
|
ve.track( 'trace.apiLoad.enter', { mode: 'visual' } );
|
2015-03-13 15:50:23 +00:00
|
|
|
|
2017-10-11 20:26:18 +00:00
|
|
|
if ( data.paction === 'parse' && options.wikitext !== undefined ) {
|
|
|
|
// Non-RESTBase custom wikitext parse
|
|
|
|
data.paction = 'parsefragment';
|
|
|
|
data.wikitext = options.wikitext;
|
|
|
|
apiXhr = new mw.Api().post( data );
|
|
|
|
} else {
|
|
|
|
apiXhr = new mw.Api().get( data );
|
|
|
|
}
|
2015-03-13 22:15:17 +00:00
|
|
|
apiPromise = apiXhr.then( function ( data, jqxhr ) {
|
2017-12-07 11:14:00 +00:00
|
|
|
ve.track( 'trace.apiLoad.exit', { mode: 'visual' } );
|
2015-03-13 22:15:17 +00:00
|
|
|
ve.track( 'mwtiming.performance.system.apiLoad', {
|
2018-02-27 21:35:29 +00:00
|
|
|
bytes: require( 'mediawiki.String' ).byteLength( jqxhr.responseText ),
|
2015-03-13 15:50:23 +00:00
|
|
|
duration: ve.now() - start,
|
2015-04-09 12:48:16 +00:00
|
|
|
cacheHit: /hit/i.test( jqxhr.getResponseHeader( 'X-Cache' ) ),
|
2017-12-07 11:14:00 +00:00
|
|
|
targetName: options.targetName,
|
|
|
|
mode: 'visual'
|
2015-03-13 15:50:23 +00:00
|
|
|
} );
|
|
|
|
return data;
|
2015-03-13 22:15:17 +00:00
|
|
|
} );
|
|
|
|
|
2015-10-08 22:16:56 +00:00
|
|
|
if ( conf.fullRestbaseUrl || conf.restbaseUrl ) {
|
2017-12-07 11:14:00 +00:00
|
|
|
ve.track( 'trace.restbaseLoad.enter', { mode: 'visual' } );
|
2016-10-27 15:54:46 +00:00
|
|
|
|
|
|
|
headers = {
|
2018-06-22 16:57:50 +00:00
|
|
|
// Should be synchronised with ApiVisualEditor.php
|
|
|
|
Accept: 'text/html; charset=utf-8;' +
|
|
|
|
' profile="https://www.mediawiki.org/wiki/Specs/HTML/1.7.0"',
|
2016-10-27 15:54:46 +00:00
|
|
|
'Api-User-Agent': 'VisualEditor-MediaWiki/' + mw.config.get( 'wgVersion' )
|
|
|
|
};
|
|
|
|
|
2017-09-11 14:53:50 +00:00
|
|
|
// Convert specified Wikitext to HTML
|
2016-04-11 22:34:00 +00:00
|
|
|
if (
|
2017-01-02 18:40:07 +00:00
|
|
|
// wikitext can be an empty string
|
2017-09-11 14:53:50 +00:00
|
|
|
options.wikitext !== undefined &&
|
2016-04-11 22:34:00 +00:00
|
|
|
!$( '[name=wpSection]' ).val()
|
|
|
|
) {
|
2017-03-09 17:30:16 +00:00
|
|
|
if ( conf.fullRestbaseUrl ) {
|
|
|
|
pageHtmlUrl = conf.fullRestbaseUrl + 'v1/transform/wikitext/to/html/';
|
|
|
|
} else {
|
|
|
|
pageHtmlUrl = conf.restbaseUrl.replace( 'v1/page/html/', 'v1/transform/wikitext/to/html/' );
|
|
|
|
}
|
2016-04-04 16:31:39 +00:00
|
|
|
switched = true;
|
2017-09-11 14:53:50 +00:00
|
|
|
fromEditedState = options.modified;
|
2015-11-07 03:57:19 +00:00
|
|
|
window.onbeforeunload = null;
|
|
|
|
$( window ).off( 'beforeunload' );
|
2016-02-27 01:58:13 +00:00
|
|
|
restbaseXhr = $.ajax( {
|
2017-03-09 17:30:16 +00:00
|
|
|
url: pageHtmlUrl + encodeURIComponent( pageName ) +
|
2017-09-11 14:53:50 +00:00
|
|
|
( data.oldid === undefined ? '' : '/' + data.oldid ),
|
2016-02-27 01:58:13 +00:00
|
|
|
type: 'POST',
|
|
|
|
data: {
|
2015-10-08 22:16:56 +00:00
|
|
|
title: pageName,
|
2017-09-11 14:53:50 +00:00
|
|
|
oldid: data.oldid,
|
|
|
|
wikitext: options.wikitext,
|
2015-10-08 22:16:56 +00:00
|
|
|
stash: 'true'
|
2016-02-27 01:58:13 +00:00
|
|
|
},
|
2016-10-27 15:54:46 +00:00
|
|
|
headers: headers,
|
2016-02-27 01:58:13 +00:00
|
|
|
dataType: 'text'
|
|
|
|
} );
|
2015-10-08 22:16:56 +00:00
|
|
|
} else {
|
2017-09-11 14:53:50 +00:00
|
|
|
// Fetch revision
|
2015-10-08 22:16:56 +00:00
|
|
|
if ( conf.fullRestbaseUrl ) {
|
|
|
|
pageHtmlUrl = conf.fullRestbaseUrl + 'v1/page/html/';
|
|
|
|
} else {
|
|
|
|
pageHtmlUrl = conf.restbaseUrl;
|
|
|
|
}
|
|
|
|
restbaseXhr = $.ajax( {
|
|
|
|
url: pageHtmlUrl + encodeURIComponent( pageName ) +
|
2017-09-11 14:53:50 +00:00
|
|
|
( data.oldid === undefined ? '' : '/' + data.oldid ) + '?redirect=false',
|
2015-10-08 22:16:56 +00:00
|
|
|
type: 'GET',
|
2016-10-27 15:54:46 +00:00
|
|
|
headers: headers,
|
2015-10-08 22:16:56 +00:00
|
|
|
dataType: 'text'
|
|
|
|
} );
|
|
|
|
}
|
2015-03-30 02:44:06 +00:00
|
|
|
restbasePromise = restbaseXhr.then(
|
|
|
|
function ( data, status, jqxhr ) {
|
2017-12-07 11:14:00 +00:00
|
|
|
ve.track( 'trace.restbaseLoad.exit', { mode: 'visual' } );
|
2015-03-30 02:44:06 +00:00
|
|
|
ve.track( 'mwtiming.performance.system.restbaseLoad', {
|
2018-02-27 21:35:29 +00:00
|
|
|
bytes: require( 'mediawiki.String' ).byteLength( jqxhr.responseText ),
|
2015-04-09 12:48:16 +00:00
|
|
|
duration: ve.now() - start,
|
2017-12-07 11:14:00 +00:00
|
|
|
targetName: options.targetName,
|
|
|
|
mode: 'visual'
|
2015-03-30 02:44:06 +00:00
|
|
|
} );
|
2015-10-08 22:16:56 +00:00
|
|
|
return [ data, jqxhr.getResponseHeader( 'etag' ) ];
|
2015-03-30 02:44:06 +00:00
|
|
|
},
|
2016-12-21 03:19:19 +00:00
|
|
|
function ( xhr, code, _ ) {
|
|
|
|
if ( xhr.status === 404 ) {
|
2015-03-30 02:44:06 +00:00
|
|
|
// Page does not exist, so let the user start with a blank document.
|
2015-11-04 15:31:19 +00:00
|
|
|
return $.Deferred().resolve( [ '', undefined ] ).promise();
|
2015-03-30 02:44:06 +00:00
|
|
|
} else {
|
2016-12-21 03:19:19 +00:00
|
|
|
mw.log.warn( 'RESTBase load failed: ' + xhr.statusText );
|
|
|
|
return $.Deferred().reject( code, xhr, _ ).promise();
|
2015-03-30 02:44:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2015-03-13 22:15:17 +00:00
|
|
|
|
|
|
|
dataPromise = $.when( apiPromise, restbasePromise )
|
2015-10-08 22:16:56 +00:00
|
|
|
.then( function ( apiData, restbaseData ) {
|
2015-03-13 22:15:17 +00:00
|
|
|
if ( apiData.visualeditor ) {
|
2017-09-14 20:08:09 +00:00
|
|
|
if ( restbaseData[ 0 ] || !apiData.visualeditor.content ) {
|
|
|
|
// If we have actual content loaded, use it.
|
|
|
|
// Otherwise, allow fallback content if present.
|
|
|
|
// If no fallback content, this will give us an empty string for
|
|
|
|
// content, which is desirable.
|
|
|
|
apiData.visualeditor.content = restbaseData[ 0 ];
|
|
|
|
apiData.visualeditor.etag = restbaseData[ 1 ];
|
|
|
|
}
|
2016-04-04 16:31:39 +00:00
|
|
|
apiData.visualeditor.switched = switched;
|
2015-10-08 22:16:56 +00:00
|
|
|
apiData.visualeditor.fromEditedState = fromEditedState;
|
2015-03-13 22:15:17 +00:00
|
|
|
}
|
|
|
|
return apiData;
|
|
|
|
} )
|
|
|
|
.promise( { abort: function () {
|
|
|
|
apiXhr.abort();
|
|
|
|
restbaseXhr.abort();
|
|
|
|
} } );
|
|
|
|
} else {
|
|
|
|
dataPromise = apiPromise.promise( { abort: apiXhr.abort } );
|
|
|
|
}
|
|
|
|
|
|
|
|
return dataPromise;
|
2016-05-26 12:08:26 +00:00
|
|
|
},
|
|
|
|
|
2017-01-02 18:40:07 +00:00
|
|
|
/**
|
|
|
|
* Request the page wikitext and various metadata from the MediaWiki API.
|
|
|
|
*
|
2017-09-11 14:53:50 +00:00
|
|
|
* @param {string} pageName See #requestPageData
|
|
|
|
* @param {Object} [options] See #requestPageData
|
2017-01-02 18:40:07 +00:00
|
|
|
* @return {jQuery.Promise} Abortable promise resolved with a JSON object
|
|
|
|
*/
|
2017-09-11 14:53:50 +00:00
|
|
|
requestWikitext: function ( pageName, options ) {
|
2018-05-20 10:53:19 +00:00
|
|
|
var data;
|
|
|
|
|
|
|
|
options = options || {};
|
|
|
|
data = {
|
2016-10-28 00:22:30 +00:00
|
|
|
action: 'visualeditor',
|
|
|
|
paction: 'wikitext',
|
|
|
|
page: pageName,
|
2016-12-31 17:02:33 +00:00
|
|
|
uselang: mw.config.get( 'wgUserLanguage' ),
|
2017-09-14 20:08:09 +00:00
|
|
|
editintro: uri.query.editintro,
|
|
|
|
preload: options.preload,
|
|
|
|
preloadparams: options.preloadparams
|
2016-10-28 00:22:30 +00:00
|
|
|
};
|
2016-05-26 12:08:26 +00:00
|
|
|
|
2016-09-06 19:16:55 +00:00
|
|
|
// section should never really be undefined, but check just in case
|
2017-09-11 14:53:50 +00:00
|
|
|
if ( options.section !== null && options.section !== undefined ) {
|
|
|
|
data.section = options.section;
|
2016-09-06 19:16:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-11 14:53:50 +00:00
|
|
|
if ( options.oldId !== undefined ) {
|
|
|
|
data.oldid = options.oldId;
|
2016-05-26 12:08:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return new mw.Api().get( data );
|
Load RL modules in one load.php request, rather than in two stages
This introduces TargetLoader, which manages plugins and RL modules
in a slightly more generic fashion so that Targets themselves don't
have to. This allows us to load all RL modules in one load.php
request, rather than first loading ViewPageTarget which then
loads the other modules.
TargetLoader loads in the bottom queue, so it will be loaded
as part of the main load.php request, but in VPT.init.js we
still have to wait for it with using() because it might not
have arrived yet. This also degrades gracefully on cached pages
where TargetLoader isn't in the bottom queue: it'll be loaded
as a separate request instead, which is suboptimal but no
worse that what we were doing before.
Right now TargetLoader is small enough that it could also be in
the top queue, but in the future we want to add things like
the action=visualeditor API request to it, and mw.Api is
relatively big.
Note: this also makes a breaking change to the plugin API:
plugin callbacks no longer receive the target instance
as a parameter, as they're now executed before the target
has been constructed rather than after. In the long term,
if we want to give plugins access to the target instance,
we could give them the target promise somehow. For now,
I've killed this feature because nothing used it and
the change from a direct object reference to a promise
would have been a breaking change anyway.
Also fixed incorrect documentation index for ve.init.mw.ViewPageTarget.init.
Bug: T53569
Change-Id: Ibfa6abbeaf872ae2aadc6ed9d5beba7473ea441a
2015-02-26 01:22:44 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}() );
|