Merge "[BREAKING CHANGE] Evalute block/inline state when inserting a transclusion node"

This commit is contained in:
jenkins-bot 2016-05-16 08:27:52 +00:00 committed by Gerrit Code Review
commit 7a69ae68ab
4 changed files with 130 additions and 60 deletions

View file

@ -87,6 +87,33 @@ ve.ce.MWTransclusionNode.static.getDescription = function ( model ) {
.join( ve.msg( 'comma-separator' ) );
};
/**
* Filter rendering to remove auto-generated content and wrappers
*
* @static
* @param {HTMLElement[]} contentNodes Rendered nodes
* @return {HTMLElement[]} Filtered rendered nodes
*/
ve.ce.MWTransclusionNode.static.filterRendering = function ( contentNodes ) {
// Filter out auto-generated items, e.g. reference lists
contentNodes = contentNodes.filter( function ( node ) {
var dataMw = node.nodeType === Node.ELEMENT_NODE &&
node.hasAttribute( 'data-mw' ) &&
JSON.parse( node.getAttribute( 'data-mw' ) );
if ( dataMw && dataMw.autoGenerated ) {
return false;
}
return true;
} );
// HACK: if $content consists of a single paragraph, unwrap it.
// We have to do this because the parser wraps everything in <p>s, and inline templates
// will render strangely when wrapped in <p>s.
if ( contentNodes.length === 1 && contentNodes[ 0 ].nodeName.toLowerCase() === 'p' ) {
contentNodes = Array.prototype.slice.apply( contentNodes[ 0 ].childNodes );
}
return contentNodes;
};
/* Methods */
/**
@ -122,24 +149,7 @@ ve.ce.MWTransclusionNode.prototype.onParseSuccess = function ( deferred, respons
// Work around https://github.com/jquery/jquery/issues/1997
contentNodes = $.parseHTML( response.visualeditor.content, this.getModelHtmlDocument() ) || [];
// Filter out auto-generated items, e.g. reference lists
contentNodes = contentNodes.filter( function ( node ) {
var dataMw = node.nodeType === Node.ELEMENT_NODE &&
node.hasAttribute( 'data-mw' ) &&
JSON.parse( node.getAttribute( 'data-mw' ) );
if ( dataMw && dataMw.autoGenerated ) {
return false;
}
return true;
} );
// HACK: if $content consists of a single paragraph, unwrap it.
// We have to do this because the parser wraps everything in <p>s, and inline templates
// will render strangely when wrapped in <p>s.
if ( contentNodes.length === 1 && contentNodes[ 0 ].nodeName.toLowerCase() === 'p' ) {
contentNodes = Array.prototype.slice.apply( contentNodes[ 0 ].childNodes );
}
deferred.resolve( contentNodes );
deferred.resolve( this.constructor.static.filterRendering( contentNodes ) );
};
/**

View file

@ -50,19 +50,63 @@
/**
* Insert transclusion at the end of a surface fragment.
*
* @param {ve.dm.SurfaceFragment} surfaceFragment Surface fragment to insert at
* 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 {boolean|undefined} [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 ) {
surfaceFragment
.insertContent( [
{
type: 'mwTransclusionInline',
attributes: {
mw: this.getPlainObject()
ve.dm.MWTransclusionModel.prototype.insertTransclusionNode = function ( surfaceFragment, forceType ) {
var model = this,
deferred = $.Deferred(),
nodeClass = ve.dm.MWTransclusionNode;
function insertNode( isInline ) {
var type = isInline ? nodeClass.static.inlineType : nodeClass.static.blockType;
surfaceFragment
.insertContent( [
{
type: type,
attributes: {
mw: model.getPlainObject()
}
},
{ type: '/' + type }
] );
deferred.resolve();
}
if ( forceType ) {
insertNode( forceType === 'inline' );
} else {
new mw.Api().post( {
action: 'visualeditor',
paction: 'parsefragment',
page: mw.config.get( 'wgRelevantPageName' ),
wikitext: nodeClass.static.getWikitext( this.getPlainObject() ),
pst: 1
} )
.then( function ( response ) {
var contentNodes;
if ( ve.getProp( response, 'visualeditor', 'result' ) === 'success' ) {
contentNodes = $.parseHTML( response.visualeditor.content, surfaceFragment.getDocument().getHtmlDocument() ) || [];
contentNodes = ve.ce.MWTransclusionNode.static.filterRendering( contentNodes );
insertNode(
nodeClass.static.isHybridInline( contentNodes, ve.dm.converter )
);
} else {
// Request failed - just assume inline
insertNode( true );
}
},
{ type: '/mwTransclusionInline' }
] );
}, function () {
insertNode( true );
} );
}
return deferred.promise();
};
/**

View file

@ -268,6 +268,41 @@ ve.dm.MWTransclusionNode.static.escapeParameter = function ( param ) {
return output;
};
/**
* Get the wikitext for this transclusion.
*
* @static
* @param {Object} content MW data content
* @return {string} Wikitext like `{{foo|1=bar|baz=quux}}`
*/
ve.dm.MWTransclusionNode.static.getWikitext = function ( content ) {
var i, len, part, template, param,
wikitext = '';
// Normalize to multi template format
if ( content.params ) {
content = { parts: [ { template: content } ] };
}
// Build wikitext from content
for ( i = 0, len = content.parts.length; i < len; i++ ) {
part = content.parts[ i ];
if ( part.template ) {
// Template
template = part.template;
wikitext += '{{' + template.target.wt;
for ( param in template.params ) {
wikitext += '|' + param + '=' +
this.escapeParameter( template.params[ param ].wt );
}
wikitext += '}}';
} else {
// Plain wikitext
wikitext += part;
}
}
return wikitext;
};
/* Methods */
/**
@ -350,38 +385,13 @@ ve.dm.MWTransclusionNode.prototype.getPartsList = function () {
};
/**
* Get the wikitext for this transclusion.
* Wrapper for static method
*
* @method
* @return {string} Wikitext like `{{foo|1=bar|baz=quux}}`
*/
ve.dm.MWTransclusionNode.prototype.getWikitext = function () {
var i, len, part, template, param,
content = this.getAttribute( 'mw' ),
wikitext = '';
// Normalize to multi template format
if ( content.params ) {
content = { parts: [ { template: content } ] };
}
// Build wikitext from content
for ( i = 0, len = content.parts.length; i < len; i++ ) {
part = content.parts[ i ];
if ( part.template ) {
// Template
template = part.template;
wikitext += '{{' + template.target.wt;
for ( param in template.params ) {
wikitext += '|' + param + '=' +
this.constructor.static.escapeParameter( template.params[ param ].wt );
}
wikitext += '}}';
} else {
// Plain wikitext
wikitext += part;
}
}
return wikitext;
return this.constructor.static.getWikitext( this.getAttribute( 'mw' ) );
};
/* Concrete subclasses */

