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

Commit

Permalink
Added a new method (#isAttached()) to both (view and model) Nodes cla…
Browse files Browse the repository at this point in the history
…sses.
  • Loading branch information
pomek committed Feb 28, 2020
1 parent 21390a9 commit 8039a8d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/conversion/downcasthelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ export function clearAttributes() {
// Not collapsed selection should not have artifacts.
if ( range.isCollapsed ) {
// Position might be in the node removed by the view writer.
if ( range.end.parent.parent ) {
if ( range.end.parent.isAttached() ) {
conversionApi.writer.mergeAttributes( range.start );
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/model/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ export default class Node {
return root;
}

/**
* Returns true if a node is in a tree rooted in an element of the root type.
*
* @returns {Boolean}
*/
isAttached() {
return this.root.is( 'rootElement' );
}

/**
* Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,
* beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to
Expand Down
4 changes: 0 additions & 4 deletions src/view/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -667,10 +667,6 @@ export default class Element extends Node {
if ( key == 'class' ) {
parseClasses( this._classes, value );
} else if ( key == 'style' ) {
// if (!this._styles ) {
// debugger;
// }

this._styles.setTo( value );
} else {
this._attrs.set( key, value );
Expand Down
9 changes: 9 additions & 0 deletions src/view/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ export default class Node {
return root;
}

/**
* Returns true if a node is in a tree rooted in an element of the root type.
*
* @returns {Boolean}
*/
isAttached() {
return this.root.is( 'rootElement' );
}

/**
* Gets a path to the node. The path is an array containing indices of consecutive ancestors of this node,
* beginning from {@link module:engine/view/node~Node#root root}, down to this node's index.
Expand Down
51 changes: 51 additions & 0 deletions tests/model/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import DocumentFragment from '../../src/model/documentfragment';
import Node from '../../src/model/node';
import Element from '../../src/model/element';
import Text from '../../src/model/text';
import RootElement from '../../src/model/rootelement';
import count from '@ckeditor/ckeditor5-utils/src/count';
import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor';

describe( 'Node', () => {
let doc, root, node,
Expand Down Expand Up @@ -386,6 +388,55 @@ describe( 'Node', () => {
} );
} );

describe( 'isAttached()', () => {
it( 'returns false for a fresh node', () => {
const char = new Text( 'x' );
const el = new Element( 'one' );

expect( char.isAttached() ).to.equal( false );
expect( el.isAttached() ).to.equal( false );
} );

it( 'returns true for the root element', () => {
const model = new Model();
const root = new RootElement( model.document, 'root' );

expect( root.isAttached() ).to.equal( true );
} );

it( 'returns false for a node attached to a document fragment', () => {
const foo = new Text( 'foo' );
new DocumentFragment( [ foo ] ); // eslint-disable-line no-new

expect( foo.isAttached() ).to.equal( false );
} );

it( 'returns true for a node moved to graveyard', () => {
return ModelTestEditor.create()
.then( editor => {
const model = editor.model;
const root = model.document.getRoot();

// Allow "paragraph" element to be added as a child in block elements.
model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );

const node = model.change( writer => writer.createElement( 'paragraph' ) );

expect( node.isAttached() ).to.equal( false );

model.change( writer => writer.append( node, root ) );

expect( node.isAttached() ).to.equal( true );

model.change( writer => writer.remove( node ) );

expect( node.isAttached() ).to.equal( true );

return editor.destroy();
} );
} );
} );

describe( 'attributes interface', () => {
const node = new Node( { foo: 'bar' } );

Expand Down
43 changes: 32 additions & 11 deletions tests/view/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Node from '../../src/view/node';
import DocumentFragment from '../../src/view/documentfragment';
import RootEditableElement from '../../src/view/rooteditableelement';

import createDocumentMock from '../../tests/view/_utils/createdocumentmock';
import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
import Document from '../../src/view/document';
import { StylesProcessor } from '../../src/view/stylesmap';
Expand Down Expand Up @@ -180,9 +179,9 @@ describe( 'Node', () => {
} );

it( 'should return proper element for nodes in different branches and on different levels', () => {
const foo = new Text( 'foo' );
const bar = new Text( 'bar' );
const bom = new Text( 'bom' );
const foo = new Text( document, 'foo' );
const bar = new Text( document, 'bar' );
const bom = new Text( document, 'bom' );
const d = new Element( document, 'd', null, [ bar ] );
const c = new Element( document, 'c', null, [ foo, d ] );
const b = new Element( document, 'b', null, [ c ] );
Expand All @@ -207,8 +206,8 @@ describe( 'Node', () => {
} );

it( 'should return document fragment', () => {
const foo = new Text( 'foo' );
const bar = new Text( 'bar' );
const foo = new Text( document, 'foo' );
const bar = new Text( document, 'bar' );
const df = new DocumentFragment( document, [ foo, bar ] );

expect( foo.getCommonAncestor( bar ) ).to.equal( df );
Expand All @@ -232,7 +231,7 @@ describe( 'Node', () => {
} );

it( 'should throw an error if parent does not contain element', () => {
const f = new Text( 'f' );
const f = new Text( document, 'f' );
const bar = new Element( document, 'bar', [], [] );

f.parent = bar;
Expand Down Expand Up @@ -266,7 +265,6 @@ describe( 'Node', () => {

it( 'should return root element', () => {
const parent = new RootEditableElement( document, 'div' );
parent._document = createDocumentMock();
const child = new Element( document, 'p' );

child.parent = parent;
Expand Down Expand Up @@ -352,17 +350,40 @@ describe( 'Node', () => {
} );
} );

describe( 'isAttached()', () => {
it( 'returns false for a fresh node', () => {
const char = new Text( document, 'x' );
const el = new Element( document, 'one' );

expect( char.isAttached() ).to.equal( false );
expect( el.isAttached() ).to.equal( false );
} );

it( 'returns true for the root element', () => {
const root = new RootEditableElement( document, 'div' );

expect( root.isAttached() ).to.equal( true );
} );

it( 'returns false for a node attached to a document fragment', () => {
const foo = new Text( document, 'foo' );
new DocumentFragment( document, [ foo ] ); // eslint-disable-line no-new

expect( foo.isAttached() ).to.equal( false );
} );
} );

describe( '_remove()', () => {
it( 'should remove node from its parent', () => {
const char = new Text( 'a' );
const char = new Text( document, 'a' );
const parent = new Element( document, 'p', null, [ char ] );
char._remove();

expect( parent.getChildIndex( char ) ).to.equal( -1 );
} );

it( 'uses parent._removeChildren method', () => {
const char = new Text( 'a' );
const char = new Text( document, 'a' );
const parent = new Element( document, 'p', null, [ char ] );
const _removeChildrenSpy = sinon.spy( parent, '_removeChildren' );
const index = char.index;
Expand Down Expand Up @@ -399,7 +420,7 @@ describe( 'Node', () => {
} );

beforeEach( () => {
text = new Text( 'foo' );
text = new Text( document, 'foo' );
img = new Element( document, 'img', { 'src': 'img.png' } );

root = new Element( document, 'p', { renderer: { markToSync: rootChangeSpy } } );
Expand Down
1 change: 0 additions & 1 deletion tests/view/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,6 @@ describe( 'Position', () => {
it( 'should return EditableElement when position is placed inside', () => {
const p = new Element( document, 'p' );
const editable = new EditableElement( document, 'div', null, p );
editable._document = document;
const position = new Position( p, 0 );

expect( position.editableElement ).to.equal( editable );
Expand Down

0 comments on commit 8039a8d

Please sign in to comment.