Implement 'change' events in templates models

This will make generating live previews possible.

Changes:
* Add change events to template model.
* Set up connect/disconnect.

Also:
* Add missing fallback for getParameterLabel (Param#label is
  optional per the TemplateData spec).
* Implement getWikitext, to be used by the UI dialog later
  to create a preview from the wikitext.
* Correctly mark ve.dm.MWTransclusionNode#escapeParameter as
  being a static method.

Change-Id: Ie306ed03babf11568e954b1813ce5324f57d7f0e
This commit is contained in:
Trevor Parscal 2013-12-09 11:05:57 -08:00 committed by Krinkle
parent 09ed99ef81
commit 92746ef3da
7 changed files with 99 additions and 37 deletions

View file

@ -239,7 +239,9 @@ ve.dm.MWTemplateModel.prototype.addParameter = function ( param ) {
this.sequence = null;
this.params[name] = param;
this.spec.fill();
param.connect( this, { 'change': [ 'emit', 'change' ] } );
this.emit( 'add', param );
this.emit( 'change' );
};
/**
@ -252,7 +254,9 @@ ve.dm.MWTemplateModel.prototype.removeParameter = function ( param ) {
if ( param ) {
this.sequence = null;
delete this.params[param.getName()];
param.disconnect( this );
this.emit( 'remove', param );
this.emit( 'change' );
}
};
@ -298,3 +302,19 @@ ve.dm.MWTemplateModel.prototype.serialize = function () {
return { 'template': template };
};
/**
* @inheritdoc
*/
ve.dm.MWTemplateModel.prototype.getWikitext = function () {
var param,
wikitext = this.getTarget().wt,
params = this.getParameters();
for ( param in params ) {
wikitext += '|' + param + '=' +
ve.dm.MWTransclusionNode.static.escapeParameter( params[param].getValue() );
}
return '{{' + wikitext + '}}';
};

View file

