From 1fc13cce68cbccdc8b6fd7e88460bed36e8f932a Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Tue, 7 Oct 2014 00:06:02 +0000 Subject: [PATCH] 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 --- .../dm/models/ve.dm.MWTransclusionModel.js | 101 ++++++++++-------- .../ui/dialogs/ve.ui.MWTemplateDialog.js | 30 +++++- 2 files changed, 83 insertions(+), 48 deletions(-) diff --git a/modules/ve-mw/dm/models/ve.dm.MWTransclusionModel.js b/modules/ve-mw/dm/models/ve.dm.MWTransclusionModel.js index f56120c413..3f6700196c 100644 --- a/modules/ve-mw/dm/models/ve.dm.MWTransclusionModel.js +++ b/modules/ve-mw/dm/models/ve.dm.MWTransclusionModel.js @@ -4,6 +4,9 @@ * @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt */ + +/* global mw */ + ( function () { var hasOwn = Object.hasOwnProperty, specCache = {}; @@ -25,6 +28,7 @@ this.uid = 0; this.requests = []; this.queue = []; + this.specCache = specCache; }; /* Inheritance */ @@ -189,7 +193,7 @@ return; } - var i, len, item, title, request, + var i, len, item, title, titles = [], specs = {}, queue = this.queue.slice(); @@ -223,60 +227,65 @@ return; } - // Request template specs from server - request = ve.init.target.constructor.static.apiRequest( { + this.requests.push( this.fetchRequest( titles, specs, queue ) ); + }; + + ve.dm.MWTransclusionModel.prototype.fetchRequest = function ( titles, specs, queue ) { + return ve.init.target.constructor.static.apiRequest( { action: 'templatedata', titles: titles.join( '|' ), lang: mw.config.get( 'wgUserLanguage' ), redirects: '1' } ) - .done( function ( data ) { - var i, len, id, aliasMap = []; + .done( ve.bind( this.fetchRequestDone, this, titles, specs ) ) + .always( ve.bind( this.fetchRequestAlways, this, queue ) ); + }; - if ( data && data.pages ) { - // Keep spec data on hand for future use - 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]; - } - } + ve.dm.MWTransclusionModel.prototype.fetchRequestDone = function ( titles, specs, data ) { + var i, len, id, title, aliasMap = []; - // 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 ); + if ( data && data.pages ) { + // Keep spec data on hand for future use + 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]; } - } ) - .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 ); }; /** diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWTemplateDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWTemplateDialog.js index 00753b2849..973f2b0dd4 100644 --- a/modules/ve-mw/ui/dialogs/ve.ui.MWTemplateDialog.js +++ b/modules/ve-mw/ui/dialogs/ve.ui.MWTemplateDialog.js @@ -5,6 +5,8 @@ * @license The MIT License (MIT); see LICENSE.txt */ +/* global mw */ + /** * Dialog for inserting and editing MediaWiki transclusions. * @@ -439,7 +441,7 @@ ve.ui.MWTemplateDialog.prototype.getSetupProcess = function ( data ) { this.transclusionModel, data.template ); promise = this.transclusionModel.addPart( template ).done( function () { - template.addPromptedParameters(); + this.initializeNewTemplateParameters(); } ); } else { // New template placeholder @@ -451,7 +453,10 @@ ve.ui.MWTemplateDialog.prototype.getSetupProcess = function ( data ) { this.actions.setMode( 'edit' ); // Load existing template 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.pushPending(); @@ -459,6 +464,27 @@ ve.ui.MWTemplateDialog.prototype.getSetupProcess = function ( data ) { }, 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 */