Paragraph->heading conversion was broken when cursor next to an inline node

In this case, selectNodes() returns the paragraph, which is not a content
node, and so newFromContentBranchConversion() decides to do nothing at all.

This change makes newFromContentBranchConversion() more intelligent about
finding the content branch to operate on, fixing cases such as these
where selectNodes() returns the content branch itself rather than one of
its children.

Bug: 41203
Change-Id: I710fbf184ef5ef84d9c2f5bca2b115e0660f5b8f
This commit is contained in:
Roan Kattouw 2013-04-26 16:49:43 -07:00 committed by Catrope
parent b010e491bc
commit e89e991037
3 changed files with 116 additions and 2 deletions

View file

@ -396,8 +396,8 @@ ve.dm.Transaction.newFromContentBranchConversion = function ( doc, range, type,
// Replace the wrappings of each content branch in the range
for ( i = 0; i < selection.length; i++ ) {
selected = selection[i];
if ( selected.node.isContent() ) {
branch = selected.node.getParent();
branch = selected.node.isContent() ? selected.node.getParent() : selected.node;
if ( branch.canContainContent() ) {
// Skip branches that are already of the target type and have identical attributes
if ( branch.getType() === type && ve.compareObjects( branch.getAttributes(), attr ) ) {
continue;

View file

@ -800,6 +800,7 @@ QUnit.test( 'newFromAnnotation', function ( assert ) {
QUnit.test( 'newFromContentBranchConversion', function ( assert ) {
var i, key, store,
doc = ve.dm.example.createExampleDocument(),
doc2 = ve.dm.example.createExampleDocument( 'inlineAtEdges' ),
cases = {
'range inside a heading, convert to paragraph': {
'args': [doc, new ve.Range( 1, 2 ), 'paragraph'],
@ -847,6 +848,102 @@ QUnit.test( 'newFromContentBranchConversion', function ( assert ) {
},
{ 'type': 'retain', 'length': 3 }
]
},
'zero-length range before inline node at the start': {
'args': [doc2, new ve.Range( 1, 1 ), 'heading', { 'level': 2 }],
'ops': [
{
'type': 'replace',
'remove': [{ 'type': 'paragraph' }],
'insert': [{ 'type': 'heading', 'attributes': { 'level': 2 } }]
},
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [{ 'type': '/paragraph' }],
'insert': [{ 'type': '/heading' }]
}
]
},
'zero-length range inside inline node at the start': {
'args': [doc2, new ve.Range( 2, 2 ), 'heading', { 'level': 2 }],
'ops': [
{
'type': 'replace',
'remove': [{ 'type': 'paragraph' }],
'insert': [{ 'type': 'heading', 'attributes': { 'level': 2 } }]
},
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [{ 'type': '/paragraph' }],
'insert': [{ 'type': '/heading' }]
}
]
},
'zero-length range after inline node at the start': {
'args': [doc2, new ve.Range( 3, 3 ), 'heading', { 'level': 2 }],
'ops': [
{
'type': 'replace',
'remove': [{ 'type': 'paragraph' }],
'insert': [{ 'type': 'heading', 'attributes': { 'level': 2 } }]
},
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [{ 'type': '/paragraph' }],
'insert': [{ 'type': '/heading' }]
}
]
},
'zero-length range before inline node at the end': {
'args': [doc2, new ve.Range( 6, 6 ), 'heading', { 'level': 2 }],
'ops': [
{
'type': 'replace',
'remove': [{ 'type': 'paragraph' }],
'insert': [{ 'type': 'heading', 'attributes': { 'level': 2 } }]
},
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [{ 'type': '/paragraph' }],
'insert': [{ 'type': '/heading' }]
}
]
},
'zero-length range inside inline node at the end': {
'args': [doc2, new ve.Range( 7, 7 ), 'heading', { 'level': 2 }],
'ops': [
{
'type': 'replace',
'remove': [{ 'type': 'paragraph' }],
'insert': [{ 'type': 'heading', 'attributes': { 'level': 2 } }]
},
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [{ 'type': '/paragraph' }],
'insert': [{ 'type': '/heading' }]
}
]
},
'zero-length range after inline node at the end': {
'args': [doc2, new ve.Range( 8, 8 ), 'heading', { 'level': 2 }],
'ops': [
{
'type': 'replace',
'remove': [{ 'type': 'paragraph' }],
'insert': [{ 'type': 'heading', 'attributes': { 'level': 2 } }]
},
{ 'type': 'retain', 'length': 7 },
{
'type': 'replace',
'remove': [{ 'type': '/paragraph' }],
'insert': [{ 'type': '/heading' }]
},
]
}
};
QUnit.expect( ve.getObjectKeys( cases ).length );

View file

@ -627,6 +627,23 @@ ve.dm.example.complexTable = [
{ 'type': '/table' }
];
ve.dm.example.inlineAtEdges = [
{ 'type': 'paragraph' },
{ 'type': 'image', 'attributes': {
'html/0/src': ve.dm.example.imgSrc,
'src': ve.dm.example.imgSrc,
'width': null,
'height': null
} },
{ 'type': '/image' },
'F',
'o',
'o',
{ 'type': 'alienInline', 'attributes': { 'html': '<foobar />' } },
{ 'type': '/alienInline' },
{ 'type': '/paragraph' }
];
/**
* Sample content data index.
*