@ -9,6 +9,7 @@
* MediaWiki template parameter.
*
* @class
* @mixins OO.EventEmitter
*
* @constructor
* @param {ve.dm.MWTemplateModel} template Template
@ -16,6 +17,9 @@
* @param {string} value Parameter value
*/
ve.dm.MWTemplateParameterModel = function VeDmMWTemplateParameterModel( template, name, value ) {
// Mixin constructors
OO.EventEmitter.call( this );
// Properties
this.template = template;
this.originalName = name;
@ -24,6 +28,16 @@ ve.dm.MWTemplateParameterModel = function VeDmMWTemplateParameterModel( template
this.id = this.template.getId() + '/' + name;
};
/* Inheritance */
OO.mixinClass( ve.dm.MWTemplateParameterModel, OO.EventEmitter );
/* Events */
/**
* @event change
*/
/* Methods */
/**
@ -40,7 +54,6 @@ ve.dm.MWTemplateParameterModel.prototype.isRequired = function () {
/**
* Get template parameter is part of.
*
* @method
* @returns {ve.dm.MWTemplateModel} Template
*/
ve.dm.MWTemplateParameterModel.prototype.getTemplate = function () {
@ -59,7 +72,6 @@ ve.dm.MWTemplateParameterModel.prototype.getId = function () {
/**
* Get parameter name.
*
* @method
* @returns {string} Parameter name
*/
ve.dm.MWTemplateParameterModel.prototype.getName = function () {
@ -69,7 +81,6 @@ ve.dm.MWTemplateParameterModel.prototype.getName = function () {
/**
* Get parameter name.
*
* @method
* @returns {string} Parameter name
*/
ve.dm.MWTemplateParameterModel.prototype.getOriginalName = function () {
@ -79,7 +90,6 @@ ve.dm.MWTemplateParameterModel.prototype.getOriginalName = function () {
/**
* Get parameter value.
*
* @method
* @returns {string} Parameter value
*/
ve.dm.MWTemplateParameterModel.prototype.getValue = function () {
@ -89,17 +99,15 @@ ve.dm.MWTemplateParameterModel.prototype.getValue = function () {
/**
* Set parameter value.
*
* @method
* @param {string} value Parameter value
*/
ve.dm.MWTemplateParameterModel.prototype.setValue = function ( value ) {
this.value = value;
this.emit( 'change' );
};
/**
* Remove parameter from template.
*
* @method
*/
ve.dm.MWTemplateParameterModel.prototype.remove = function () {
this.template.removeParameter( this );

View file

@ -39,7 +39,6 @@ ve.dm.MWTemplateSpecModel = function VeDmMWTemplateSpecModel( template ) {
* any filled in values are not overwritten unless new values are available. This prevents changes
* in the API or fill methods from causing issues.
*
* @method
* @param {Object} data Template spec data
* @param {string} [data.description] Template description
* @param {string[]} [data.paramOrder] Canonically ordered parameter names
@ -81,8 +80,6 @@ ve.dm.MWTemplateSpecModel.prototype.extend = function ( data ) {
* Filling is passive, so existing information is never overwitten. The spec should be re-filled
* after a parameter is added to ensure it's still complete, and this is safe because existing data
* is never overwritten.
*
* @method
*/
ve.dm.MWTemplateSpecModel.prototype.fill = function () {
var key;
@ -97,7 +94,6 @@ ve.dm.MWTemplateSpecModel.prototype.fill = function () {
/**
* Get the default spec for a parameter.
*
* @method
* @param {string} name Parameter name
* @returns {Object} Parameter spec
*/
@ -117,7 +113,6 @@ ve.dm.MWTemplateSpecModel.prototype.getDefaultParameterSpec = function ( name )
/**
* Get template label.
*
* @method
* @returns {string} Template label
*/
ve.dm.MWTemplateSpecModel.prototype.getLabel = function () {
@ -145,7 +140,6 @@ ve.dm.MWTemplateSpecModel.prototype.getLabel = function () {
/**
* Get template description.
*
* @method
* @param {string} [lang] Language to get description in
* @returns {string|null} Template description or null if not available
*/
@ -169,7 +163,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterOrder = function () {
*
* Could be a primary name or alias.
*
* @method
* @param {string} name Parameter name
* @returns {boolean} Parameter name is known
*/
@ -180,7 +173,6 @@ ve.dm.MWTemplateSpecModel.prototype.isParameterKnown = function ( name ) {
/**
* Check if a parameter name is an alias.
*
* @method
* @param {string} name Parameter name
* @returns {boolean} Parameter name is an alias
*/
@ -191,20 +183,18 @@ ve.dm.MWTemplateSpecModel.prototype.isParameterAlias = function ( name ) {
/**
* Get a parameter label.
*
* @method
* @param {string} name Parameter name
* @param {string} [lang] Language to get label in
* @returns {string} Parameter label
*/
ve.dm.MWTemplateSpecModel.prototype.getParameterLabel = function ( name, lang ) {
var value = this.params[name].label;
var value = this.params[name].label || name;
return ve.isPlainObject( value ) ? OO.ui.getLocalValue( value, lang ) : value;
};
/**
* Get a parameter description.
*
* @method
* @param {string} name Parameter name
* @param {string} [lang] Language to get description
* @returns {string|null} Parameter description
@ -217,7 +207,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterDescription = function ( name, l
/**
* Get a parameter value.
*
* @method
* @param {string} name Parameter name
* @returns {string} Default parameter value
*/
@ -228,7 +217,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterDefaultValue = function ( name )
/**
* Get a parameter type.
*
* @method
* @param {string} name Parameter name
* @returns {string} Parameter type
*/
@ -239,7 +227,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterType = function ( name ) {
/**
* Get parameter aliases.
*
* @method
* @param {string} name Parameter name
* @returns {string[]} Alternate parameter names
*/
@ -252,7 +239,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterAliases = function ( name ) {
*
* If a parameter is not an alias of another, the output will be the same as the input.
*
* @method
* @param {string} name Parameter alias
* @returns {string} Parameter name
*/
@ -263,7 +249,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterName = function ( name ) {
/**
* Check if parameter is required.
*
* @method
* @param {string} name Parameter name
* @returns {boolean} Parameter is required
*/
@ -274,7 +259,6 @@ ve.dm.MWTemplateSpecModel.prototype.isParameterRequired = function ( name ) {
/**
* Check if parameter is deprecated.
*
* @method
* @param {string} name Parameter name
* @returns {boolean} Parameter is deprecated
*/
@ -285,7 +269,6 @@ ve.dm.MWTemplateSpecModel.prototype.isParameterDeprecated = function ( name ) {
/**
* Get parameter deprecation description.
*
* @method
* @param {string} name Parameter name
* @returns {string} Explaining of why parameter is deprecated, empty if parameter is not deprecated
*/
@ -296,7 +279,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterDeprecationDescription = functio
/**
* Get all primary parameter names.
*
* @method
* @returns {string[]} Parameter names
*/
ve.dm.MWTemplateSpecModel.prototype.getParameterNames = function () {
@ -315,7 +297,6 @@ ve.dm.MWTemplateSpecModel.prototype.getParameterNames = function () {
/**
* Get parameter sets.
*
* @method
* @returns {Object[]} Lists of parameter set descriptors
*/
ve.dm.MWTemplateSpecModel.prototype.getParameterSets = function () {

View file

@ -27,12 +27,17 @@ ve.dm.MWTransclusionContentModel = function VeDmMWTransclusionContentModel( tran
OO.inheritClass( ve.dm.MWTransclusionContentModel, ve.dm.MWTransclusionPartModel );
/* Events */
/**
* @event change
*/
/* Methods */
/**
* Get content value.
*
* @method
* @returns {string} Content value
*/
ve.dm.MWTransclusionContentModel.prototype.getValue = function () {
@ -42,16 +47,23 @@ ve.dm.MWTransclusionContentModel.prototype.getValue = function () {
/**
* Set content value.
*
* @method
* @param {string} value Content value
*/
ve.dm.MWTransclusionContentModel.prototype.setValue = function ( value ) {
this.value = value;
this.emit( 'change' );
};
/**
* @inheritdoc
*/
ve.dm.MWTransclusionContentModel.prototype.serialize = function () {
return this.getValue();
return this.value;
};
/**
* @inheritdoc
*/
ve.dm.MWTransclusionPartModel.prototype.getWikitext = function () {
return this.value;
};

View file

@ -42,6 +42,10 @@ OO.mixinClass( ve.dm.MWTransclusionModel, OO.EventEmitter );
* @param {ve.dm.MWTransclusionPartModel|null} added Added part
*/
/**
* @event change
*/
/* Methods */
/**
@ -91,6 +95,7 @@ ve.dm.MWTransclusionModel.prototype.load = function ( data ) {
* @param {Object[]} queue List of objects containing parts to add and optionally indexes to add
* them at, if no index is given parts will be added at the end
* @fires replace For each item added
* @fires change
*/
ve.dm.MWTransclusionModel.prototype.process = function ( queue ) {
var i, len, item, title, index,
@ -108,6 +113,7 @@ ve.dm.MWTransclusionModel.prototype.process = function ( queue ) {
index = ve.indexOf( item.add, this.parts );
if ( index !== -1 ) {
this.parts.splice( index, 1 );
item.add.disconnect( this );
this.emit( 'replace', item.add, null );
}
// Add at index, or end if none was given
@ -123,12 +129,19 @@ ve.dm.MWTransclusionModel.prototype.process = function ( queue ) {
index = this.parts.length;
}
this.parts.splice( index, remove, item.add );
if ( item.add ) {
item.add.connect( this, { 'change': [ 'emit', 'change' ] } );
}
if ( item.remove ) {
item.remove.disconnect( this );
}
this.emit( 'replace', item.remove || null, item.add );
// Resolve promises
if ( item.deferred ) {
item.deferred.resolve();
}
}
this.emit( 'change' );
};
/** */
@ -221,8 +234,6 @@ ve.dm.MWTransclusionModel.prototype.fetch = function () {
/**
* Abort any pending requests.
*
* @method
*/
ve.dm.MWTransclusionModel.prototype.abortRequests = function () {
var i, len;
@ -257,6 +268,22 @@ ve.dm.MWTransclusionModel.prototype.getPlainObject = function () {
return obj;
};
/**
* Get the wikitext for this transclusion.
*
* @returns {string} Wikitext like `{{foo|1=bar|baz=quux}}`
*/
ve.dm.MWTransclusionModel.prototype.getWikitext = function () {
var i, len,
wikitext = '';
for ( i = 0, len = this.parts.length; i < len; i++ ) {
wikitext += this.parts[i].getWikitext();
}
return wikitext;
};
/**
* Get a unique ID for a part in the transclusion.
*
@ -330,6 +357,7 @@ ve.dm.MWTransclusionModel.prototype.removePart = function ( part ) {
var index = ve.indexOf( part, this.parts );
if ( index !== -1 ) {
this.parts.splice( index, 1 );
part.disconnect( this );
this.emit( 'replace', part, null );
}
};

View file

@ -27,12 +27,17 @@ ve.dm.MWTransclusionPartModel = function VeDmMWTransclusionPartModel( transclusi
OO.mixinClass( ve.dm.MWTransclusionPartModel, OO.EventEmitter );
/* Events */
/**
* @event change
*/
/* Methods */
/**
* Get transclusion part is in.
*
* @method
* @returns {ve.dm.MWTransclusionModel} Transclusion
*/
ve.dm.MWTransclusionPartModel.prototype.getTransclusion = function () {
@ -50,8 +55,6 @@ ve.dm.MWTransclusionPartModel.prototype.getId = function () {
/**
* Remove part from transclusion.
*
* @method
*/
ve.dm.MWTransclusionPartModel.prototype.remove = function () {
this.transclusion.removePart( this );
@ -60,9 +63,17 @@ ve.dm.MWTransclusionPartModel.prototype.remove = function () {
/**
* Get serialized representation of transclusion part.
*
* @method
* @returns {Mixed} Serialized representation, or undefined if empty
*/
ve.dm.MWTransclusionPartModel.prototype.serialize = function () {
return undefined;
};
/**
* Get the wikitext for this part.
*
* @returns {string} Wikitext
*/
ve.dm.MWTransclusionPartModel.prototype.getWikitext = function () {
return '';
};

View file

@ -144,7 +144,9 @@ ve.dm.MWTransclusionNode.static.toDomElements = function ( dataElement, doc, con
};
/**
* Escape a template parameter. Helper function for getWikitext().
* Escape a template parameter. Helper function for #getWikitext.
*
* @static
* @param {string} param Parameter value
* @returns {string} Escaped parameter value
*/