-
Notifications
You must be signed in to change notification settings - Fork 40
T/1002: Introduce Position#getCommonAncestor( otherPosition ) and Range#getCommonAncestor() #1005
Changes from 7 commits
3cd1cef
7267e15
22926a1
a43a195
98dda91
bc2ae56
bf294b3
42b5a7b
f6e287c
42f0b8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,6 +175,26 @@ export default class Position { | |
} | ||
} | ||
|
||
/** | ||
* Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment} | ||
* which is a common ancestor for both positions. | ||
* | ||
* @param {module:engine/view/position~Position} position | ||
* @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} | ||
*/ | ||
getCommonAncestor( position ) { | ||
const ancestorsA = this.getAncestors(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second issue – you didn't pass |
||
const ancestorsB = position.getAncestors(); | ||
|
||
let i = 0; | ||
|
||
while ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) { | ||
i++; | ||
} | ||
|
||
return i === 0 ? null : ancestorsA[ i - 1 ]; | ||
} | ||
|
||
/** | ||
* Checks whether this position equals given position. | ||
* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -844,4 +844,47 @@ describe( 'Position', () => { | |
).to.throw( CKEditorError, /model-position-fromjson-no-root/ ); | ||
} ); | ||
} ); | ||
|
||
describe( 'getCommonAncestor()', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All tests use the same length of paths. |
||
it( 'returns null when roots of the position are not the same', () => { | ||
const pos1 = new Position( root, [ 0 ] ); | ||
const pos2 = new Position( otherRoot, [ 1, 1 ] ); | ||
|
||
test( pos1, pos2, null ); | ||
} ); | ||
|
||
it( 'for two the same positions returns the parent element', () => { | ||
const fPosition = new Position( root, [ 1, 0, 0 ] ); | ||
const otherPosition = new Position( root, [ 1, 0, 0 ] ); | ||
|
||
test( fPosition, otherPosition, li1 ); | ||
} ); | ||
|
||
it( 'for two positions in the same element returns the element', () => { | ||
const fPosition = new Position( root, [ 1, 0, 0 ] ); | ||
const zPosition = new Position( root, [ 1, 0, 2 ] ); | ||
|
||
test( fPosition, zPosition, li1 ); | ||
} ); | ||
|
||
it( 'works when one positions is nested deeper than the other', () => { | ||
const zPosition = new Position( root, [ 1, 0, 2 ] ); | ||
const liPosition = new Position( root, [ 1, 1 ] ); | ||
|
||
test( liPosition, zPosition, ul ); | ||
} ); | ||
|
||
it( 'works fine with positions hooked in `DocumentFragment`', () => { | ||
const docFrag = new DocumentFragment( [ p, ul ] ); | ||
const zPosition = new Position( docFrag, [ 1, 0, 2 ] ); | ||
const afterLiPosition = new Position( docFrag, [ 1, 2 ] ); | ||
|
||
test( zPosition, afterLiPosition, ul ); | ||
} ); | ||
|
||
function test( positionA, positionB, lca ) { | ||
expect( positionA.getCommonAncestor( positionB ) ).to.equal( lca ); | ||
expect( positionB.getCommonAncestor( positionA ) ).to.equal( lca ); | ||
} | ||
} ); | ||
} ); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -519,4 +519,69 @@ describe( 'Position', () => { | |
document.destroy(); | ||
} ); | ||
} ); | ||
|
||
describe( 'getCommonAncestor()', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you use positions on the same depts as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's just a single test with positions in text nodes and it uses a |
||
let div, section, article, p, ul, li1, li2, foz, bar, lipsum; | ||
|
||
// |- div | ||
// |- ul | ||
// | |- li | ||
// | | |- f | ||
// | | |- o | ||
// | | |- z | ||
// | |- li | ||
// | |- b | ||
// | |- a | ||
// | |- r | ||
// |- section | ||
// |- article | ||
// |- p | ||
// |- l | ||
// |- i | ||
// |- p | ||
// |- s | ||
// |- u | ||
// |- m | ||
|
||
beforeEach( () => { | ||
foz = new Text( 'foz' ); | ||
bar = new Text( 'bar' ); | ||
li1 = new Element( 'li', null, foz ); | ||
li2 = new Element( 'li', null, bar ); | ||
ul = new Element( 'ul', null, [ li1, li2 ] ); | ||
|
||
lipsum = new Text( 'lipsum' ); | ||
p = new Element( 'p', null, lipsum ); | ||
article = new Element( 'article', null, p ); | ||
section = new Element( 'section', null, article ); | ||
|
||
div = new Element( 'div', null, [ ul, section ] ); | ||
} ); | ||
|
||
it( 'for two the same positions returns the parent element', () => { | ||
const fPosition = new Position( li1, 0 ); | ||
const otherPosition = Position.createFromPosition( fPosition ); | ||
|
||
test( fPosition, otherPosition, li1 ); | ||
} ); | ||
|
||
it( 'for two positions in the same element returns the element', () => { | ||
const fPosition = new Position( li1, 0 ); | ||
const zPosition = new Position( li1, 2 ); | ||
|
||
test( fPosition, zPosition, li1 ); | ||
} ); | ||
|
||
it( 'works when one positions is nested deeper than the other', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "when one position" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or rather "one of the positions" |
||
const zPosition = new Position( li1, 2 ); | ||
const iPosition = Position.createAt( lipsum, 'start' ); | ||
|
||
test( iPosition, zPosition, div ); | ||
} ); | ||
|
||
function test( positionA, positionB, lca ) { | ||
expect( positionA.getCommonAncestor( positionB ) ).to.equal( lca ); | ||
expect( positionB.getCommonAncestor( positionA ) ).to.equal( lca ); | ||
} | ||
} ); | ||
} ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something I expected from this method's model implementation. But I wonder what other think. Is "text node" a position's ancestor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, @scofalik and @pjasiun confirm that a text node is not an ancestor of position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a comment here saying that "Although paths can indicate a text node, text node is not an ancestor of a position."