Make MWTransclusionModel and MWTemplateDialog extensible

Wikia has done some work on the template user experience, including
automatically showing all available parameters without the use of
TemplateData. In order to make our changes, we had to make some changes
to VE-MW.

ve.dm.MWTransclusionModel.js
* this.specCache is created so subclasses can reference it.
* Promise handlers in the fetch() method have been broken out as class
  methods so they can be overridden in subclasses.

ve.ui.MWTemplateDialog.js
* addPromptedParameters() has been moved to the
  initializeNewTemplateParameters() class method so subclasses can
  overwrite. In Wikia's implementation, we have a method of getting
  all parameters and a dialog that shows all of the parameters, so the
  request to addPromptedParameters is overwritten.
* Added a done() handler to the transclusionModel promise for Wikia
  extensibility.

Change-Id: I073c5850420e7719e82957f879423c2717af674a
This commit is contained in:
Christian Williams 2014-10-07 00:06:02 +00:00 committed by Jforrester
parent dcdc5ab0c0
commit 1fc13cce68
2 changed files with 83 additions and 48 deletions

View file

@ -4,6 +4,9 @@
* @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt * @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt * @license The MIT License (MIT); see LICENSE.txt
*/ */
/* global mw */
( function () { ( function () {
var hasOwn = Object.hasOwnProperty, var hasOwn = Object.hasOwnProperty,
specCache = {}; specCache = {};
@ -25,6 +28,7 @@
this.uid = 0; this.uid = 0;
this.requests = []; this.requests = [];
this.queue = []; this.queue = [];
this.specCache = specCache;
}; };
/* Inheritance */ /* Inheritance */
@ -189,7 +193,7 @@
return; return;
} }
var i, len, item, title, request, var i, len, item, title,
titles = [], titles = [],
specs = {}, specs = {},
queue = this.queue.slice(); queue = this.queue.slice();
@ -223,60 +227,65 @@
return; return;
} }
// Request template specs from server this.requests.push( this.fetchRequest( titles, specs, queue ) );
request = ve.init.target.constructor.static.apiRequest( { };
ve.dm.MWTransclusionModel.prototype.fetchRequest = function ( titles, specs, queue ) {
return ve.init.target.constructor.static.apiRequest( {
action: 'templatedata', action: 'templatedata',
titles: titles.join( '|' ), titles: titles.join( '|' ),
lang: mw.config.get( 'wgUserLanguage' ), lang: mw.config.get( 'wgUserLanguage' ),
redirects: '1' redirects: '1'
} ) } )
.done( function ( data ) { .done( ve.bind( this.fetchRequestDone, this, titles, specs ) )
var i, len, id, aliasMap = []; .always( ve.bind( this.fetchRequestAlways, this, queue ) );
};
if ( data && data.pages ) { ve.dm.MWTransclusionModel.prototype.fetchRequestDone = function ( titles, specs, data ) {
// Keep spec data on hand for future use var i, len, id, title, aliasMap = [];
for ( id in data.pages ) {
specs[data.pages[id].title] = data.pages[id];
}
// Follow redirects
if ( data.redirects ) {
aliasMap = data.redirects;
}
// Follow MW's normalisation
if ( data.normalized ) {
aliasMap.push.apply( aliasMap, data.normalized );
}
// Cross-reference aliased titles.
for ( i = 0, len = aliasMap.length; i < len; i++ ) {
// Only define the alias if the target exists, otherwise
// we create a new property with an invalid "undefined" value.
if ( hasOwn.call( specs, aliasMap[i].to ) ) {
specs[aliasMap[i].from] = specs[aliasMap[i].to];
}
}
// Prevent asking again for templates that have no specs if ( data && data.pages ) {
for ( i = 0, len = titles.length; i < len; i++ ) { // Keep spec data on hand for future use
title = titles[i]; for ( id in data.pages ) {
if ( !specs[title] ) { specs[data.pages[id].title] = data.pages[id];
specs[title] = null; }
} // Follow redirects
} if ( data.redirects ) {
aliasMap = data.redirects;
ve.extendObject( specCache, specs ); }
// Follow MW's normalisation
if ( data.normalized ) {
aliasMap.push.apply( aliasMap, data.normalized );
}
// Cross-reference aliased titles.
for ( i = 0, len = aliasMap.length; i < len; i++ ) {
// Only define the alias if the target exists, otherwise
// we create a new property with an invalid "undefined" value.
if ( hasOwn.call( specs, aliasMap[i].to ) ) {
specs[aliasMap[i].from] = specs[aliasMap[i].to];
} }
} ) }
.always( function () {
// Prune completed request
var index = ve.indexOf( request, this.requests );
if ( index !== -1 ) {
this.requests.splice( index, 1 );
}
// Actually add queued items
this.process( queue );
}.bind( this ) );
this.requests.push( request ); // Prevent asking again for templates that have no specs
for ( i = 0, len = titles.length; i < len; i++ ) {
title = titles[i];
if ( !specs[title] ) {
specs[title] = null;
}
}
ve.extendObject( specCache, specs );
}
};
ve.dm.MWTransclusionModel.prototype.fetchRequestAlways = function ( queue, data, textStatus, jqXHR ) {
// Prune completed request
var index = ve.indexOf( jqXHR, this.requests );
if ( index !== -1 ) {
this.requests.splice( index, 1 );
}
// Actually add queued items
this.process( queue );
}; };
/** /**

View file

@ -5,6 +5,8 @@
* @license The MIT License (MIT); see LICENSE.txt * @license The MIT License (MIT); see LICENSE.txt
*/ */
/* global mw */
/** /**
* Dialog for inserting and editing MediaWiki transclusions. * Dialog for inserting and editing MediaWiki transclusions.
* *
@ -439,7 +441,7 @@ ve.ui.MWTemplateDialog.prototype.getSetupProcess = function ( data ) {
this.transclusionModel, data.template this.transclusionModel, data.template
); );
promise = this.transclusionModel.addPart( template ).done( function () { promise = this.transclusionModel.addPart( template ).done( function () {
template.addPromptedParameters(); this.initializeNewTemplateParameters();
} ); } );
} else { } else {
// New template placeholder // New template placeholder
@ -451,7 +453,10 @@ ve.ui.MWTemplateDialog.prototype.getSetupProcess = function ( data ) {
this.actions.setMode( 'edit' ); this.actions.setMode( 'edit' );
// Load existing template // Load existing template
promise = this.transclusionModel promise = this.transclusionModel
.load( ve.copy( this.selectedNode.getAttribute( 'mw' ) ) ); .load( ve.copy( this.selectedNode.getAttribute( 'mw' ) ) )
.done( ve.bind( function () {
this.initializeTemplateParameters();
}, this ) );
} }
this.actions.setAbilities( { apply: false, insert: false } ); this.actions.setAbilities( { apply: false, insert: false } );
this.pushPending(); this.pushPending();
@ -459,6 +464,27 @@ ve.ui.MWTemplateDialog.prototype.getSetupProcess = function ( data ) {
}, this ); }, this );
}; };
/**
* Initialize parameters for new template insertion
*
* @method
*/
ve.ui.MWTemplateDialog.prototype.initializeNewTemplateParameters = function () {
var i, parts = this.transclusionModel.getParts();
for ( i = 0; i < parts.length; i++ ) {
if ( parts[i] instanceof ve.dm.MWTemplateModel ) {
parts[i].addPromptedParameters();
}
}
};
/**
* Intentionally empty. This is provided for Wikia extensibility.
*
* @method
*/
ve.ui.MWTemplateDialog.prototype.initializeTemplateParameters = function () {};
/** /**
* @inheritdoc * @inheritdoc
*/ */