mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-09-25 11:16:51 +00:00
(bug 42119) Handle alienation in wrapping mode properly
When alienating in wrapping mode, we need to look at the type of tag to decide whether to create a wrapped alienInline, or to interrupt the paragraph for an alienBlock. This was being done just fine for the general alienation case (unrecognized tag), but not for the special cases (mw:unrecognized, about groups). * Centralize the logic for ending a wrapper in stopWrapping() * Move the wrapping-contingent block/inline detection logic into createAlien() * Simplify the terrible if statement to decide whether a future decision requires us to stop wrapping. Instead, detect the cases in each code path separately and call stopWrapping() as appropriate * Add tests Change-Id: I4054584ae05e7d5daa71edead3e6a6588cf5d3bb
This commit is contained in:
parent
f71247608b
commit
662880605c
|
@ -207,8 +207,11 @@ ve.dm.Converter.prototype.getDomElementFromDataAnnotation = function ( dataAnnot
|
||||||
* @returns {Array} Linear model data
|
* @returns {Array} Linear model data
|
||||||
*/
|
*/
|
||||||
ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, dataElement, path, alreadyWrapped ) {
|
ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, dataElement, path, alreadyWrapped ) {
|
||||||
function createAlien( domElement, isInline, isWrapper ) {
|
function createAlien( domElement, branchIsContent, isWrapper ) {
|
||||||
var type = isInline ? 'alienInline' : 'alienBlock', html;
|
// If we're in wrapping mode, we don't know if this alien is supposed to be block
|
||||||
|
// or inline, so detect it based on the HTML tag name.
|
||||||
|
var isInline = wrapping ? !ve.isBlockElement( domElement ) : branchIsContent,
|
||||||
|
type = isInline ? 'alienInline' : 'alienBlock', html;
|
||||||
if ( isWrapper ) {
|
if ( isWrapper ) {
|
||||||
html = $( domElement ).html();
|
html = $( domElement ).html();
|
||||||
} else {
|
} else {
|
||||||
|
@ -248,6 +251,18 @@ ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, d
|
||||||
nextWhitespace = '';
|
nextWhitespace = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function stopWrapping() {
|
||||||
|
if ( wrappedWhitespace !== '' ) {
|
||||||
|
// Remove wrappedWhitespace from data
|
||||||
|
data.splice( -wrappedWhitespace.length, wrappedWhitespace.length );
|
||||||
|
addWhitespace( wrappingParagraph, 3, wrappedWhitespace );
|
||||||
|
nextWhitespace = wrappedWhitespace;
|
||||||
|
}
|
||||||
|
data.push( { 'type': '/paragraph' } );
|
||||||
|
wrappingParagraph = undefined;
|
||||||
|
wrapping = false;
|
||||||
|
wrappingIsOurs = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to group adjacent child elements with the same about attribute together.
|
* Helper function to group adjacent child elements with the same about attribute together.
|
||||||
|
@ -334,6 +349,9 @@ ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, d
|
||||||
// Alienate about groups
|
// Alienate about groups
|
||||||
if ( childDomElement.hasAttribute( 'data-ve-aboutgroup' ) ) {
|
if ( childDomElement.hasAttribute( 'data-ve-aboutgroup' ) ) {
|
||||||
alien = createAlien( childDomElement, branchIsContent, true );
|
alien = createAlien( childDomElement, branchIsContent, true );
|
||||||
|
if ( wrapping && alien[0].type === 'alienBlock' ) {
|
||||||
|
stopWrapping();
|
||||||
|
}
|
||||||
data = data.concat( alien );
|
data = data.concat( alien );
|
||||||
processNextWhitespace( alien[0] );
|
processNextWhitespace( alien[0] );
|
||||||
prevElement = alien[0];
|
prevElement = alien[0];
|
||||||
|
@ -391,6 +409,9 @@ ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, d
|
||||||
!rdfaType.match( /^mw:Entity/ )
|
!rdfaType.match( /^mw:Entity/ )
|
||||||
) {
|
) {
|
||||||
alien = createAlien( childDomElement, branchIsContent );
|
alien = createAlien( childDomElement, branchIsContent );
|
||||||
|
if ( wrapping && alien[0].type === 'alienBlock' ) {
|
||||||
|
stopWrapping();
|
||||||
|
}
|
||||||
data = data.concat( alien );
|
data = data.concat( alien );
|
||||||
processNextWhitespace( alien[0] );
|
processNextWhitespace( alien[0] );
|
||||||
prevElement = alien[0];
|
prevElement = alien[0];
|
||||||
|
@ -426,32 +447,12 @@ ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, d
|
||||||
|
|
||||||
// Look up child element type
|
// Look up child element type
|
||||||
childDataElement = this.getDataElementFromDomElement( childDomElement );
|
childDataElement = this.getDataElementFromDomElement( childDomElement );
|
||||||
// End auto-wrapping of bare content from a previously processed node
|
|
||||||
// but only if childDataElement is a non-content element or if
|
|
||||||
// we are about to produce a block alien
|
|
||||||
if (
|
|
||||||
wrapping && (
|
|
||||||
(
|
|
||||||
childDataElement &&
|
|
||||||
!ve.dm.nodeFactory.isNodeContent( childDataElement.type )
|
|
||||||
) || (
|
|
||||||
!childDataElement &&
|
|
||||||
ve.isBlockElement( childDomElement )
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if ( wrappedWhitespace !== '' ) {
|
|
||||||
// Remove wrappedWhitespace from data
|
|
||||||
data.splice( -wrappedWhitespace.length, wrappedWhitespace.length );
|
|
||||||
addWhitespace( wrappingParagraph, 3, wrappedWhitespace );
|
|
||||||
nextWhitespace = wrappedWhitespace;
|
|
||||||
}
|
|
||||||
data.push( { 'type': '/paragraph' } );
|
|
||||||
wrappingParagraph = undefined;
|
|
||||||
wrapping = false;
|
|
||||||
wrappingIsOurs = false;
|
|
||||||
}
|
|
||||||
if ( childDataElement ) {
|
if ( childDataElement ) {
|
||||||
|
// End auto-wrapping of bare content from a previously processed node
|
||||||
|
// but only if childDataElement is a non-content element
|
||||||
|
if ( wrapping && !ve.dm.nodeFactory.isNodeContent( childDataElement.type ) ) {
|
||||||
|
stopWrapping();
|
||||||
|
}
|
||||||
if ( ve.dm.nodeFactory.canNodeHaveChildren( childDataElement.type ) ) {
|
if ( ve.dm.nodeFactory.canNodeHaveChildren( childDataElement.type ) ) {
|
||||||
// Append child element data
|
// Append child element data
|
||||||
data = data.concat(
|
data = data.concat(
|
||||||
|
@ -473,12 +474,12 @@ ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, d
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We don't know what this is, fall back to alien.
|
// We don't know what this is, fall back to alien.
|
||||||
// If we're in wrapping mode, we don't know if this alien is
|
alien = createAlien( childDomElement, branchIsContent );
|
||||||
// supposed to be block or inline, so detect it based on the HTML
|
// End auto-wrapping of bare content from a previously processed node
|
||||||
// tag name.
|
// but only if we produced an alienBlock
|
||||||
alien = createAlien( childDomElement, wrapping ?
|
if ( wrapping && alien[0].type === 'alienBlock' ) {
|
||||||
!ve.isBlockElement( childDomElement ) : branchIsContent
|
stopWrapping();
|
||||||
);
|
}
|
||||||
data = data.concat( alien );
|
data = data.concat( alien );
|
||||||
processNextWhitespace( alien[0] );
|
processNextWhitespace( alien[0] );
|
||||||
prevElement = alien[0];
|
prevElement = alien[0];
|
||||||
|
@ -627,15 +628,9 @@ ve.dm.Converter.prototype.getDataFromDom = function ( domElement, annotations, d
|
||||||
}
|
}
|
||||||
// End auto-wrapping of bare content
|
// End auto-wrapping of bare content
|
||||||
if ( wrapping && wrappingIsOurs ) {
|
if ( wrapping && wrappingIsOurs ) {
|
||||||
if ( wrappedWhitespace !== '' ) {
|
stopWrapping();
|
||||||
// Remove wrappedWhitespace from data
|
|
||||||
data.splice( -wrappedWhitespace.length, wrappedWhitespace.length );
|
|
||||||
addWhitespace( wrappingParagraph, 3, wrappedWhitespace );
|
|
||||||
nextWhitespace = wrappedWhitespace;
|
|
||||||
}
|
|
||||||
data.push( { 'type': '/paragraph' } );
|
|
||||||
// Don't set wrapping = false here because it's checked below
|
// Don't set wrapping = false here because it's checked below
|
||||||
wrappingParagraph = undefined;
|
wrapping = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're closing a node that doesn't have any children, but could contain a paragraph,
|
// If we're closing a node that doesn't have any children, but could contain a paragraph,
|
||||||
|
|
|
@ -694,6 +694,52 @@ ve.dm.example.domToDataCases = {
|
||||||
{ 'type': '/paragraph' }
|
{ 'type': '/paragraph' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
'wrapping of bare content with mw:unrecognized inline alien': {
|
||||||
|
'html': '1<span typeof="mw:Placeholder">baz</span>2',
|
||||||
|
'data': [
|
||||||
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
||||||
|
'1',
|
||||||
|
{
|
||||||
|
'type': 'alienInline',
|
||||||
|
'attributes': { 'html': '<span typeof="mw:Placeholder">baz</span>' }
|
||||||
|
},
|
||||||
|
{ 'type': '/alienInline' },
|
||||||
|
'2',
|
||||||
|
{ 'type': '/paragraph' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'wrapping of bare content with mw:unrecognized block alien': {
|
||||||
|
'html': '1<div typeof="mw:Placeholder">baz</div>2',
|
||||||
|
'data': [
|
||||||
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
||||||
|
'1',
|
||||||
|
{ 'type': '/paragraph' },
|
||||||
|
{
|
||||||
|
'type': 'alienBlock',
|
||||||
|
'attributes': { 'html': '<div typeof="mw:Placeholder">baz</div>' }
|
||||||
|
},
|
||||||
|
{ 'type': '/alienBlock' },
|
||||||
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
||||||
|
'2',
|
||||||
|
{ 'type': '/paragraph' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'wrapping of bare content with about group': {
|
||||||
|
'html': '1<tt about="#mwt1">foo</tt><tt about="#mwt1">bar</tt>2',
|
||||||
|
'data': [
|
||||||
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
||||||
|
'1',
|
||||||
|
{ 'type': '/paragraph' },
|
||||||
|
{
|
||||||
|
'type': 'alienBlock',
|
||||||
|
'attributes': { 'html': '<tt about="#mwt1">foo</tt><tt about="#mwt1">bar</tt>' }
|
||||||
|
},
|
||||||
|
{ 'type': '/alienBlock' },
|
||||||
|
{ 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } },
|
||||||
|
'2',
|
||||||
|
{ 'type': '/paragraph' }
|
||||||
|
]
|
||||||
|
},
|
||||||
'wrapping of bare content between structural nodes': {
|
'wrapping of bare content between structural nodes': {
|
||||||
'html': '<table></table>abc<table></table>',
|
'html': '<table></table>abc<table></table>',
|
||||||
'data': [
|
'data': [
|
||||||
|
|
Loading…
Reference in a new issue