mediawiki-extensions-Visual.../modules/ve-mw/dm/models/ve.dm.MWTransclusionModel.js

608 lines
18 KiB
JavaScript
Raw Normal View History

/*!
* VisualEditor DataModel MWTransclusionModel class.
*
* @copyright See AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Object literal
*
* @class ve.dm.MWTransclusionPartInstruction
* @private
*/
/**
* @property {ve.dm.MWTransclusionPartModel} [remove]
* @property {ve.dm.MWTransclusionPartModel} [add]
* @property {number} [index]
* @property {jQuery.Deferred} [deferred]
*/
( function () {
const hasOwn = Object.hasOwnProperty,
specCache = {};
/**
* Represents a MediaWiki transclusion, i.e. a sequence of one or more template invocations that
* strictly belong to each other (e.g. because they are unbalanced), possibly mixed with raw
* wikitext snippets. These individual "parts" are subclasses of ve.dm.MWTransclusionPartModel.
*
* @class
* @mixes OO.EventEmitter
*
* @constructor
* @param {ve.dm.Document} doc Document to use associate with API requests
*/
ve.dm.MWTransclusionModel = function VeDmMWTransclusionModel( doc ) {
// Mixin constructors
OO.EventEmitter.call( this );
/**
* @property {ve.dm.MWTransclusionPartModel[]} parts
* @property {number} uid
* @property {jQuery.Promise[]} templateDataApiRequests Currently running API requests. The only
* reason to keep these around is to be able to abort them earlier when the template dialog
* closes or resets.
* @property {Object[]} changeQueue
*/
this.doc = doc;
this.parts = [];
this.uid = 0;
this.templateDataApiRequests = [];
this.changeQueue = [];
};
/* Inheritance */
OO.mixinClass( ve.dm.MWTransclusionModel, OO.EventEmitter );
/* Events */
/**
* Emitted when a part is added, removed, replaced (e.g. a placeholder with an actual template),
* or an existing part changed position.
*
* @event ve.dm.MWTransclusionPartInstruction#replace
* @param {ve.dm.MWTransclusionPartModel|null} removed Removed part
* @param {ve.dm.MWTransclusionPartModel|null} added Added or moved part
* @param {number} [newPosition] Position the part was added or moved to
*/
/**
* Emitted when anything changed, including any changes in the content of the parts.
*
* @event ve.dm.MWTransclusionPartInstruction#change
*/
/* Methods */
/**
* Insert transclusion at the end of a surface fragment.
*
* If forceType is not specified and this is used in async mode, users of this method
* should ensure the surface is not accessible while the type is being evaluated.
*
* @param {ve.dm.SurfaceFragment} surfaceFragment Surface fragment after which to insert.
* @param {string} [forceType] Force the type to 'inline' or 'block'. If not
* specified it will be evaluated asynchronously.
* @return {jQuery.Promise} Promise which resolves when the node has been inserted. If
* forceType was specified this will be instant.
*/
ve.dm.MWTransclusionModel.prototype.insertTransclusionNode = function ( surfaceFragment, forceType ) {
const deferred = ve.createDeferred(),
baseNodeClass = ve.dm.MWTransclusionNode;
const insertNode = ( isInline, generatedContents ) => {
const type = isInline ? baseNodeClass.static.inlineType : baseNodeClass.static.blockType,
data = [
{
type: type,
attributes: {
mw: this.getPlainObject()
}
},
{ type: '/' + type }
];
// If we just fetched the generated contents, put them in the store
// so we don't do a duplicate API call later.
if ( generatedContents ) {
const nodeClass = ve.dm.modelRegistry.lookup( type );
const store = surfaceFragment.getDocument().getStore();
const hash = OO.getHash( [ nodeClass.static.getHashObjectForRendering( data[ 0 ] ), undefined ] );
store.hash( generatedContents, hash );
}
surfaceFragment.insertContent( data );
deferred.resolve();
};
if ( forceType ) {
insertNode( forceType === 'inline' );
} else {
ve.init.target.parseWikitextFragment(
baseNodeClass.static.getWikitext( this.getPlainObject() ),
true,
surfaceFragment.getDocument()
).then( ( response ) => {
if ( ve.getProp( response, 'visualeditor', 'result' ) === 'success' ) {
// This method is only ever run by a client, so it is okay to use jQuery
// eslint-disable-next-line no-undef
let contentNodes = $.parseHTML( response.visualeditor.content, surfaceFragment.getDocument().getHtmlDocument() ) || [];
contentNodes = ve.ce.MWTransclusionNode.static.filterRendering( contentNodes );
insertNode(
baseNodeClass.static.isHybridInline( contentNodes, ve.dm.converter ),
contentNodes
);
} else {
// Request failed - just assume inline
insertNode( true );
}
}, () => {
insertNode( true );
} );
}
return deferred.promise();
};
/**
* Update transclusion node in a document.
*
* @param {ve.dm.Surface} surfaceModel Surface model of main document
* @param {ve.dm.MWTransclusionNode} node Transclusion node to update
*/
ve.dm.MWTransclusionModel.prototype.updateTransclusionNode = function ( surfaceModel, node ) {
const obj = this.getPlainObject();
if ( obj !== null ) {
surfaceModel.getLinearFragment( node.getOuterRange(), true )
.changeAttributes( { mw: obj } );
} else {
surfaceModel.getLinearFragment( node.getOuterRange(), true )
.removeContent();
}
};
/**
* Load from transclusion data, and fetch spec from server.
*
* @param {Object} data Transclusion data
* @return {jQuery.Promise} Promise, resolved when spec is loaded
*/
ve.dm.MWTransclusionModel.prototype.load = function ( data ) {
const promises = [];
// Convert single part format to multi-part format
// Parsoid doesn't use this format any more, but we accept it for backwards compatibility
if ( data.params && data.target ) {
data = { parts: [ { template: data } ] };
}
if ( Array.isArray( data.parts ) ) {
for ( let i = 0; i < data.parts.length; i++ ) {
const part = data.parts[ i ];
if ( part.template ) {
const deferred = ve.createDeferred();
promises.push( deferred.promise() );
this.changeQueue.push( {
add: ve.dm.MWTemplateModel.newFromData( this, part.template ),
deferred: deferred
} );
} else if ( typeof part === 'string' ) {
const deferred = ve.createDeferred();
promises.push( deferred.promise() );
this.changeQueue.push( {
add: new ve.dm.MWTransclusionContentModel( this, part ),
deferred: deferred
} );
}
}
setTimeout( this.processChangeQueue.bind( this ) );
}
Refactor Transclusion and Meta dialogs to use BookletLayout Use OOJS-UI's newly-extended paged dialogs (in e08eb2a03b) to refactor how the Transclusion and Meta dialogs work, splitting out the code for each of the panels into its own file and simplifying extensibility. The Meta dialog (ve.ui.MWMetaDialog) now has two self-managing panels: * ve.ui.MWCategoriesPage for categories and the default sort key * ve.ui.MWLanguagesPage for language links The Transclusion dialog (ve.ui.MWTransclusionDialog) now has four: * ve.ui.MWTemplatePage for a template's primary panel * ve.ui.MWTemplateParameterPage for each parameter of a template * ve.ui.MWTemplatePlaceholderPage for a placeholder to insert a template * ve.ui.MWTransclusionContentPage for non-template transclusion Additionally, the Transclusion dialog has been slightly cleaned up: * Replace add/remove events with replace events in transclusion model * Actually return and resolve a promise (as documented) * Get rid of "origin" info in template models * Add method for adding required parts TODO: * Decide how and when we will choose between advanced transclusion and template dialogs * Work out design issues with how template descriptions will be visible and how adding parameters will work if only showing parameters in outline * Add preview to template dialog * Consider ways to further improve pages for use in continuous mode WARNING: * Right now the template dialog gets overridden by the advanced transclusion dialog because they have the same symbolic name and the latter is registered later than the former. To test the template dialog, just change the symbolic name of the advanced transclusion dialog. Change-Id: I51e74b322aec9a4c3918e6f792bdb3d318060979
2013-12-02 20:10:55 +00:00
return ve.promiseAll( promises );
};
/**
* Process one or more queue items.
*
* @private
* @param {ve.dm.MWTransclusionPartInstruction[]} 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 ve.dm.MWTransclusionPartInstruction#replace For each item added
* @fires ve.dm.MWTransclusionPartInstruction#change
*/
ve.dm.MWTransclusionModel.prototype.resolveChangeQueue = function ( queue ) {
const resolveQueue = [];
for ( let i = 0; i < queue.length; i++ ) {
const item = queue[ i ];
let remove = 0;
if ( item.add instanceof ve.dm.MWTemplateModel ) {
const title = item.add.getTemplateDataQueryTitle();
if ( hasOwn.call( specCache, title ) && specCache[ title ] ) {
item.add.getSpec().setTemplateData( specCache[ title ] );
}
}
// Use specified index
let index = item.index;
// Auto-remove if already existing, preserving index
const existing = this.parts.indexOf( item.add );
if ( existing !== -1 ) {
this.removePart( item.add );
if ( index && existing + 1 < index ) {
index--;
}
}
// Derive index from removal if given
if ( index === undefined && item.remove ) {
index = this.parts.indexOf( item.remove );
if ( index !== -1 ) {
remove = 1;
}
}
// Use last index as a last resort
if ( index === undefined || index === -1 ) {
index = this.parts.length;
}
this.parts.splice( index, remove, item.add );
if ( item.add ) {
// This forwards change events from the nested ve.dm.MWTransclusionPartModel upwards.
// The array syntax is a way to call `this.emit( 'change' )`.
item.add.connect( this, { change: [ 'emit', 'change' ] } );
}
if ( item.remove ) {
item.remove.disconnect( this );
}
this.emit( 'replace', item.remove || null, item.add, index );
// Resolve promises
if ( item.deferred ) {
resolveQueue.push( item.deferred );
}
}
this.emit( 'change' );
// We need to go back and resolve the deferreds after emitting change.
// Otherwise we get silly situations like a single change event being
// guaranteed after the transclusion loaded promise gets resolved.
resolveQueue.forEach( ( queueItem ) => {
queueItem.resolve();
} );
};
/**
* @private
*/
ve.dm.MWTransclusionModel.prototype.processChangeQueue = function () {
const templateNamespaceId = mw.config.get( 'wgNamespaceIds' ).template,
titles = [];
if ( !this.changeQueue.length ) {
return;
}
const queue = this.changeQueue.slice();
// Clear shared queue for future calls
this.changeQueue.length = 0;
// Get unique list of template titles that aren't already loaded
for ( let i = 0; i < queue.length; i++ ) {
const item = queue[ i ];
if ( item.add instanceof ve.dm.MWTemplateModel ) {
const title = item.add.getTemplateDataQueryTitle(),
mwTitle = title ? mw.Title.newFromText( title, templateNamespaceId ) : null;
if (
// Skip titles that don't have a resolvable href
mwTitle &&
// Skip already cached data
!hasOwn.call( specCache, title ) &&
// Skip duplicate titles in the same batch
titles.indexOf( title ) === -1
) {
titles.push( title );
}
Refactor Transclusion and Meta dialogs to use BookletLayout Use OOJS-UI's newly-extended paged dialogs (in e08eb2a03b) to refactor how the Transclusion and Meta dialogs work, splitting out the code for each of the panels into its own file and simplifying extensibility. The Meta dialog (ve.ui.MWMetaDialog) now has two self-managing panels: * ve.ui.MWCategoriesPage for categories and the default sort key * ve.ui.MWLanguagesPage for language links The Transclusion dialog (ve.ui.MWTransclusionDialog) now has four: * ve.ui.MWTemplatePage for a template's primary panel * ve.ui.MWTemplateParameterPage for each parameter of a template * ve.ui.MWTemplatePlaceholderPage for a placeholder to insert a template * ve.ui.MWTransclusionContentPage for non-template transclusion Additionally, the Transclusion dialog has been slightly cleaned up: * Replace add/remove events with replace events in transclusion model * Actually return and resolve a promise (as documented) * Get rid of "origin" info in template models * Add method for adding required parts TODO: * Decide how and when we will choose between advanced transclusion and template dialogs * Work out design issues with how template descriptions will be visible and how adding parameters will work if only showing parameters in outline * Add preview to template dialog * Consider ways to further improve pages for use in continuous mode WARNING: * Right now the template dialog gets overridden by the advanced transclusion dialog because they have the same symbolic name and the latter is registered later than the former. To test the template dialog, just change the symbolic name of the advanced transclusion dialog. Change-Id: I51e74b322aec9a4c3918e6f792bdb3d318060979
2013-12-02 20:10:55 +00:00
}
}
// Bypass server for empty lists
if ( !titles.length ) {
setTimeout( this.resolveChangeQueue.bind( this, queue ) );
return;
}
this.templateDataApiRequests.push( this.callTemplateDataApi( titles, queue ) );
};
/**
* @private
* @param {string[]} titles
* @param {ve.dm.MWTransclusionPartInstruction[]} queue
* @return {jQuery.Promise}
*/
ve.dm.MWTransclusionModel.prototype.callTemplateDataApi = function ( titles, queue ) {
const xhr = ve.init.target.getContentApi( this.doc ).get( {
action: 'templatedata',
titles: titles,
lang: mw.config.get( 'wgUserLanguage' ),
includeMissingTitles: '1',
redirects: '1'
} ).done( this.cacheTemplateDataApiResponse.bind( this ) );
xhr.always(
this.markRequestAsDone.bind( this, xhr ),
this.resolveChangeQueue.bind( this, queue )
);
return xhr;
};
/**
* @private
* @param {Object} [data]
* @param {Object.<number,ve.dm.MWTemplatePageMetadata>} [data.pages]
*/
ve.dm.MWTransclusionModel.prototype.cacheTemplateDataApiResponse = function ( data ) {
if ( !data || !data.pages ) {
return;
}
// Keep spec data on hand for future use
for ( const id in data.pages ) {
const title = data.pages[ id ].title;
if ( data.pages[ id ].missing ) {
// Remember templates that don't exist in the link cache
// { title: { missing: true|false }
const missingTitle = {};
missingTitle[ title ] = { missing: true };
ve.init.platform.linkCache.setMissing( missingTitle );
} else if ( data.pages[ id ].notemplatedata && !OO.isPlainObject( data.pages[ id ].params ) ) {
// (T243868) Prevent asking again for templates that have neither user-provided specs
// nor automatically detected params
specCache[ title ] = null;
} else {
specCache[ title ] = data.pages[ id ];
}
}
// Follow redirects
const aliasMap = data.redirects || [];
// Follow MW's normalisation
if ( data.normalized ) {
ve.batchPush( aliasMap, data.normalized );
}
// Cross-reference aliased titles.
for ( let i = 0; i < aliasMap.length; i++ ) {
// Only define the alias if the target exists, otherwise
// we create a new property with an invalid "undefined" value.
if ( hasOwn.call( specCache, aliasMap[ i ].to ) ) {
specCache[ aliasMap[ i ].from ] = specCache[ aliasMap[ i ].to ];
}
}
};
/**
* @private
* @param {jQuery.Promise} apiPromise
*/
ve.dm.MWTransclusionModel.prototype.markRequestAsDone = function ( apiPromise ) {
// Prune completed request
const index = this.templateDataApiRequests.indexOf( apiPromise );
if ( index !== -1 ) {
this.templateDataApiRequests.splice( index, 1 );
}
};
ve.dm.MWTransclusionModel.prototype.abortAllApiRequests = function () {
for ( let i = 0; i < this.templateDataApiRequests.length; i++ ) {
this.templateDataApiRequests[ i ].abort();
}
this.templateDataApiRequests.length = 0;
};
/**
* Get plain object representation of template transclusion.
*
* @return {Object|null} Plain object representation, or null if empty
*/
ve.dm.MWTransclusionModel.prototype.getPlainObject = function () {
const parts = [];
for ( let i = 0; i < this.parts.length; i++ ) {
const part = this.parts[ i ];
const serialization = part.serialize();
if ( serialization !== undefined && serialization !== '' ) {
parts.push( serialization );
}
}
return parts.length ? { parts: parts } : null;
};
/**
* @return {string} Next part ID, starting from "part_0", guaranteed to be unique for this
* transclusion
*/
ve.dm.MWTransclusionModel.prototype.nextUniquePartId = function () {
return 'part_' + this.uid++;
};
/**
* Replace asynchronously.
*
* @param {ve.dm.MWTransclusionPartModel} remove Part to remove
* @param {ve.dm.MWTransclusionPartModel} add Part to add
* @throws {Error} If part to remove is not valid
* @throws {Error} If part to add is not valid
* @return {jQuery.Promise} Promise, resolved when part is added
*/
ve.dm.MWTransclusionModel.prototype.replacePart = function ( remove, add ) {
const deferred = ve.createDeferred();
if (
!( remove instanceof ve.dm.MWTransclusionPartModel ) ||
!( add instanceof ve.dm.MWTransclusionPartModel )
) {
throw new Error( 'Invalid transclusion part' );
}
this.changeQueue.push( { remove: remove, add: add, deferred: deferred } );
// Fetch on next yield to process items in the queue together, subsequent calls will
// have no effect because the queue will be clear
setTimeout( this.processChangeQueue.bind( this ) );
return deferred.promise();
};
/**
* Added asynchronously, but order is preserved.
*
* @param {ve.dm.MWTransclusionPartModel} part
* @param {number} [index] Specific index to add content at, defaults to the end
* @throws {Error} If part is not valid
* @return {jQuery.Promise} Promise, resolved when part is added
*/
ve.dm.MWTransclusionModel.prototype.addPart = function ( part, index ) {
const deferred = ve.createDeferred();
if ( !( part instanceof ve.dm.MWTransclusionPartModel ) ) {
throw new Error( 'Invalid transclusion part' );
}
this.changeQueue.push( { add: part, index: index, deferred: deferred } );
// Fetch on next yield to process items in the queue together, subsequent calls to fetch will
// have no effect because the queue will be clear
setTimeout( this.processChangeQueue.bind( this ) );
return deferred.promise();
};
/**
* @param {ve.dm.MWTransclusionPartModel} part
* @fires ve.dm.MWTransclusionPartInstruction#replace
*/
ve.dm.MWTransclusionModel.prototype.removePart = function ( part ) {
const index = this.parts.indexOf( part );
if ( index !== -1 ) {
this.parts.splice( index, 1 );
part.disconnect( this );
this.emit( 'replace', part, null );
Outline controls Objectives: * Allow reordering items in outline widgets using an outline control widget * Use an outline control widget to reorder transclusion parts Changes: ve.ui.SelectWidget.js * Emit add and remove events ve.ui.OutlineItemWidget.js * Add movable config options * Add isMovable method ve.ui.OutlineControlsWidget.js * New class * Displays move up/down buttons which are synchronized with an outline widget * Doesn't actually move items (since an outline widget is probably data-driven) just emits events ve.ui.Widget.css * Add disabled style for icon button widgets * Add styles for outline controls widget ve.ui.Icons*.css * Add missing icon styles ve.ui.Dialog.css * Add styles for outline and controls in editable paged dialogs ve.ui.GroupElement.js * Fix bug where items are insertions are in the wrong place when "moving" them ve.ui.PagedDialog.js * Add editable config option which shows outline controls under the outline * Pass through movable config option when creating pages ve.ui.MWTranclusionDialog.js * Configure paged dialog outline as editable * Add initialize method to connect outline controls widget events * Make addPart method automatically add parameters when templates are added * Add handler for outline controls move event which re-orders parts * Make parts movable (params are automatically ordered, so they aren't movable) ve.dm.MWTransclusionModel.js * Add addPart method and use it within the addContent and addTemplate methods * Fix documentation lies * Add getPartFromId method *.php * Add links to new files and messages Change-Id: I919d4c3e9b85d07a97a99c0b2e8739a859bdf2b1
2013-06-14 00:46:45 +00:00
}
};
/**
* @return {boolean} True if the transclusion is literally empty or contains only placeholders
*/
ve.dm.MWTransclusionModel.prototype.isEmpty = function () {
return this.parts.every( ( part ) => part instanceof ve.dm.MWTemplatePlaceholderModel );
};
/**
* @return {boolean} True if this is a single template or template placeholder
*/
ve.dm.MWTransclusionModel.prototype.isSingleTemplate = function () {
return this.parts.length === 1 && (
this.parts[ 0 ] instanceof ve.dm.MWTemplateModel ||
this.parts[ 0 ] instanceof ve.dm.MWTemplatePlaceholderModel
);
};
/**
* @return {ve.dm.MWTransclusionPartModel[]} All parts in this transclusion
*/
ve.dm.MWTransclusionModel.prototype.getParts = function () {
return this.parts;
};
/**
* Matching is performed against the first section of the `id`, delimited by a '/'.
*
* @param {string} [id] Any id, including slash-delimited template parameter ids
* @return {ve.dm.MWTransclusionPartModel|undefined} Part with matching ID, if found
*/
ve.dm.MWTransclusionModel.prototype.getPartFromId = function ( id ) {
if ( !id ) {
return;
}
// For ids from ve.dm.MWParameterModel, compare against the part id
// of the parameter instead of the entire model id (e.g. "part_1" instead of "part_1/foo").
const partId = id.split( '/', 1 )[ 0 ];
for ( let i = 0; i < this.parts.length; i++ ) {
if ( this.parts[ i ].getId() === partId ) {
return this.parts[ i ];
}
Refactor Transclusion and Meta dialogs to use BookletLayout Use OOJS-UI's newly-extended paged dialogs (in e08eb2a03b) to refactor how the Transclusion and Meta dialogs work, splitting out the code for each of the panels into its own file and simplifying extensibility. The Meta dialog (ve.ui.MWMetaDialog) now has two self-managing panels: * ve.ui.MWCategoriesPage for categories and the default sort key * ve.ui.MWLanguagesPage for language links The Transclusion dialog (ve.ui.MWTransclusionDialog) now has four: * ve.ui.MWTemplatePage for a template's primary panel * ve.ui.MWTemplateParameterPage for each parameter of a template * ve.ui.MWTemplatePlaceholderPage for a placeholder to insert a template * ve.ui.MWTransclusionContentPage for non-template transclusion Additionally, the Transclusion dialog has been slightly cleaned up: * Replace add/remove events with replace events in transclusion model * Actually return and resolve a promise (as documented) * Get rid of "origin" info in template models * Add method for adding required parts TODO: * Decide how and when we will choose between advanced transclusion and template dialogs * Work out design issues with how template descriptions will be visible and how adding parameters will work if only showing parameters in outline * Add preview to template dialog * Consider ways to further improve pages for use in continuous mode WARNING: * Right now the template dialog gets overridden by the advanced transclusion dialog because they have the same symbolic name and the latter is registered later than the former. To test the template dialog, just change the symbolic name of the advanced transclusion dialog. Change-Id: I51e74b322aec9a4c3918e6f792bdb3d318060979
2013-12-02 20:10:55 +00:00
}
};
/**
* Get the index of a part or parameter.
*
* Indexes are linear depth-first addresses in the transclusion tree.
*
* @param {ve.dm.MWTransclusionPartModel|ve.dm.MWParameterModel} model Part or parameter
* @return {number} Page index of model
*/
ve.dm.MWTransclusionModel.prototype.getIndex = function ( model ) {
const parts = this.parts;
let index = 0;
for ( let i = 0; i < parts.length; i++ ) {
const part = parts[ i ];
if ( part === model ) {
return index;
}
index++;
if ( part instanceof ve.dm.MWTemplateModel ) {
const names = part.getOrderedParameterNames();
for ( let j = 0; j < names.length; j++ ) {
if ( part.getParameter( names[ j ] ) === model ) {
return index;
}
index++;
Refactor Transclusion and Meta dialogs to use BookletLayout Use OOJS-UI's newly-extended paged dialogs (in e08eb2a03b) to refactor how the Transclusion and Meta dialogs work, splitting out the code for each of the panels into its own file and simplifying extensibility. The Meta dialog (ve.ui.MWMetaDialog) now has two self-managing panels: * ve.ui.MWCategoriesPage for categories and the default sort key * ve.ui.MWLanguagesPage for language links The Transclusion dialog (ve.ui.MWTransclusionDialog) now has four: * ve.ui.MWTemplatePage for a template's primary panel * ve.ui.MWTemplateParameterPage for each parameter of a template * ve.ui.MWTemplatePlaceholderPage for a placeholder to insert a template * ve.ui.MWTransclusionContentPage for non-template transclusion Additionally, the Transclusion dialog has been slightly cleaned up: * Replace add/remove events with replace events in transclusion model * Actually return and resolve a promise (as documented) * Get rid of "origin" info in template models * Add method for adding required parts TODO: * Decide how and when we will choose between advanced transclusion and template dialogs * Work out design issues with how template descriptions will be visible and how adding parameters will work if only showing parameters in outline * Add preview to template dialog * Consider ways to further improve pages for use in continuous mode WARNING: * Right now the template dialog gets overridden by the advanced transclusion dialog because they have the same symbolic name and the latter is registered later than the former. To test the template dialog, just change the symbolic name of the advanced transclusion dialog. Change-Id: I51e74b322aec9a4c3918e6f792bdb3d318060979
2013-12-02 20:10:55 +00:00
}
}
}
return -1;
};
Refactor Transclusion and Meta dialogs to use BookletLayout Use OOJS-UI's newly-extended paged dialogs (in e08eb2a03b) to refactor how the Transclusion and Meta dialogs work, splitting out the code for each of the panels into its own file and simplifying extensibility. The Meta dialog (ve.ui.MWMetaDialog) now has two self-managing panels: * ve.ui.MWCategoriesPage for categories and the default sort key * ve.ui.MWLanguagesPage for language links The Transclusion dialog (ve.ui.MWTransclusionDialog) now has four: * ve.ui.MWTemplatePage for a template's primary panel * ve.ui.MWTemplateParameterPage for each parameter of a template * ve.ui.MWTemplatePlaceholderPage for a placeholder to insert a template * ve.ui.MWTransclusionContentPage for non-template transclusion Additionally, the Transclusion dialog has been slightly cleaned up: * Replace add/remove events with replace events in transclusion model * Actually return and resolve a promise (as documented) * Get rid of "origin" info in template models * Add method for adding required parts TODO: * Decide how and when we will choose between advanced transclusion and template dialogs * Work out design issues with how template descriptions will be visible and how adding parameters will work if only showing parameters in outline * Add preview to template dialog * Consider ways to further improve pages for use in continuous mode WARNING: * Right now the template dialog gets overridden by the advanced transclusion dialog because they have the same symbolic name and the latter is registered later than the former. To test the template dialog, just change the symbolic name of the advanced transclusion dialog. Change-Id: I51e74b322aec9a4c3918e6f792bdb3d318060979
2013-12-02 20:10:55 +00:00
/**
* Add missing required and suggested parameters to each transclusion.
*/
ve.dm.MWTransclusionModel.prototype.addPromptedParameters = function () {
this.parts.forEach( ( part ) => {
if ( part instanceof ve.dm.MWTemplateModel ) {
part.addPromptedParameters();
}
} );
};
/**
* @return {boolean} True if any transclusion part contains meaningful, non-default user input
*/
ve.dm.MWTransclusionModel.prototype.containsValuableData = function () {
return this.parts.some( ( part ) => part.containsValuableData() );
};
/**
* Resets the model's state.
*/
ve.dm.MWTransclusionModel.prototype.reset = function () {
this.parts = [];
this.uid = 0;
this.templateDataApiRequests = [];
this.changeQueue = [];
};
// Temporary compatibility for https://github.com/femiwiki/Sanctions/pull/118. Remove when not
// needed any more.
mw.log.deprecate( ve.dm.MWTransclusionModel.prototype, 'abortRequests',
ve.dm.MWTransclusionModel.prototype.abortAllApiRequests,
'Use "abortAllApiRequests" instead.'
);
}() );