2017-07-13 13:48:32 +00:00
|
|
|
/*!
|
|
|
|
* VisualEditor MediaWiki DiffLoader.
|
|
|
|
*
|
2023-12-01 16:06:11 +00:00
|
|
|
* @copyright See AUTHORS.txt
|
2017-07-13 13:48:32 +00:00
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
2024-04-30 11:32:58 +00:00
|
|
|
/* global ve */
|
|
|
|
|
2017-07-13 13:48:32 +00:00
|
|
|
/**
|
|
|
|
* Diff loader.
|
|
|
|
*
|
|
|
|
* @class mw.libs.ve.diffLoader
|
|
|
|
* @singleton
|
2024-04-30 11:02:45 +00:00
|
|
|
* @hideconstructor
|
2017-07-13 13:48:32 +00:00
|
|
|
*/
|
|
|
|
( function () {
|
2024-05-21 14:22:56 +00:00
|
|
|
const revCache = {};
|
2017-07-13 13:48:32 +00:00
|
|
|
|
|
|
|
mw.libs.ve = mw.libs.ve || {};
|
|
|
|
|
|
|
|
mw.libs.ve.diffLoader = {
|
|
|
|
/**
|
|
|
|
* Get a ve.dm.Document model from a Parsoid response
|
|
|
|
*
|
|
|
|
* @param {Object} response Parsoid response from the VisualEditor API
|
2020-03-31 20:04:30 +00:00
|
|
|
* @param {string|null} section Section. Null for the whole document.
|
2017-07-13 13:48:32 +00:00
|
|
|
* @return {ve.dm.Document|null} Document, or null if an invalid response
|
|
|
|
*/
|
2018-03-12 12:24:18 +00:00
|
|
|
getModelFromResponse: function ( response, section ) {
|
2021-05-05 17:06:37 +00:00
|
|
|
// This method is only called after actually loading these, see `parseDocumentModulePromise`
|
2024-05-21 14:22:56 +00:00
|
|
|
const targetClass = ve.init.mw.ArticleTarget,
|
2017-07-13 13:48:32 +00:00
|
|
|
data = response ? ( response.visualeditor || response.visualeditoredit ) : null;
|
|
|
|
if ( data && typeof data.content === 'string' ) {
|
2024-05-21 14:22:56 +00:00
|
|
|
const doc = targetClass.static.parseDocument( data.content, 'visual', section, section !== null );
|
2020-06-10 19:31:16 +00:00
|
|
|
mw.libs.ve.stripRestbaseIds( doc );
|
2017-07-13 13:48:32 +00:00
|
|
|
return targetClass.static.createModelFromDom( doc, 'visual' );
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch a specific revision from Parsoid as a DM document, and cache in memory
|
|
|
|
*
|
|
|
|
* @param {number} revId Revision ID
|
|
|
|
* @param {string} [pageName] Page name, defaults to wgRelevantPageName
|
2020-03-31 20:04:30 +00:00
|
|
|
* @param {string|null} [section=null] Section. Null for the whole document.
|
2017-07-13 13:48:32 +00:00
|
|
|
* @param {jQuery.Promise} [parseDocumentModulePromise] Promise which resolves when Target#parseDocument is available
|
|
|
|
* @return {jQuery.Promise} Promise which resolves with a document model
|
|
|
|
*/
|
2019-03-06 11:30:26 +00:00
|
|
|
fetchRevision: function ( revId, pageName, section, parseDocumentModulePromise ) {
|
2017-07-13 13:48:32 +00:00
|
|
|
pageName = pageName || mw.config.get( 'wgRelevantPageName' );
|
2019-03-06 11:30:26 +00:00
|
|
|
parseDocumentModulePromise = parseDocumentModulePromise || $.Deferred().resolve().promise();
|
|
|
|
section = section !== undefined ? section : null;
|
|
|
|
|
2024-05-21 14:22:56 +00:00
|
|
|
const cacheKey = revId + ( section !== null ? '/' + section : '' );
|
2017-07-13 13:48:32 +00:00
|
|
|
|
2018-03-12 12:24:18 +00:00
|
|
|
revCache[ cacheKey ] = revCache[ cacheKey ] ||
|
2019-12-02 17:20:09 +00:00
|
|
|
mw.libs.ve.targetLoader.requestParsoidData(
|
|
|
|
pageName,
|
|
|
|
{ oldId: revId, targetName: 'diff' },
|
|
|
|
false,
|
|
|
|
// noMetadata, we only use `content` in getModelFromResponse
|
|
|
|
true
|
2024-05-01 11:36:18 +00:00
|
|
|
).then(
|
|
|
|
( response ) => parseDocumentModulePromise.then( () => mw.libs.ve.diffLoader.getModelFromResponse( response, section ) ),
|
2024-11-14 21:30:05 +00:00
|
|
|
( ...args ) => {
|
|
|
|
// Clear promise. Do not cache errors.
|
2024-05-01 11:36:18 +00:00
|
|
|
delete revCache[ cacheKey ];
|
|
|
|
// Let caller handle the error code
|
2024-11-14 21:30:05 +00:00
|
|
|
return $.Deferred().reject( ...args );
|
2024-05-01 11:36:18 +00:00
|
|
|
}
|
|
|
|
);
|
2017-07-13 13:48:32 +00:00
|
|
|
|
2018-03-12 12:24:18 +00:00
|
|
|
return revCache[ cacheKey ];
|
2017-07-13 13:48:32 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a visual diff generator promise
|
|
|
|
*
|
|
|
|
* @param {number|jQuery.Promise} oldIdOrPromise Old revision ID, or document model promise
|
|
|
|
* @param {number|jQuery.Promise} newIdOrPromise New revision ID, or document model promise
|
|
|
|
* @param {jQuery.Promise} [parseDocumentModulePromise] Promise which resolves when Target#parseDocument is available
|
|
|
|
* @param {string} [oldPageName] Old revision's page name, defaults to wgRelevantPageName
|
|
|
|
* @param {string} [newPageName] New revision's page name, defaults to oldPageName
|
|
|
|
* @return {jQuery.Promise} Promise which resolves with a ve.dm.VisualDiff generator function
|
|
|
|
*/
|
|
|
|
getVisualDiffGeneratorPromise: function ( oldIdOrPromise, newIdOrPromise, parseDocumentModulePromise, oldPageName, newPageName ) {
|
|
|
|
parseDocumentModulePromise = parseDocumentModulePromise || $.Deferred().resolve().promise();
|
|
|
|
oldPageName = oldPageName || mw.config.get( 'wgRelevantPageName' );
|
|
|
|
|
2024-05-21 14:22:56 +00:00
|
|
|
const oldRevPromise = typeof oldIdOrPromise === 'number' ? this.fetchRevision( oldIdOrPromise, oldPageName, null, parseDocumentModulePromise ) : oldIdOrPromise;
|
|
|
|
const newRevPromise = typeof newIdOrPromise === 'number' ? this.fetchRevision( newIdOrPromise, newPageName, null, parseDocumentModulePromise ) : newIdOrPromise;
|
2017-07-13 13:48:32 +00:00
|
|
|
|
2024-04-30 16:44:25 +00:00
|
|
|
return $.when( oldRevPromise, newRevPromise, parseDocumentModulePromise ).then( ( oldDoc, newDoc ) => {
|
2017-07-13 13:48:32 +00:00
|
|
|
// TODO: Differ expects newDoc to be derived from oldDoc and contain all its store data.
|
|
|
|
// We may want to remove that assumption from the differ?
|
|
|
|
newDoc.getStore().merge( oldDoc.getStore() );
|
2024-05-01 11:36:18 +00:00
|
|
|
return () => new ve.dm.VisualDiff( oldDoc, newDoc );
|
2017-07-13 13:48:32 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}() );
|