Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

T/1002: Introduce Position#getCommonAncestor( otherPosition ) and Range#getCommonAncestor() #1005

Merged
merged 10 commits into from
Jul 11, 2017

Conversation

pomek
Copy link
Member

@pomek pomek commented Jul 7, 2017

Suggested merge commit message (convention)

Feature: Introduced Position#getCommonAncestor( position ) and Range#getCommonAncestor() methods for view and model. Closes ckeditor/ckeditor5#4105.

…etCommonAncestor()` methods for `view` and `model`.
@pomek pomek requested a review from Reinmar July 7, 2017 13:58
* of these two positions must be identical.
*
* @param {module:engine/model/position~Position} position The second position.
* @returns {module:engine/model/node~Node|null} Node that contains both positions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DocumentFragment is not a node. So the correct notation is Element|DF.

return null;
}

const ancestorsA = this.getAncestors();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I liked the previous implementation more. The one which reused getCommonPath(). It was shorter and more readable.

Let me guess – you decided to skip it because DF doesn't implement getNodeByPath()? ;) Why not borrowing it from Element for DF?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right :D

If it does not a problem, I could do it as you said.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will make a lot of sense to unify the APIs of Element and DF, so it's definitely good to add this method there.

@@ -446,6 +446,15 @@ export default class Range {
}

/**
* Returns a {@link module:engine/model/node~Node} which is a common ancestor for both positions.
*
* @returns {module:engine/model/node~Node|null}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, wrong type.

* @returns {module:engine/view/node~Node|null}
*/
getCommonAncestor( position ) {
const ancestorsA = this.getAncestors();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getAncestors() accept options.includeNode so will this work in such a case: <p>x{y}z</p>? For such positions the text node should be returned. And for such <p>[x]</p> the element.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second issue – you didn't pass options.parentFirst too so how can you iterate from i==0 (leafs)? What if one ancestors array is longer than the other?

* Returns a {@link module:engine/view/node~Node} which is a common ancestor for both positions.
*
* @param {module:engine/view/position~Position} position
* @returns {module:engine/view/node~Node|null}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case it should be DF|Node because here we can also get text nodes.

@@ -844,4 +844,46 @@ describe( 'Position', () => {
).to.throw( CKEditorError, /model-position-fromjson-no-root/ );
} );
} );

describe( 'getCommonAncestor()', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All tests use the same length of paths.

@@ -519,4 +519,43 @@ describe( 'Position', () => {
document.destroy();
} );
} );

describe( 'getCommonAncestor()', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you use positions on the same depts as well.


const node = this.root.getNodeByPath( this.getCommonPath( position ) );

if ( node.is( 'text' ) ) {
Copy link
Member

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?

Copy link
Member

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.

Copy link
Member

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."

@Reinmar
Copy link
Member

Reinmar commented Jul 10, 2017

@pjasiun and @scofalik pointed out that the tests miss these 2 tests:

<p>{}<a></a></p>
<p>xxx{}xxx</p>

They will prove that using getCommonPath() will not work.

test( fPosition, zPosition, li1 );
} );

it( 'works when one positions is nested deeper than the other', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"when one position"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or rather "one of the positions"

@@ -519,4 +519,69 @@ describe( 'Position', () => {
document.destroy();
} );
} );

describe( 'getCommonAncestor()', () => {
Copy link
Member

Choose a reason for hiding this comment

The 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 0 offset. Please add more, with better offsets (ones which have a chance to break something).

@Reinmar Reinmar merged commit 0e29844 into master Jul 11, 2017
@Reinmar Reinmar deleted the t/1002 branch July 11, 2017 15:52
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Introduce Position#getCommonAncestor( otherPosition ) and Range#getCommonAncestor()
2 participants