View file

@ -414,19 +414,25 @@ ve.ui.MWTemplateDialog.prototype.getActionProcess = function ( action ) {
return new OO.ui.Process( function () {
var deferred = $.Deferred();
dialog.checkRequiredParameters().done( function () {
var surfaceModel = dialog.getFragment().getSurface(),
var modelPromise,
surfaceModel = dialog.getFragment().getSurface(),
obj = dialog.transclusionModel.getPlainObject();
dialog.pushPending();
if ( dialog.selectedNode instanceof ve.dm.MWTransclusionNode ) {
dialog.transclusionModel.updateTransclusionNode( surfaceModel, dialog.selectedNode );
// TODO: updating the node could result in the inline/block state change
modelPromise = $.Deferred().resolve().promise();
} else if ( obj !== null ) {
// Collapse returns a new fragment, so update dialog.fragment
dialog.fragment = dialog.getFragment().collapseToEnd();
dialog.transclusionModel.insertTransclusionNode( dialog.getFragment() );
modelPromise = dialog.transclusionModel.insertTransclusionNode( dialog.getFragment() );
}
dialog.pushPending();
dialog.close( { action: action } ).always( dialog.popPending.bind( dialog ) );
return modelPromise.then( function () {
dialog.close( { action: action } ).always( dialog.popPending.bind( dialog ) );
} );
} ).always( deferred.resolve );
return deferred;