From 3b19330db383bb19f256f322fa67b02c9f6ad437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 6 Dec 2018 13:51:14 +0100 Subject: [PATCH 01/19] Update selection post-fixer tests to reflect tables structure. --- tests/model/utils/selection-post-fixer.js | 194 +++++++++++++++++----- 1 file changed, 150 insertions(+), 44 deletions(-) diff --git a/tests/model/utils/selection-post-fixer.js b/tests/model/utils/selection-post-fixer.js index 60e25898a..2a45c778f 100644 --- a/tests/model/utils/selection-post-fixer.js +++ b/tests/model/utils/selection-post-fixer.js @@ -27,8 +27,9 @@ describe( 'Selection post-fixer', () => { model.schema.register( 'table', { allowWhere: '$block', - isObject: true, - isLimit: true + allowAttributes: [ 'headingRows', 'headingColumns' ], + isLimit: true, + isObject: true } ); model.schema.register( 'tableRow', { @@ -38,15 +39,18 @@ describe( 'Selection post-fixer', () => { model.schema.register( 'tableCell', { allowIn: 'tableRow', - allowContentOf: '$block', + allowAttributes: [ 'colspan', 'rowspan' ], isLimit: true } ); model.schema.register( 'image', { - allowIn: '$root', - isObject: true + isObject: true, + isBlock: true, + allowWhere: '$block' } ); + model.schema.extend( '$block', { allowIn: 'tableCell' } ); + model.schema.register( 'caption', { allowIn: 'image', allowContentOf: '$block', @@ -98,13 +102,16 @@ describe( 'Selection post-fixer', () => { setModelData( model, '[]foo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'bar' ); } ); - it( 'should fix #1', () => { + it( 'should fix #1 - range start outside table, end on table cell', () => { // f[oo]... model.change( writer => { writer.setSelection( writer.createRange( @@ -116,13 +123,16 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'f[oo' + '
' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
]' + 'bar' ); } ); - it( 'should fix #2', () => { + it( 'should fix #2 - range start on table cell, end outside table', () => { // ...[
b]ar model.change( writer => { writer.setSelection( writer.createRange( @@ -134,7 +144,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '[' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'b]ar' ); @@ -152,7 +165,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'f[oo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
]' + 'bar' ); @@ -162,15 +178,18 @@ describe( 'Selection post-fixer', () => { // fooa[aab]bb model.change( writer => { writer.setSelection( writer.createRange( - writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ).getChild( 0 ), 1 ), - writer.createPositionAt( modelRoot.getChild( 1 ).getChild( 0 ).getChild( 1 ), 2 ) + writer.createPositionAt( modelRoot.getNodeByPath( [ 1, 0, 0, 0 ] ), 1 ), + writer.createPositionAt( modelRoot.getNodeByPath( [ 1, 0, 1, 0 ] ), 2 ) ) ); } ); expect( getModelData( model ) ).to.equal( 'foo' + '[
' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
]' + 'bar' ); @@ -180,11 +199,17 @@ describe( 'Selection post-fixer', () => { setModelData( model, 'foo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + '[]' + '' + - 'xxxyyy' + + '' + + 'xxx' + + 'yyy' + + '' + '
' + 'baz' ); @@ -192,10 +217,16 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '[' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
]' + '' + - 'xxxyyy' + + '' + + 'xxx' + + 'yyy' + + '' + '
' + 'baz' ); @@ -208,7 +239,10 @@ describe( 'Selection post-fixer', () => { setModelData( model, 'foo' + '' + - '[aaabbb]' + + '[' + + 'aaa' + + 'bbb' + + ']' + '
' + 'baz' ); @@ -216,7 +250,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '[' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
]' + 'baz' ); @@ -226,9 +263,18 @@ describe( 'Selection post-fixer', () => { setModelData( model, 'foo' + '' + - '[12' + - '34]' + - '56' + + '[' + + '1' + + '2' + + '' + + '' + + '3' + + '4]' + + '' + + '' + + '5' + + '6' + + '' + '
' + 'baz' ); @@ -236,9 +282,18 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '[' + - '12' + - '34' + - '56' + + '' + + '1' + + '2' + + '' + + '' + + '3' + + '4' + + '' + + '' + + '5' + + '6' + + '' + '
]' + 'baz' ); @@ -270,11 +325,14 @@ describe( 'Selection post-fixer', () => { ); } ); - it( 'should not fix #1', () => { + it( 'should not fix #1 - selection over paragraphs outside table', () => { setModelData( model, 'foo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'b[ar' + 'ba]z' @@ -283,7 +341,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'b[ar' + 'ba]z' @@ -308,7 +369,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'f[oo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
]' + 'bar' ); @@ -333,7 +397,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'f[oo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'ba]r' ); @@ -343,10 +410,22 @@ describe( 'Selection post-fixer', () => { setModelData( model, 'foo' + '' + - '[aaabbb' + - '][aaabbb' + - '][aaabbb' + - '][aaabbb' + + '' + + '[aaa' + + 'bbb' + + '' + + ']' + + '[aaa' + + 'bbb' + + '' + + ']' + + '[aaa' + + 'bbb' + + '' + + ']' + + '[aaa' + + 'bbb' + + '' + '
' + 'b]az' ); @@ -354,10 +433,22 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '[' + - 'aaabbb' + - 'aaabbb' + - 'aaabbb' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + + '' + + 'aaa' + + 'bbb' + + '' + + '' + + 'aaa' + + 'bbb' + + '' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'b]az' ); @@ -386,7 +477,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'f[oo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'bar]' ); @@ -722,7 +816,10 @@ describe( 'Selection post-fixer', () => { setModelData( model, '[]foo' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'bar' ); @@ -739,7 +836,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo[]' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'bar' ); @@ -758,7 +858,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( 'foo' + '' + - '[]aaabbb' + + '' + + '[]aaa' + + 'bbb' + + '' + '
' + 'bar' ); @@ -778,7 +881,10 @@ describe( 'Selection post-fixer', () => { expect( getModelData( model ) ).to.equal( '[foo]' + '' + - 'aaabbb' + + '' + + 'aaa' + + 'bbb' + + '' + '
' + 'bar' ); From efa318b32e664eec6589d92981fd8b61d95189ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 6 Dec 2018 14:28:08 +0100 Subject: [PATCH 02/19] Remove redundant plugins from table manual test. --- src/model/utils/selection-post-fixer.js | 47 ++++++++++++++++------- tests/model/utils/selection-post-fixer.js | 28 ++++++++++++++ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index abfa23fea..dc9da0391 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -159,6 +159,7 @@ function tryFixingCollapsedRange( range, schema ) { // // @param {module:engine/model/range~Range} range Expanded range to fix. // @param {module:engine/model/schema~Schema} schema + // @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid. function tryFixingNonCollapsedRage( range, schema ) { const start = range.start; @@ -197,13 +198,23 @@ function tryFixingNonCollapsedRage( range, schema ) { // At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element // then the range crossed limit element boundaries and needs to be fixed. if ( isStartInLimit || isEndInLimit ) { + const bothInSameParent = ( !!start.nodeAfter && !!end.nodeBefore ) && start.nodeAfter === end.nodeBefore; + + const expandStart = isStartInLimit && ( !bothInSameParent || !isInObject( start.nodeAfter, schema ) ); + const expandEnd = isEndInLimit && ( !bothInSameParent || !isInObject( end.nodeBefore, schema ) ); + // Although we've already found limit element on start/end positions we must find the outer-most limit element. // as limit elements might be nested directly inside (ie table > tableRow > tableCell). - const startPosition = Position._createAt( startLimitElement, 0 ); - const endPosition = Position._createAt( endLimitElement, 0 ); + let fixedStart = start; + let fixedEnd = end; - const fixedStart = isStartInLimit ? expandSelectionOnIsLimitNode( startPosition, schema, 'start' ) : start; - const fixedEnd = isEndInLimit ? expandSelectionOnIsLimitNode( endPosition, schema, 'end' ) : end; + if ( expandStart ) { + fixedStart = Position._createBefore( findOuterMostIsLimitAncestor( startLimitElement, schema ) ); + } + + if ( expandEnd ) { + fixedEnd = Position._createAfter( findOuterMostIsLimitAncestor( endLimitElement, schema ) ); + } return new Range( fixedStart, fixedEnd ); } @@ -212,24 +223,23 @@ function tryFixingNonCollapsedRage( range, schema ) { return null; } -// Expands selection so it contains whole limit node. +// Finds the outer-most ancestor. // -// @param {module:engine/model/position~Position} position +// @param {module:engine/model/node~Node} startingNode // @param {module:engine/model/schema~Schema} schema // @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range. -// @returns {module:engine/model/position~Position} -function expandSelectionOnIsLimitNode( position, schema, expandToDirection ) { - let node = position.parent; - let parent = node; +// @returns {module:engine/model/node~Node} +function findOuterMostIsLimitAncestor( startingNode, schema ) { + let isLimitNode = startingNode; + let parent = isLimitNode; // Find outer most isLimit block as such blocks might be nested (ie. in tables). while ( schema.isLimit( parent ) && parent.parent ) { - node = parent; + isLimitNode = parent; parent = parent.parent; } - // Depending on direction of expanding selection return position before or after found node. - return expandToDirection === 'start' ? Position._createBefore( node ) : Position._createAfter( node ); + return isLimitNode; } // Checks whether both range ends are placed around non-limit elements. @@ -237,9 +247,20 @@ function expandSelectionOnIsLimitNode( position, schema, expandToDirection ) { // @param {module:engine/model/position~Position} start // @param {module:engine/model/position~Position} end // @param {module:engine/model/schema~Schema} schema +// @returns {Boolean} function checkSelectionOnNonLimitElements( start, end, schema ) { const startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' ); const endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' ); return startIsOnBlock && endIsOnBlock; } + +// Checks if node exists and if it's an object. +// +// @param {module:engine/model/node~Node} node +// @param {module:engine/model/schema~Schema} schema +// @returns {Boolean} +function isInObject( node, schema ) { + return node && schema.isObject( node ); +} + diff --git a/tests/model/utils/selection-post-fixer.js b/tests/model/utils/selection-post-fixer.js index 2a45c778f..0addabea3 100644 --- a/tests/model/utils/selection-post-fixer.js +++ b/tests/model/utils/selection-post-fixer.js @@ -351,6 +351,34 @@ describe( 'Selection post-fixer', () => { ); } ); + it( 'should not fix #2 - selection over image in table', () => { + setModelData( model, + 'foo' + + '' + + '' + + 'foo' + + '[]bbb' + + '' + + '
' + ); + + model.change( writer => { + const image = model.document.getRoot().getNodeByPath( [ 1, 0, 0, 1 ] ); + + writer.setSelection( writer.createRangeOn( image ) ); + } ); + + expect( getModelData( model ) ).to.equal( + 'foo' + + '' + + '' + + 'foo[]' + + 'bbb' + + '' + + '
' + ); + } ); + it( 'should fix multiple ranges #1', () => { model.change( writer => { const ranges = [ From ecffa73dd1c911b9cb81ce5fe233c47992cf7700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 6 Dec 2018 18:21:57 +0100 Subject: [PATCH 03/19] Make selection post-fixer should allow selection of an objects. --- src/model/utils/selection-post-fixer.js | 13 ++++-- tests/model/utils/selection-post-fixer.js | 56 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index dc9da0391..99ced7437 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -184,9 +184,14 @@ function tryFixingNonCollapsedRage( range, schema ) { // - [foo] -> [foo] // - [foo] -> [foo] // - f[oo] -> f[oo] + // TODO: make it nicer + // - [foo] -> [foo] if ( checkSelectionOnNonLimitElements( start, end, schema ) ) { - const fixedStart = schema.getNearestSelectionRange( start, 'forward' ); - const fixedEnd = schema.getNearestSelectionRange( end, 'backward' ); + const isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter ); + const fixedStart = isStartObject ? null : schema.getNearestSelectionRange( start, 'forward' ); + + const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); + const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' ); return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end ); } @@ -249,8 +254,8 @@ function findOuterMostIsLimitAncestor( startingNode, schema ) { // @param {module:engine/model/schema~Schema} schema // @returns {Boolean} function checkSelectionOnNonLimitElements( start, end, schema ) { - const startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' ); - const endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' ); + const startIsOnBlock = ( start.nodeAfter && schema.isBlock( start.nodeAfter ) ) || schema.checkChild( start, '$text' ); + const endIsOnBlock = ( end.nodeBefore && schema.isBlock( end.nodeBefore ) ) || schema.checkChild( end, '$text' ); return startIsOnBlock && endIsOnBlock; } diff --git a/tests/model/utils/selection-post-fixer.js b/tests/model/utils/selection-post-fixer.js index 0addabea3..3fc26c609 100644 --- a/tests/model/utils/selection-post-fixer.js +++ b/tests/model/utils/selection-post-fixer.js @@ -379,6 +379,62 @@ describe( 'Selection post-fixer', () => { ); } ); + it( 'should not fix #3 - selection over paragraph & image in table', () => { + setModelData( model, + 'foo' + + '' + + '' + + 'foo' + + '[]bbb' + + '' + + '
' + ); + + model.change( writer => { + const tableCell = model.document.getRoot().getNodeByPath( [ 1, 0, 0 ] ); + + writer.setSelection( writer.createRangeIn( tableCell ) ); + } ); + + expect( getModelData( model ) ).to.equal( + 'foo' + + '' + + '' + + '[foo]' + + 'bbb' + + '' + + '
' + ); + } ); + + it( 'should not fix #3 - selection over image & paragraph in table', () => { + setModelData( model, + 'foo' + + '' + + '' + + 'foo' + + '[]bbb' + + '' + + '
' + ); + + model.change( writer => { + const tableCell = model.document.getRoot().getNodeByPath( [ 1, 0, 0 ] ); + + writer.setSelection( writer.createRangeIn( tableCell ) ); + } ); + + expect( getModelData( model ) ).to.equal( + 'foo' + + '' + + '' + + '[foo]' + + 'bbb' + + '' + + '
' + ); + } ); + it( 'should fix multiple ranges #1', () => { model.change( writer => { const ranges = [ From 6e4794558c27ac49f11b3a2d4eec0b4cd27141b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Fri, 7 Dec 2018 11:39:23 +0100 Subject: [PATCH 04/19] Add tests for blockQuote in table in selection post-fixer tests. --- tests/model/utils/selection-post-fixer.js | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/model/utils/selection-post-fixer.js b/tests/model/utils/selection-post-fixer.js index 3fc26c609..2561fb700 100644 --- a/tests/model/utils/selection-post-fixer.js +++ b/tests/model/utils/selection-post-fixer.js @@ -407,7 +407,7 @@ describe( 'Selection post-fixer', () => { ); } ); - it( 'should not fix #3 - selection over image & paragraph in table', () => { + it( 'should not fix #4 - selection over image & paragraph in table', () => { setModelData( model, 'foo' + '' + @@ -435,6 +435,39 @@ describe( 'Selection post-fixer', () => { ); } ); + it( 'should not fix #4 - selection over blockQuote in table', () => { + model.schema.register( 'blockQuote', { + allowWhere: '$block', + allowContentOf: '$root' + } ); + + setModelData( model, + 'foo' + + '
' + + '' + + '
foo
' + + '[]bbb' + + '
' + + '
' + ); + + model.change( writer => { + const tableCell = model.document.getRoot().getNodeByPath( [ 1, 0, 0 ] ); + + writer.setSelection( writer.createRangeIn( tableCell ) ); + } ); + + expect( getModelData( model ) ).to.equal( + 'foo' + + '' + + '' + + '
[foo]
' + + 'bbb' + + '
' + + '
' + ); + } ); + it( 'should fix multiple ranges #1', () => { model.change( writer => { const ranges = [ From ef8352cb39b506514c5d34375555fc892817221f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Fri, 7 Dec 2018 12:32:49 +0100 Subject: [PATCH 05/19] Fix requirements checking on general elements in selection post-fixer. --- src/model/utils/selection-post-fixer.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 99ced7437..6bfa98c0b 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -184,8 +184,7 @@ function tryFixingNonCollapsedRage( range, schema ) { // - [foo] -> [foo] // - [foo] -> [foo] // - f[oo] -> f[oo] - // TODO: make it nicer - // - [foo] -> [foo] + // - [foo] -> [foo] if ( checkSelectionOnNonLimitElements( start, end, schema ) ) { const isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter ); const fixedStart = isStartObject ? null : schema.getNearestSelectionRange( start, 'forward' ); @@ -247,17 +246,18 @@ function findOuterMostIsLimitAncestor( startingNode, schema ) { return isLimitNode; } -// Checks whether both range ends are placed around non-limit elements. +// Checks whether one of range ends is placed around non-limit elements. // // @param {module:engine/model/position~Position} start // @param {module:engine/model/position~Position} end // @param {module:engine/model/schema~Schema} schema // @returns {Boolean} function checkSelectionOnNonLimitElements( start, end, schema ) { - const startIsOnBlock = ( start.nodeAfter && schema.isBlock( start.nodeAfter ) ) || schema.checkChild( start, '$text' ); - const endIsOnBlock = ( end.nodeBefore && schema.isBlock( end.nodeBefore ) ) || schema.checkChild( end, '$text' ); + const startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' ); + const endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' ); - return startIsOnBlock && endIsOnBlock; + // We should fix such selection when one of those nodes needs fixing. + return startIsOnBlock || endIsOnBlock; } // Checks if node exists and if it's an object. From 1d54e748b5c6d62f0be169ed2f9943030806bb64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Fri, 7 Dec 2018 12:56:42 +0100 Subject: [PATCH 06/19] Add test case for object in object case. --- tests/model/utils/selection-post-fixer.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/model/utils/selection-post-fixer.js b/tests/model/utils/selection-post-fixer.js index 2561fb700..9a2c9ad12 100644 --- a/tests/model/utils/selection-post-fixer.js +++ b/tests/model/utils/selection-post-fixer.js @@ -435,7 +435,7 @@ describe( 'Selection post-fixer', () => { ); } ); - it( 'should not fix #4 - selection over blockQuote in table', () => { + it( 'should not fix #5 - selection over blockQuote in table', () => { model.schema.register( 'blockQuote', { allowWhere: '$block', allowContentOf: '$root' @@ -926,6 +926,25 @@ describe( 'Selection post-fixer', () => { 'fo[ob]ar' ); } ); + + it( 'should not fix #4 - object in object', () => { + model.schema.register( 'div', { + allowWhere: '$block', + isObject: true + } ); + + model.schema.extend( 'div', { allowIn: 'div' } ); + + setModelData( model, '
[
]
' ); + + model.change( writer => { + const innerDiv = model.document.getRoot().getNodeByPath( [ 0, 0 ] ); + + writer.setSelection( writer.createRangeOn( innerDiv ) ); + } ); + + expect( getModelData( model ) ).to.equal( '
[
]
' ); + } ); } ); describe( 'collapsed selection', () => { From 33aa691d08f9f59ad967082c6c1107acc87c7178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Fri, 7 Dec 2018 12:59:16 +0100 Subject: [PATCH 07/19] Simplify 'should not fix #4 - object in object' test. --- tests/model/utils/selection-post-fixer.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/model/utils/selection-post-fixer.js b/tests/model/utils/selection-post-fixer.js index 9a2c9ad12..44311b627 100644 --- a/tests/model/utils/selection-post-fixer.js +++ b/tests/model/utils/selection-post-fixer.js @@ -929,12 +929,10 @@ describe( 'Selection post-fixer', () => { it( 'should not fix #4 - object in object', () => { model.schema.register( 'div', { - allowWhere: '$block', + allowIn: [ '$root', 'div' ], isObject: true } ); - model.schema.extend( 'div', { allowIn: 'div' } ); - setModelData( model, '
[
]
' ); model.change( writer => { From 6862a796ed9d7121a621a94970edb0c8bc15e79f Mon Sep 17 00:00:00 2001 From: Szymon Cofalik Date: Thu, 20 Dec 2018 09:58:05 +0100 Subject: [PATCH 08/19] Code style changes in selection-post-fixer. Co-Authored-By: jodator --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 6bfa98c0b..129025ef4 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -187,7 +187,7 @@ function tryFixingNonCollapsedRage( range, schema ) { // - [foo] -> [foo] if ( checkSelectionOnNonLimitElements( start, end, schema ) ) { const isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter ); - const fixedStart = isStartObject ? null : schema.getNearestSelectionRange( start, 'forward' ); + const fixedStart = isStartObject ? start : schema.getNearestSelectionRange( start, 'forward' ).start; const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' ); From d1a522fd0ba0c0620915cec6a30976d2365c2f1c Mon Sep 17 00:00:00 2001 From: Szymon Cofalik Date: Thu, 20 Dec 2018 09:58:21 +0100 Subject: [PATCH 09/19] Code style changes in selection-post-fixer. Co-Authored-By: jodator --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 129025ef4..e29e08498 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -190,7 +190,7 @@ function tryFixingNonCollapsedRage( range, schema ) { const fixedStart = isStartObject ? start : schema.getNearestSelectionRange( start, 'forward' ).start; const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); - const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' ); + const fixedEnd = isEndObject ? end : schema.getNearestSelectionRange( end, 'backward' ).end; return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end ); } From 92f9a9f984e92b003fb6d538b2c3776bce27d8f9 Mon Sep 17 00:00:00 2001 From: Szymon Cofalik Date: Thu, 20 Dec 2018 09:58:32 +0100 Subject: [PATCH 10/19] Code style changes in selection-post-fixer. Co-Authored-By: jodator --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index e29e08498..5096c3a15 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -192,7 +192,7 @@ function tryFixingNonCollapsedRage( range, schema ) { const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); const fixedEnd = isEndObject ? end : schema.getNearestSelectionRange( end, 'backward' ).end; - return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end ); + return new Range( fixedStart, fixedEnd ); } } From d1debb956d728d4ad95ca9c8c2dc4b79b77deba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:06:37 +0100 Subject: [PATCH 11/19] Fix code style because of Github. --- src/model/utils/selection-post-fixer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 5096c3a15..1510de54b 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -187,12 +187,12 @@ function tryFixingNonCollapsedRage( range, schema ) { // - [foo] -> [foo] if ( checkSelectionOnNonLimitElements( start, end, schema ) ) { const isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter ); - const fixedStart = isStartObject ? start : schema.getNearestSelectionRange( start, 'forward' ).start; + const fixedStart = isStartObject ? start : schema.getNearestSelectionRange( start, 'forward' ).start; const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); - const fixedEnd = isEndObject ? end : schema.getNearestSelectionRange( end, 'backward' ).end; + const fixedEnd = isEndObject ? end : schema.getNearestSelectionRange( end, 'backward' ).end; - return new Range( fixedStart, fixedEnd ); + return new Range( fixedStart, fixedEnd ); } } From 5a055e17013a91145c71db4d39434cd9f231a8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:08:59 +0100 Subject: [PATCH 12/19] Revert "Code style changes in selection-post-fixer." This reverts commit 92f9a9f9 --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 1510de54b..0aaec838f 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -192,7 +192,7 @@ function tryFixingNonCollapsedRage( range, schema ) { const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); const fixedEnd = isEndObject ? end : schema.getNearestSelectionRange( end, 'backward' ).end; - return new Range( fixedStart, fixedEnd ); + return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end ); } } From b16b0f0e692d910673ef7b52f8f1d8391afc6969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:09:15 +0100 Subject: [PATCH 13/19] Revert "Code style changes in selection-post-fixer." This reverts commit d1a522fd --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 0aaec838f..4d44267c3 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -190,7 +190,7 @@ function tryFixingNonCollapsedRage( range, schema ) { const fixedStart = isStartObject ? start : schema.getNearestSelectionRange( start, 'forward' ).start; const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); - const fixedEnd = isEndObject ? end : schema.getNearestSelectionRange( end, 'backward' ).end; + const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' ); return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end ); } From d9643757c0f5a9e2e59b7554df1b20227161cad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:09:27 +0100 Subject: [PATCH 14/19] Revert "Code style changes in selection-post-fixer." This reverts commit 6862a796 --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 4d44267c3..6bfa98c0b 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -187,7 +187,7 @@ function tryFixingNonCollapsedRage( range, schema ) { // - [foo] -> [foo] if ( checkSelectionOnNonLimitElements( start, end, schema ) ) { const isStartObject = start.nodeAfter && schema.isObject( start.nodeAfter ); - const fixedStart = isStartObject ? start : schema.getNearestSelectionRange( start, 'forward' ).start; + const fixedStart = isStartObject ? null : schema.getNearestSelectionRange( start, 'forward' ); const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' ); From 9cf3a14650391627bfe15b0a3abe78874f377fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:11:43 +0100 Subject: [PATCH 15/19] Update comment in tryFixingNonCollapsedRage() of selection-post-fixer. --- src/model/utils/selection-post-fixer.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 6bfa98c0b..50810a226 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -192,7 +192,11 @@ function tryFixingNonCollapsedRage( range, schema ) { const isEndObject = end.nodeBefore && schema.isObject( end.nodeBefore ); const fixedEnd = isEndObject ? null : schema.getNearestSelectionRange( end, 'backward' ); - return new Range( fixedStart ? fixedStart.start : start, fixedEnd ? fixedEnd.start : end ); + // The schema.getNearestSelectionRange might return null - if that happens use original position. + const rangeStart = fixedStart ? fixedStart.start : start; + const rangeEnd = fixedEnd ? fixedEnd.start : end; + + return new Range( rangeStart, rangeEnd ); } } From 9172eee6539eed02aac7a65e32819611e67a4020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:13:08 +0100 Subject: [PATCH 16/19] Remove empty line in selection-post-fixer. --- src/model/utils/selection-post-fixer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index 50810a226..e6e8614cb 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -159,7 +159,6 @@ function tryFixingCollapsedRange( range, schema ) { // // @param {module:engine/model/range~Range} range Expanded range to fix. // @param {module:engine/model/schema~Schema} schema - // @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid. function tryFixingNonCollapsedRage( range, schema ) { const start = range.start; From 77d39f26f162d54db33d377df41c8cf8ce725a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:17:07 +0100 Subject: [PATCH 17/19] Code style - remove redundant cast to boolean. --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index e6e8614cb..b50e13971 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -205,7 +205,7 @@ function tryFixingNonCollapsedRage( range, schema ) { // At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element // then the range crossed limit element boundaries and needs to be fixed. if ( isStartInLimit || isEndInLimit ) { - const bothInSameParent = ( !!start.nodeAfter && !!end.nodeBefore ) && start.nodeAfter === end.nodeBefore; + const bothInSameParent = ( start.nodeAfter && end.nodeBefore ) && start.nodeAfter.parent === end.nodeBefore.parent; const expandStart = isStartInLimit && ( !bothInSameParent || !isInObject( start.nodeAfter, schema ) ); const expandEnd = isEndInLimit && ( !bothInSameParent || !isInObject( end.nodeBefore, schema ) ); From da417e0abdfbb4f7568e9101e782fa7fc85ba29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:18:04 +0100 Subject: [PATCH 18/19] Rename findOuterMostIsLimitAncestor to findOutermostLimitAncestor(). --- src/model/utils/selection-post-fixer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index b50e13971..f7f54f808 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -216,11 +216,11 @@ function tryFixingNonCollapsedRage( range, schema ) { let fixedEnd = end; if ( expandStart ) { - fixedStart = Position._createBefore( findOuterMostIsLimitAncestor( startLimitElement, schema ) ); + fixedStart = Position._createBefore( findOutermostLimitAncestor( startLimitElement, schema ) ); } if ( expandEnd ) { - fixedEnd = Position._createAfter( findOuterMostIsLimitAncestor( endLimitElement, schema ) ); + fixedEnd = Position._createAfter( findOutermostLimitAncestor( endLimitElement, schema ) ); } return new Range( fixedStart, fixedEnd ); @@ -236,7 +236,7 @@ function tryFixingNonCollapsedRage( range, schema ) { // @param {module:engine/model/schema~Schema} schema // @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range. // @returns {module:engine/model/node~Node} -function findOuterMostIsLimitAncestor( startingNode, schema ) { +function findOutermostLimitAncestor( startingNode, schema ) { let isLimitNode = startingNode; let parent = isLimitNode; From 3398e5d19a2211d1ddddf3fa2e33b7c8176bb243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 20 Dec 2018 10:19:26 +0100 Subject: [PATCH 19/19] Update checkSelectionOnNonLimitElements() description. --- src/model/utils/selection-post-fixer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js index f7f54f808..73eca8e49 100644 --- a/src/model/utils/selection-post-fixer.js +++ b/src/model/utils/selection-post-fixer.js @@ -249,7 +249,7 @@ function findOutermostLimitAncestor( startingNode, schema ) { return isLimitNode; } -// Checks whether one of range ends is placed around non-limit elements. +// Checks whether any of range boundaries is placed around non-limit elements. // // @param {module:engine/model/position~Position} start // @param {module:engine/model/position~Position} end