From c5751e6e425a575b717616cec231a6c8aef97123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Tue, 16 Oct 2018 13:59:58 +0200 Subject: [PATCH 01/14] Introduced methods for creating document fragment, element and text in UpcastWriter. --- src/view/documentfragment.js | 3 ++ src/view/element.js | 5 +-- src/view/text.js | 3 +- src/view/upcastwriter.js | 45 ++++++++++++++++++++++++ tests/view/upcastwriter.js | 67 ++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) diff --git a/src/view/documentfragment.js b/src/view/documentfragment.js index 8fe9fb31c..59f65f95a 100644 --- a/src/view/documentfragment.js +++ b/src/view/documentfragment.js @@ -20,6 +20,9 @@ export default class DocumentFragment { /** * Creates new DocumentFragment instance. * + * **Note:** Constructor of this class shouldn't be used directly in the code. Use the + * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment} method instead. + * * @protected * @param {module:engine/view/node~Node|Iterable.} [children] List of nodes to be inserted into * created document fragment. diff --git a/src/view/element.js b/src/view/element.js index 5b7cf2ab8..0fde772e5 100644 --- a/src/view/element.js +++ b/src/view/element.js @@ -53,8 +53,9 @@ export default class Element extends Node { * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement} for inline element, * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement} for block element, * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement} for editable element, - * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement} for empty element or - * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} for UI element instead. + * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement} for empty element, + * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} for UI element instead or + * {@link module:engine/view/upcastwriter~UpcastWriter#createElement} for general element creation. * * @protected * @param {String} name Node name. diff --git a/src/view/text.js b/src/view/text.js index 1f6c4cfd8..06f35a44a 100644 --- a/src/view/text.js +++ b/src/view/text.js @@ -19,7 +19,8 @@ export default class Text extends Node { * Creates a tree view text node. * * **Note:** Constructor of this class shouldn't be used directly in the code. - * Use the {@link module:engine/view/downcastwriter~DowncastWriter#createText} method instead. + * Use the {@link module:engine/view/downcastwriter~DowncastWriter#createText} or + * {@link module:engine/view/upcastwriter~UpcastWriter#createText} method instead. * * @protected * @param {String} data Text. diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index 2599a9490..d27471806 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -7,7 +7,9 @@ * @module module:engine/view/upcastwriter */ +import DocumentFragment from './documentfragment'; import Element from './element'; +import Text from './text'; import { isPlainObject } from 'lodash-es'; /** @@ -17,6 +19,49 @@ import { isPlainObject } from 'lodash-es'; * see {@link module:engine/view/downcastwriter~DowncastWriter writer}. */ export default class UpcastWriter { + /** + * Creates new {@link module:engine/view/documentfragment~DocumentFragment}. + * + * @see module:engine/view/documentfragment~DocumentFragment#constructor + * @param {module:engine/view/node~Node|Iterable.} [children] + * List of nodes to be inserted into created document fragment. + * @returns {module:engine/view/documentfragment~DocumentFragment} Created document fragment. + */ + createDocumentFragment( children ) { + return new DocumentFragment( children ); + } + + /** + * Creates new {@link module:engine/view/element~Element}. + * + * Attributes can be passed in various formats: + * + * new Element( 'div', { 'class': 'editor', 'contentEditable': 'true' } ); // object + * new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator + * new Element( 'div', mapOfAttributes ); // map + * + * @see module:engine/view/element~Element#constructor + * @param {String} name Node name. + * @param {Object|Iterable} [attrs] Collection of attributes. + * @param {module:engine/view/node~Node|Iterable.} [children] + * List of nodes to be inserted into created element. + * @returns {module:engine/view/element~Element} Created element. + */ + createElement( name, attrs, children ) { + return new Element( name, attrs, children ); + } + + /** + * Creates new {@link module:engine/view/text~Text}. + * + * @see module:engine/view/text~Text#constructor + * @param {String} data Text + * @returns {module:engine/view/text~Text} Created text. + */ + createText( data ) { + return new Text( data ); + } + /** * Clones provided element. * diff --git a/tests/view/upcastwriter.js b/tests/view/upcastwriter.js index 7cd3b5ceb..ae4fd0a8d 100644 --- a/tests/view/upcastwriter.js +++ b/tests/view/upcastwriter.js @@ -3,7 +3,9 @@ * For licensing, see LICENSE.md. */ +import DocumentFragment from '../../src/view/documentfragment'; import Element from '../../src/view/element'; +import Text from '../../src/view/text'; import UpcastWriter from '../../src/view/upcastwriter'; import HtmlDataProcessor from '../../src/dataprocessor/htmldataprocessor'; @@ -29,6 +31,71 @@ describe( 'UpcastWriter', () => { view = dataprocessor.toView( html ); } ); + describe( 'createDocumentFragment', () => { + it( 'should create empty document fragment', () => { + const df = writer.createDocumentFragment(); + + expect( df ).to.instanceOf( DocumentFragment ); + expect( df.childCount ).to.equal( 0 ); + } ); + + it( 'should create document fragment with children', () => { + const df = writer.createDocumentFragment( [ view.getChild( 0 ), view.getChild( 1 ) ] ); + + expect( df ).to.instanceOf( DocumentFragment ); + expect( df.childCount ).to.equal( 2 ); + } ); + } ); + + describe( 'createElement', () => { + it( 'should create empty element', () => { + const el = writer.createElement( 'p' ); + + expect( el ).to.instanceOf( Element ); + expect( el.name ).to.equal( 'p' ); + expect( Array.from( el.getAttributes() ).length ).to.equal( 0 ); + expect( el.childCount ).to.equal( 0 ); + } ); + + it( 'should create element with attributes', () => { + const el = writer.createElement( 'a', { 'class': 'editor', 'contentEditable': 'true' } ); + + expect( el ).to.instanceOf( Element ); + expect( el.name ).to.equal( 'a' ); + expect( Array.from( el.getAttributes() ).length ).to.equal( 2 ); + expect( el.childCount ).to.equal( 0 ); + } ); + + it( 'should create element with children', () => { + const el = writer.createElement( 'div', null, [ view.getChild( 0 ) ] ); + + expect( el ).to.instanceOf( Element ); + expect( el.name ).to.equal( 'div' ); + expect( Array.from( el.getAttributes() ).length ).to.equal( 0 ); + expect( el.childCount ).to.equal( 1 ); + } ); + + it( 'should create element with attributes and children', () => { + const el = writer.createElement( 'blockquote', + { 'class': 'editor', 'contentEditable': 'true' }, + view.getChild( 2 ) ); + + expect( el ).to.instanceOf( Element ); + expect( el.name ).to.equal( 'blockquote' ); + expect( Array.from( el.getAttributes() ).length ).to.equal( 2 ); + expect( el.childCount ).to.equal( 1 ); + } ); + } ); + + describe( 'createText', () => { + it( 'should create text', () => { + const text = writer.createText( 'FooBar' ); + + expect( text ).to.instanceOf( Text ); + expect( text.data ).to.equal( 'FooBar' ); + } ); + } ); + describe( 'clone', () => { it( 'should clone simple element', () => { const el = view.getChild( 0 ); From a787b464e0d99bc3f77f479e98740bc6e20023ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Tue, 16 Oct 2018 14:35:55 +0200 Subject: [PATCH 02/14] The `View#change` method now returns result of its callback. --- src/view/view.js | 18 +++++++++++------- tests/view/view/view.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/view/view.js b/src/view/view.js index 7e8c9d47a..da0a943c9 100644 --- a/src/view/view.js +++ b/src/view/view.js @@ -308,16 +308,19 @@ export default class View { * Change method is the primary way of changing the view. You should use it to modify any node in the view tree. * It makes sure that after all changes are made view is rendered to DOM. It prevents situations when DOM is updated * when view state is not yet correct. It allows to nest calls one inside another and still perform single rendering - * after all changes are applied. + * after all changes are applied. It also returns the result of its callback. * - * view.change( writer => { - * writer.insert( position1, writer.createText( 'foo' ) ); + * const text = view.change( writer => { + * const newText = writer.createText( 'foo' ); + * writer.insert( position1, newText ); * * view.change( writer => { * writer.insert( position2, writer.createText( 'bar' ) ); * } ); * * writer.remove( range ); + * + * return newText; * } ); * * Change block is executed immediately. @@ -329,6 +332,7 @@ export default class View { * change block is used after rendering to DOM has started. * * @param {Function} callback Callback function which may modify the view. + * @returns {*} Value returned by the callback. */ change( callback ) { if ( this._renderingInProgress || this._postFixersInProgress ) { @@ -350,15 +354,13 @@ export default class View { // Recursive call to view.change() method - execute listener immediately. if ( this._ongoingChange ) { - callback( this._writer ); - - return; + return callback( this._writer ); } // This lock will assure that all recursive calls to view.change() will end up in same block - one "render" // event for all nested calls. this._ongoingChange = true; - callback( this._writer ); + const callbackResult = callback( this._writer ); this._ongoingChange = false; // This lock is used by editing controller to render changes from outer most model.change() once. As plugins might call @@ -370,6 +372,8 @@ export default class View { this.fire( 'render' ); } + + return callbackResult; } /** diff --git a/tests/view/view/view.js b/tests/view/view/view.js index 258eeca2e..d1feae0ab 100644 --- a/tests/view/view/view.js +++ b/tests/view/view/view.js @@ -601,6 +601,34 @@ describe( 'view', () => { sinon.assert.callOrder( changeSpy, postFixer1, postFixer2, eventSpy ); } ); + + it( 'should return result of the callback', () => { + const result = view.change( () => { + return 'FooBar'; + } ); + + expect( result ).to.equal( 'FooBar' ); + } ); + + it( 'should return result of the callback with nested change block', () => { + let result2 = false; + let result3 = false; + + const result1 = view.change( () => { + return view.change( () => { + result2 = view.change( () => { + return true; + } ); + result3 = view.change( () => {} ); + + return 42; + } ); + } ); + + expect( result1 ).to.equal( 42 ); + expect( result2 ).to.equal( true ); + expect( result3 ).to.undefined; + } ); } ); describe( 'destroy()', () => { From cd99c5dc33bb3a4310db8a3fb3a75ce53e4f056a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:23:55 +0100 Subject: [PATCH 03/14] Docs: Rewording. Co-Authored-By: f1ames --- src/view/documentfragment.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/view/documentfragment.js b/src/view/documentfragment.js index 59f65f95a..a668eb6b8 100644 --- a/src/view/documentfragment.js +++ b/src/view/documentfragment.js @@ -21,7 +21,8 @@ export default class DocumentFragment { * Creates new DocumentFragment instance. * * **Note:** Constructor of this class shouldn't be used directly in the code. Use the - * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment} method instead. + * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`} + * method instead. * * @protected * @param {module:engine/view/node~Node|Iterable.} [children] List of nodes to be inserted into From 6215452738add423b09000c8e003d2bfb1618895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:24:42 +0100 Subject: [PATCH 04/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index 2acb38a21..cfe6ed161 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -26,7 +26,7 @@ import Selection from './selection'; */ export default class UpcastWriter { /** - * Creates new {@link module:engine/view/documentfragment~DocumentFragment}. + * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance. * * @see module:engine/view/documentfragment~DocumentFragment#constructor * @param {module:engine/view/node~Node|Iterable.} [children] From 58c4961618983e93df342fe7ef2a9f649672ded1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:25:10 +0100 Subject: [PATCH 05/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index cfe6ed161..fe14c26c6 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -30,7 +30,7 @@ export default class UpcastWriter { * * @see module:engine/view/documentfragment~DocumentFragment#constructor * @param {module:engine/view/node~Node|Iterable.} [children] - * List of nodes to be inserted into created document fragment. + * A list of nodes to be inserted into the created document fragment. * @returns {module:engine/view/documentfragment~DocumentFragment} Created document fragment. */ createDocumentFragment( children ) { From b45023e275093eebaf0b242fc3fdc33ddf6ab45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:25:22 +0100 Subject: [PATCH 06/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index fe14c26c6..dc9718304 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -31,7 +31,7 @@ export default class UpcastWriter { * @see module:engine/view/documentfragment~DocumentFragment#constructor * @param {module:engine/view/node~Node|Iterable.} [children] * A list of nodes to be inserted into the created document fragment. - * @returns {module:engine/view/documentfragment~DocumentFragment} Created document fragment. + * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment. */ createDocumentFragment( children ) { return new DocumentFragment( children ); From ba7d688dda23cd5133f0de55ef158ffc7f898935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:25:32 +0100 Subject: [PATCH 07/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index dc9718304..c303a18c8 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -38,7 +38,7 @@ export default class UpcastWriter { } /** - * Creates new {@link module:engine/view/element~Element}. + * Creates a new {@link module:engine/view/element~Element} instance. * * Attributes can be passed in various formats: * From 7ce322b7cd5a399af09680217dbc032577a57ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:25:41 +0100 Subject: [PATCH 08/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index c303a18c8..955bec491 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -58,7 +58,7 @@ export default class UpcastWriter { } /** - * Creates new {@link module:engine/view/text~Text}. + * Creates a new {@link module:engine/view/text~Text} instance. * * @see module:engine/view/text~Text#constructor * @param {String} data Text From 946ab313987de5d5bfc5ff031c387dfd45845f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:25:48 +0100 Subject: [PATCH 09/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index 955bec491..0d3a70b29 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -62,7 +62,7 @@ export default class UpcastWriter { * * @see module:engine/view/text~Text#constructor * @param {String} data Text - * @returns {module:engine/view/text~Text} Created text. + * @returns {module:engine/view/text~Text} The created text node. */ createText( data ) { return new Text( data ); From ff7d4abe2b2625a370e7137b85f4085bcdc5f950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:25:58 +0100 Subject: [PATCH 10/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/upcastwriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index 0d3a70b29..c68d4839c 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -61,7 +61,7 @@ export default class UpcastWriter { * Creates a new {@link module:engine/view/text~Text} instance. * * @see module:engine/view/text~Text#constructor - * @param {String} data Text + * @param {String} data The text's data. * @returns {module:engine/view/text~Text} The created text node. */ createText( data ) { From 25cbbd68a768ec88557df81265e3abbbdbc448a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Wed, 7 Nov 2018 11:26:10 +0100 Subject: [PATCH 11/14] Docs: Rewording. [skip ci] Co-Authored-By: f1ames --- src/view/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/view.js b/src/view/view.js index b410b7d30..b46fbab14 100644 --- a/src/view/view.js +++ b/src/view/view.js @@ -311,7 +311,7 @@ export default class View { * Change method is the primary way of changing the view. You should use it to modify any node in the view tree. * It makes sure that after all changes are made view is rendered to DOM. It prevents situations when DOM is updated * when view state is not yet correct. It allows to nest calls one inside another and still perform single rendering - * after all changes are applied. It also returns the result of its callback. + * after all changes are applied. It also returns the return value of its callback. * * const text = view.change( writer => { * const newText = writer.createText( 'foo' ); From ef2978c615b5f11e5fc32bb85b2dfb4e6ca02ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Wed, 7 Nov 2018 13:36:43 +0100 Subject: [PATCH 12/14] Docs: Consistent docs across view element types and writers. --- src/view/attributeelement.js | 7 +++++-- src/view/containerelement.js | 6 +++++- src/view/documentfragment.js | 12 ++++++------ src/view/downcastwriter.js | 4 ++-- src/view/editableelement.js | 3 +++ src/view/element.js | 37 +++++++++++++++--------------------- src/view/emptyelement.js | 5 ++++- src/view/node.js | 6 ++++-- src/view/text.js | 12 +++++++----- src/view/uielement.js | 3 +++ src/view/upcastwriter.js | 11 ++++------- src/view/view.js | 1 + 12 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/view/attributeelement.js b/src/view/attributeelement.js index 06fc92591..1261b492a 100644 --- a/src/view/attributeelement.js +++ b/src/view/attributeelement.js @@ -21,15 +21,18 @@ const DEFAULT_PRIORITY = 10; * be defined by the feature developer. Creating an element you should use {@link module:engine/view/containerelement~ContainerElement} * class or `AttributeElement`. * + * The constructor of this class shouldn't be used directly. To create new `AttributeElement` use the + * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `downcastWriter#createAttributeElement()`} method. + * * @extends module:engine/view/element~Element */ export default class AttributeElement extends Element { /** - * Creates a attribute element. + * Creates an attribute element. * * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement - * @protected * @see module:engine/view/element~Element + * @protected */ constructor( name, attrs, children ) { super( name, attrs, children ); diff --git a/src/view/containerelement.js b/src/view/containerelement.js index 4711c689b..c31af4c80 100644 --- a/src/view/containerelement.js +++ b/src/view/containerelement.js @@ -16,6 +16,10 @@ import Element from './element'; * Editing engine does not define fixed HTML DTD. This is why the type of the {@link module:engine/view/element~Element} need to * be defined by the feature developer. * + * To create new `ContainerElement` + * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`} + * method should be used. + * * Creating an element you should use `ContainerElement` class or {@link module:engine/view/attributeelement~AttributeElement}. This is * important to define the type of the element because of two reasons: * @@ -47,8 +51,8 @@ export default class ContainerElement extends Element { /** * Creates a container element. * - * @see module:engine/view/element~Element * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement + * @see module:engine/view/element~Element * @protected */ constructor( name, attrs, children ) { diff --git a/src/view/documentfragment.js b/src/view/documentfragment.js index a668eb6b8..35af597c0 100644 --- a/src/view/documentfragment.js +++ b/src/view/documentfragment.js @@ -15,18 +15,18 @@ import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin'; /** * DocumentFragment class. + * + * The constructor of this class shouldn't be used directly. To create new DocumentFragment instance use the + * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`} + * method instead. */ export default class DocumentFragment { /** * Creates new DocumentFragment instance. * - * **Note:** Constructor of this class shouldn't be used directly in the code. Use the - * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`} - * method instead. - * * @protected - * @param {module:engine/view/node~Node|Iterable.} [children] List of nodes to be inserted into - * created document fragment. + * @param {module:engine/view/node~Node|Iterable.} [children] + * A list of nodes to be inserted into the created document fragment. */ constructor( children ) { /** diff --git a/src/view/downcastwriter.js b/src/view/downcastwriter.js index 7f77e8a1e..6a5636430 100644 --- a/src/view/downcastwriter.js +++ b/src/view/downcastwriter.js @@ -141,8 +141,8 @@ export default class DowncastWriter { * * writer.createText( 'foo' ); * - * @param {String} data Text data. - * @returns {module:engine/view/text~Text} Created text node. + * @param {String} data The text's data. + * @returns {module:engine/view/text~Text} The created text node. */ createText( data ) { return new Text( data ); diff --git a/src/view/editableelement.js b/src/view/editableelement.js index 32bedb24d..25a2c6e94 100644 --- a/src/view/editableelement.js +++ b/src/view/editableelement.js @@ -20,6 +20,9 @@ const documentSymbol = Symbol( 'document' ); * * Editable is automatically read-only when its {@link module:engine/view/document~Document Document} is read-only. * + * The constructor of this class shouldn't be used directly. To create new `EditableElement` use the + * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`} method. + * * @extends module:engine/view/containerelement~ContainerElement * @mixes module:utils/observablemixin~ObservableMixin */ diff --git a/src/view/element.js b/src/view/element.js index 9ef8a8058..ae90ccff6 100644 --- a/src/view/element.js +++ b/src/view/element.js @@ -22,20 +22,21 @@ import { isPlainObject } from 'lodash-es'; * This is why the type of the {@link module:engine/view/element~Element} need to * be defined by the feature developer. When creating an element you should use one of the following methods: * - * * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `writer.createContainerElement()`} in order to create - * a {@link module:engine/view/containerelement~ContainerElement}, - * * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `writer.createAttributeElement()`} in order to create - * a {@link module:engine/view/attributeelement~AttributeElement}, - * * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `writer.createEmptyElement()`} in order to create - * a {@link module:engine/view/emptyelement~EmptyElement}. - * * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `writer.createUIElement()`} in order to create - * a {@link module:engine/view/uielement~UIElement}. - * * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `writer.createEditableElement()`} in order to create - * a {@link module:engine/view/editableelement~EditableElement}. + * * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `downcastWriter#createContainerElement()`} + * in order to create a {@link module:engine/view/containerelement~ContainerElement}, + * * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `downcastWriter#createAttributeElement()`} + * in order to create a {@link module:engine/view/attributeelement~AttributeElement}, + * * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`} + * in order to create a {@link module:engine/view/emptyelement~EmptyElement}. + * * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`} + * in order to create a {@link module:engine/view/uielement~UIElement}. + * * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`} + * in order to create a {@link module:engine/view/editableelement~EditableElement}. * * Note that for view elements which are not created from the model, like elements from mutations, paste or - * {@link module:engine/controller/datacontroller~DataController#set data.set} it is not possible to define the type of the element, so - * these will be instances of the {@link module:engine/view/element~Element}. + * {@link module:engine/controller/datacontroller~DataController#set data.set} it is not possible to define the type of the element. + * In such cases the {@link module:engine/view/upcastwriter~UpcastWriter#createElement `UpcastWriter#createElement()`} method + * should be used to create generic view elements. * * @extends module:engine/view/node~Node */ @@ -45,23 +46,15 @@ export default class Element extends Node { * * Attributes can be passed in various formats: * - * new Element( 'div', { 'class': 'editor', 'contentEditable': 'true' } ); // object + * new Element( 'div', { class: 'editor', contentEditable: 'true' } ); // object * new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator * new Element( 'div', mapOfAttributes ); // map * - * **Note:** Constructor of this class shouldn't be used directly in the code. Use the - * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement} for inline element, - * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement} for block element, - * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement} for editable element, - * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement} for empty element, - * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} for UI element instead or - * {@link module:engine/view/upcastwriter~UpcastWriter#createElement} for general element creation. - * * @protected * @param {String} name Node name. * @param {Object|Iterable} [attrs] Collection of attributes. * @param {module:engine/view/node~Node|Iterable.} [children] - * List of nodes to be inserted into created element. + * A list of nodes to be inserted into created element. */ constructor( name, attrs, children ) { super(); diff --git a/src/view/emptyelement.js b/src/view/emptyelement.js index 9ac2c9a88..5ad56fe0e 100644 --- a/src/view/emptyelement.js +++ b/src/view/emptyelement.js @@ -12,7 +12,10 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import Node from './node'; /** - * EmptyElement class. It is used to represent elements that cannot contain any child nodes. + * EmptyElement class. It is used to represent elements that cannot contain any child nodes (for example `` elements). + * + * The constructor of this class shouldn't be used directly. To create new `EmptyElement` use the + * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`} method. */ export default class EmptyElement extends Element { /** diff --git a/src/view/node.js b/src/view/node.js index 3963b3116..bbb0084f8 100644 --- a/src/view/node.js +++ b/src/view/node.js @@ -16,13 +16,15 @@ import { clone } from 'lodash-es'; /** * Abstract tree view node class. * + * This is an abstract class. Its constructor should not be used directly. + * Use the {@link module:engine/view/element~Element} class to create view elements + * or {@link module:engine/view/text~Text} class to create view text nodes. + * * @abstract */ export default class Node { /** * Creates a tree view node. - * - * This is an abstract class, so this constructor should not be used directly. */ constructor() { /** diff --git a/src/view/text.js b/src/view/text.js index 06f35a44a..85ab480cb 100644 --- a/src/view/text.js +++ b/src/view/text.js @@ -12,18 +12,20 @@ import Node from './node'; /** * Tree view text node. * + * The constructor of this class shouldn't be used directly. To create new Text instances + * use the {@link module:engine/view/downcastwriter~DowncastWriter#createText `DowncastWriter#createText()`} + * method when working on data downcasted from the model or the + * {@link module:engine/view/upcastwriter~UpcastWriter#createText `UpcastWriter#createText()`} + * method when working on non-semantic views. + * * @extends module:engine/view/node~Node */ export default class Text extends Node { /** * Creates a tree view text node. * - * **Note:** Constructor of this class shouldn't be used directly in the code. - * Use the {@link module:engine/view/downcastwriter~DowncastWriter#createText} or - * {@link module:engine/view/upcastwriter~UpcastWriter#createText} method instead. - * * @protected - * @param {String} data Text. + * @param {String} data The text's data. */ constructor( data ) { super(); diff --git a/src/view/uielement.js b/src/view/uielement.js index 5adddf927..f3092a21d 100644 --- a/src/view/uielement.js +++ b/src/view/uielement.js @@ -15,6 +15,9 @@ import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; /** * UIElement class. It is used to represent UI not a content of the document. * This element can't be split and selection can't be placed inside this element. + * + * The constructor of this class shouldn't be used directly. To create new `UIElement` use the + * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`} method. */ export default class UIElement extends Element { /** diff --git a/src/view/upcastwriter.js b/src/view/upcastwriter.js index c68d4839c..beb997462 100644 --- a/src/view/upcastwriter.js +++ b/src/view/upcastwriter.js @@ -28,7 +28,6 @@ export default class UpcastWriter { /** * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance. * - * @see module:engine/view/documentfragment~DocumentFragment#constructor * @param {module:engine/view/node~Node|Iterable.} [children] * A list of nodes to be inserted into the created document fragment. * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment. @@ -42,15 +41,14 @@ export default class UpcastWriter { * * Attributes can be passed in various formats: * - * new Element( 'div', { 'class': 'editor', 'contentEditable': 'true' } ); // object - * new Element( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator - * new Element( 'div', mapOfAttributes ); // map + * upcastWriter.createElement( 'div', { class: 'editor', contentEditable: 'true' } ); // object + * upcastWriter.createElement( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator + * upcastWriter.createElement( 'div', mapOfAttributes ); // map * - * @see module:engine/view/element~Element#constructor * @param {String} name Node name. * @param {Object|Iterable} [attrs] Collection of attributes. * @param {module:engine/view/node~Node|Iterable.} [children] - * List of nodes to be inserted into created element. + * A list of nodes to be inserted into created element. * @returns {module:engine/view/element~Element} Created element. */ createElement( name, attrs, children ) { @@ -60,7 +58,6 @@ export default class UpcastWriter { /** * Creates a new {@link module:engine/view/text~Text} instance. * - * @see module:engine/view/text~Text#constructor * @param {String} data The text's data. * @returns {module:engine/view/text~Text} The created text node. */ diff --git a/src/view/view.js b/src/view/view.js index b46fbab14..74acd760b 100644 --- a/src/view/view.js +++ b/src/view/view.js @@ -314,6 +314,7 @@ export default class View { * after all changes are applied. It also returns the return value of its callback. * * const text = view.change( writer => { + * * const newText = writer.createText( 'foo' ); * writer.insert( position1, newText ); * From b0aa93b01d1214b4faa9fc1f8f94ee706a611dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Krzto=C5=84?= Date: Wed, 7 Nov 2018 16:43:02 +0100 Subject: [PATCH 13/14] Docs: Adjusted code samples to utilize writers. --- src/dev-utils/view.js | 58 ++++++++++++++++++++++--------------------- src/view/node.js | 10 ++++---- src/view/range.js | 16 ++++++------ src/view/text.js | 4 +-- src/view/uielement.js | 2 +- 5 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/dev-utils/view.js b/src/dev-utils/view.js index 75b25096f..f2f23315c 100644 --- a/src/dev-utils/view.js +++ b/src/dev-utils/view.js @@ -113,20 +113,20 @@ setData._parse = parse; * Converts view elements to HTML-like string representation. * A root element can be provided as {@link module:engine/view/text~Text text}: * - * const text = new Text( 'foobar' ); + * const text = downcastWriter.createText( 'foobar' ); * stringify( text ); // 'foobar' * * or as an {@link module:engine/view/element~Element element}: * - * const element = new Element( 'p', null, new Text( 'foobar' ) ); + * const element = downcastWriter.createElement( 'p', null, downcastWriter.createText( 'foobar' ) ); * stringify( element ); // '

foobar

' * * or as a {@link module:engine/view/documentfragment~DocumentFragment document fragment}: * - * const text = new Text( 'foobar' ); - * const b = new Element( 'b', { name: 'test' }, text ); - * const p = new Element( 'p', { style: 'color:red;' } ); - * const fragment = new DocumentFragment( [ p, b ] ); + * const text = downcastWriter.createText( 'foobar' ); + * const b = downcastWriter.createElement( 'b', { name: 'test' }, text ); + * const p = downcastWriter.createElement( 'p', { style: 'color:red;' } ); + * const fragment = downcastWriter.createDocumentFragment( [ p, b ] ); * * stringify( fragment ); // '

foobar' * @@ -134,21 +134,23 @@ setData._parse = parse; * Ranges from the selection will then be included in output data. * If a range position is placed inside the element node, it will be represented with `[` and `]`: * - * const text = new Text( 'foobar' ); - * const b = new Element( 'b', null, text ); - * const p = new Element( 'p', null, b ); - * const selection = new Selection( - * Range._createFromParentsAndOffsets( p, 0, p, 1 ) + * const text = downcastWriter.createText( 'foobar' ); + * const b = downcastWriter.createElement( 'b', null, text ); + * const p = downcastWriter.createElement( 'p', null, b ); + * const selection = downcastWriter.createSelection( + * downcastWriter.createRangeIn( p ) * ); * * stringify( p, selection ); // '

[foobar]

' * * If a range is placed inside the text node, it will be represented with `{` and `}`: * - * const text = new Text( 'foobar' ); - * const b = new Element( 'b', null, text ); - * const p = new Element( 'p', null, b ); - * const selection = new Selection( Range._createFromParentsAndOffsets( text, 1, text, 5 ) ); + * const text = downcastWriter.createText( 'foobar' ); + * const b = downcastWriter.createElement( 'b', null, text ); + * const p = downcastWriter.createElement( 'p', null, b ); + * const selection = downcastWriter.createSelection( + * downcastWriter.createRange( downcastWriter.createPositionAt( text, 1 ), downcastWriter.createPositionAt( text, 5 ) ) + * ); * * stringify( p, selection ); // '

f{ooba}r

' * @@ -159,10 +161,10 @@ setData._parse = parse; * * Multiple ranges are supported: * - * const text = new Text( 'foobar' ); - * const selection = new Selection( [ - * Range._createFromParentsAndOffsets( text, 0, text, 1 ) ), - * Range._createFromParentsAndOffsets( text, 3, text, 5 ) ) + * const text = downcastWriter.createText( 'foobar' ); + * const selection = downcastWriter.createSelection( [ + * downcastWriter.createRange( downcastWriter.createPositionAt( text, 0 ), downcastWriter.createPositionAt( text, 1 ) ), + * downcastWriter.createRange( downcastWriter.createPositionAt( text, 3 ), downcastWriter.createPositionAt( text, 5 ) ) * ] ); * * stringify( text, selection ); // '{f}oo{ba}r' @@ -172,9 +174,9 @@ setData._parse = parse; * is provided, it will be converted to a selection containing this range. If a position instance is provided, it will * be converted to a selection containing one range collapsed at this position. * - * const text = new Text( 'foobar' ); - * const range = Range._createFromParentsAndOffsets( text, 0, text, 1 ); - * const position = new Position( text, 3 ); + * const text = downcastWriter.createText( 'foobar' ); + * const range = downcastWriter.createRange( downcastWriter.createPositionAt( text, 0 ), downcastWriter.createPositionAt( text, 1 ) ); + * const position = downcastWriter.createPositionAt( text, 3 ); * * stringify( text, range ); // '{f}oobar' * stringify( text, position ); // 'foo{}bar' @@ -186,10 +188,10 @@ setData._parse = parse; * {@link module:engine/view/emptyelement~EmptyElement empty elements} * and {@link module:engine/view/uielement~UIElement UI elements}: * - * const attribute = new AttributeElement( 'b' ); - * const container = new ContainerElement( 'p' ); - * const empty = new EmptyElement( 'img' ); - * const ui = new UIElement( 'span' ); + * const attribute = downcastWriter.createAttributeElement( 'b' ); + * const container = downcastWriter.createContainerElement( 'p' ); + * const empty = downcastWriter.createEmptyElement( 'img' ); + * const ui = downcastWriter.createUIElement( 'span' ); * getData( attribute, null, { showType: true } ); // '' * getData( container, null, { showType: true } ); // '' * getData( empty, null, { showType: true } ); // '' @@ -198,14 +200,14 @@ setData._parse = parse; * If `options.showPriority` is set to `true`, a priority will be displayed for all * {@link module:engine/view/attributeelement~AttributeElement attribute elements}. * - * const attribute = new AttributeElement( 'b' ); + * const attribute = downcastWriter.createAttributeElement( 'b' ); * attribute._priority = 20; * getData( attribute, null, { showPriority: true } ); // * * If `options.showAttributeElementId` is set to `true`, the attribute element's id will be displayed for all * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that have it set. * - * const attribute = new AttributeElement( 'span' ); + * const attribute = downcastWriter.createAttributeElement( 'span' ); * attribute._id = 'marker:foo'; * getData( attribute, null, { showAttributeElementId: true } ); // * diff --git a/src/view/node.js b/src/view/node.js index bbb0084f8..6d145e8fe 100644 --- a/src/view/node.js +++ b/src/view/node.js @@ -125,11 +125,11 @@ export default class Node { * 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. * - * const abc = new Text( 'abc' ); - * const foo = new Text( 'foo' ); - * const h1 = new Element( 'h1', null, new Text( 'header' ) ); - * const p = new Element( 'p', null, [ abc, foo ] ); - * const div = new Element( 'div', null, [ h1, p ] ); + * const abc = downcastWriter.createText( 'abc' ); + * const foo = downcastWriter.createText( 'foo' ); + * const h1 = downcastWriter.createElement( 'h1', null, downcastWriter.createText( 'header' ) ); + * const p = downcastWriter.createElement( 'p', null, [ abc, foo ] ); + * const div = downcastWriter.createElement( 'div', null, [ h1, p ] ); * foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3. * h1.getPath(); // Returns [ 0 ]. * div.getPath(); // Returns []. diff --git a/src/view/range.js b/src/view/range.js index 2aeb2b775..4e9e9f964 100644 --- a/src/view/range.js +++ b/src/view/range.js @@ -205,10 +205,10 @@ export default class Range { * * Examples: * - * let foo = new Text( 'foo' ); - * let img = new ContainerElement( 'img' ); - * let bar = new Text( 'bar' ); - * let p = new ContainerElement( 'p', null, [ foo, img, bar ] ); + * let foo = downcastWriter.createText( 'foo' ); + * let img = downcastWriter.createContainerElement( 'img' ); + * let bar = downcastWriter.createText( 'bar' ); + * let p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] ); * * let range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // "o", img, "b" are in range. * let otherRange = view.createRange( // "oo", img, "ba" are in range. @@ -260,10 +260,10 @@ export default class Range { * * Examples: * - * let foo = new Text( 'foo' ); - * let img = new ContainerElement( 'img' ); - * let bar = new Text( 'bar' ); - * let p = new ContainerElement( 'p', null, [ foo, img, bar ] ); + * let foo = downcastWriter.createText( 'foo' ); + * let img = downcastWriter.createContainerElement( 'img' ); + * let bar = downcastWriter.createText( 'bar' ); + * let p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] ); * * let range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // "o", img, "b" are in range. * let otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // "oo", img are in range. diff --git a/src/view/text.js b/src/view/text.js index 85ab480cb..bf975985b 100644 --- a/src/view/text.js +++ b/src/view/text.js @@ -60,8 +60,8 @@ export default class Text extends Node { /** * This getter is required when using the addition assignment operator on protected property: * - * const foo = new Text( 'foo' ); - * const bar = new Text( 'bar' ); + * const foo = downcastWriter.createText( 'foo' ); + * const bar = downcastWriter.createText( 'bar' ); * * foo._data += bar.data; // executes: `foo._data = foo._data + bar.data` * console.log( foo.data ); // prints: 'foobar' diff --git a/src/view/uielement.js b/src/view/uielement.js index f3092a21d..eee385a1e 100644 --- a/src/view/uielement.js +++ b/src/view/uielement.js @@ -75,7 +75,7 @@ export default class UIElement extends Element { * {@link module:engine/view/domconverter~DomConverter}. * Do not use inheritance to create custom rendering method, replace `render()` method instead: * - * const myUIElement = new UIElement( 'span' ); + * const myUIElement = downcastWriter.createUIElement( 'span' ); * myUIElement.render = function( domDocument ) { * const domElement = this.toDomElement( domDocument ); * domElement.innerHTML = 'this is ui element'; From f0d6d5d123e525970c5b075c3712e5e3ba469944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Thu, 8 Nov 2018 12:08:06 +0100 Subject: [PATCH 14/14] Improved major view classes docs. --- src/dev-utils/model.js | 7 +++--- src/dev-utils/view.js | 7 +++--- src/view/attributeelement.js | 14 ++++++------ src/view/containerelement.js | 41 +++++++++++------------------------ src/view/documentfragment.js | 6 +++--- src/view/downcastwriter.js | 5 +++-- src/view/emptyelement.js | 4 ++-- src/view/position.js | 8 ++++++- src/view/range.js | 42 ++++++++++++++++++++++++------------ src/view/uielement.js | 17 ++++++++++++--- src/view/view.js | 31 +++++++++++++------------- 11 files changed, 99 insertions(+), 83 deletions(-) diff --git a/src/dev-utils/model.js b/src/dev-utils/model.js index 567e8bad8..3fc3debea 100644 --- a/src/dev-utils/model.js +++ b/src/dev-utils/model.js @@ -38,7 +38,7 @@ import { isPlainObject } from 'lodash-es'; import toMap from '@ckeditor/ckeditor5-utils/src/tomap'; /** - * Writes the content of the {@link module:engine/model/document~Document document} to an HTML-like string. + * Writes the content of a model {@link module:engine/model/document~Document document} to an HTML-like string. * * **Note:** A {@link module:engine/model/text~Text text} node that contains attributes will be represented as: * @@ -72,9 +72,10 @@ export function getData( model, options = {} ) { getData._stringify = stringify; /** - * Sets the content of the {@link module:engine/model/document~Document document} provided as an HTML-like string. + * Sets the content of a model {@link module:engine/model/document~Document document} provided as an HTML-like string. * - * **Note:** Remember to register elements in the {@link module:engine/model/model~Model#schema model's schema} before inserting them. + * **Note:** Remember to register elements in the {@link module:engine/model/model~Model#schema model's schema} before + * trying to use them. * * **Note:** To create a {@link module:engine/model/text~Text text} node that contains attributes use: * diff --git a/src/dev-utils/view.js b/src/dev-utils/view.js index f2f23315c..b00952743 100644 --- a/src/dev-utils/view.js +++ b/src/dev-utils/view.js @@ -80,7 +80,7 @@ export function getData( view, options = {} ) { getData._stringify = stringify; /** - * Sets the content of the {@link module:engine/view/document~Document document} provided as an HTML-like string. + * Sets the content of a view {@link module:engine/view/document~Document document} provided as an HTML-like string. * * @param {module:engine/view/view~View} view * @param {String} data An HTML-like string to write into the document. @@ -111,6 +111,7 @@ setData._parse = parse; /** * Converts view elements to HTML-like string representation. + * * A root element can be provided as {@link module:engine/view/text~Text text}: * * const text = downcastWriter.createText( 'foobar' ); @@ -131,7 +132,7 @@ setData._parse = parse; * stringify( fragment ); // '

foobar' * * Additionally, a {@link module:engine/view/documentselection~DocumentSelection selection} instance can be provided. - * Ranges from the selection will then be included in output data. + * Ranges from the selection will then be included in the output data. * If a range position is placed inside the element node, it will be represented with `[` and `]`: * * const text = downcastWriter.createText( 'foobar' ); @@ -251,7 +252,7 @@ export function stringify( node, selectionOrPositionOrRange = null, options = {} } /** - * Parses an HTML-like string and returns view tree nodes. + * Parses an HTML-like string and returns a view tree. * A simple string will be converted to a {@link module:engine/view/text~Text text} node: * * parse( 'foobar' ); // Returns an instance of text. diff --git a/src/view/attributeelement.js b/src/view/attributeelement.js index 1261b492a..3440fe005 100644 --- a/src/view/attributeelement.js +++ b/src/view/attributeelement.js @@ -14,15 +14,15 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; const DEFAULT_PRIORITY = 10; /** - * Attributes are elements which define document presentation. They are mostly elements like `` or ``. - * Attributes can be broken and merged by the {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}. + * Attribute elements are used to represent formatting elements in the view (think – ``, ``, etc.). + * Most often they are created when downcasting model text attributes. * - * Editing engine does not define fixed HTML DTD. This is why the type of the {@link module:engine/view/element~Element} need to - * be defined by the feature developer. Creating an element you should use {@link module:engine/view/containerelement~ContainerElement} - * class or `AttributeElement`. + * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various + * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element}, + * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature. * - * The constructor of this class shouldn't be used directly. To create new `AttributeElement` use the - * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `downcastWriter#createAttributeElement()`} method. + * To create a new attribute element instance use the + * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `DowncastWriter#createAttributeElement()`} method. * * @extends module:engine/view/element~Element */ diff --git a/src/view/containerelement.js b/src/view/containerelement.js index c31af4c80..5169c10d5 100644 --- a/src/view/containerelement.js +++ b/src/view/containerelement.js @@ -11,39 +11,22 @@ import Element from './element'; /** * Containers are elements which define document structure. They define boundaries for - * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly use for block elements like `

` or `

`. + * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly used for block elements like `

` or `

`. * - * Editing engine does not define fixed HTML DTD. This is why the type of the {@link module:engine/view/element~Element} need to - * be defined by the feature developer. + * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various + * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element}, + * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature. * - * To create new `ContainerElement` - * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`} - * method should be used. - * - * Creating an element you should use `ContainerElement` class or {@link module:engine/view/attributeelement~AttributeElement}. This is - * important to define the type of the element because of two reasons: - * - * Firstly, {@link module:engine/view/domconverter~DomConverter} needs the information what is an editable block to convert elements to - * DOM properly. {@link module:engine/view/domconverter~DomConverter} will ensure that `ContainerElement` is editable and it is possible - * to put caret inside it, even if the container is empty. - * - * Secondly, {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} uses this information. - * Nodes {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breaking} and - * {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes merging} is performed only in a bounds of a container nodes. - * - * For instance if `

` is an container and `` is attribute: + * The container element should be your default choice when writing a converter, unless: * - *

fo^o

+ * * this element represents a model text attribute (then use {@link module:engine/view/attributeelement~AttributeElement}), + * * this is an empty element like `` (then use {@link module:engine/view/emptyelement~EmptyElement}), + * * this is a root element, + * * this is a nested editable element (then use {@link module:engine/view/editableelement~EditableElement}). * - * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes} will create: - * - *

foo

- * - * There might be a need to mark `` element as a container node, for example in situation when it will be a - * container of an inline widget: - * - * foobar // attribute - * foobar // container + * To create a new container element instance use the + * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`} + * method. * * @extends module:engine/view/element~Element */ diff --git a/src/view/documentfragment.js b/src/view/documentfragment.js index 35af597c0..f708a56d2 100644 --- a/src/view/documentfragment.js +++ b/src/view/documentfragment.js @@ -14,11 +14,11 @@ import isIterable from '@ckeditor/ckeditor5-utils/src/isiterable'; import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin'; /** - * DocumentFragment class. + * Document fragment. * - * The constructor of this class shouldn't be used directly. To create new DocumentFragment instance use the + * To create a new document fragment instance use the * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`} - * method instead. + * method. */ export default class DocumentFragment { /** diff --git a/src/view/downcastwriter.js b/src/view/downcastwriter.js index 6a5636430..e20d3d090 100644 --- a/src/view/downcastwriter.js +++ b/src/view/downcastwriter.js @@ -27,10 +27,11 @@ import { isPlainObject } from 'lodash-es'; * It provides a set of methods used to manipulate view nodes. * * The `DowncastWriter` is designed to work with semantic views which are the views that were/are being downcasted from the model. - * To work with ordinary views (e.g. parsed from a string) use the {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}. + * To work with ordinary views (e.g. parsed from a pasted content) use the + * {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}. * * Do not create an instance of this writer manually. To modify a view structure, use - * the {@link module:engine/view/view~View#change View#change()) block. + * the {@link module:engine/view/view~View#change `View#change()`) block. */ export default class DowncastWriter { constructor( document ) { diff --git a/src/view/emptyelement.js b/src/view/emptyelement.js index 5ad56fe0e..ca7291035 100644 --- a/src/view/emptyelement.js +++ b/src/view/emptyelement.js @@ -12,9 +12,9 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import Node from './node'; /** - * EmptyElement class. It is used to represent elements that cannot contain any child nodes (for example `` elements). + * Empty element class. It is used to represent elements that cannot contain any child nodes (for example `` elements). * - * The constructor of this class shouldn't be used directly. To create new `EmptyElement` use the + * To create a new empty element use the * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`} method. */ export default class EmptyElement extends Element { diff --git a/src/view/position.js b/src/view/position.js index fc77cb55b..2f87827ba 100644 --- a/src/view/position.js +++ b/src/view/position.js @@ -14,7 +14,13 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import EditableElement from './editableelement'; /** - * Position in the tree. Position is always located before or after a node. + * Position in the view tree. Position is represented by its parent node and an offset in this parent. + * + * In order to create a new position instance use the `createPosition*()` factory methods available in: + * + * * {@module:engine/view/view~View} + * * {@module:engine/view/downcastwriter~DowncastWriter} + * * {@module:engine/view/upcastwriter~UpcastWriter} */ export default class Position { /** diff --git a/src/view/range.js b/src/view/range.js index 4e9e9f964..f10b01dcc 100644 --- a/src/view/range.js +++ b/src/view/range.js @@ -11,7 +11,13 @@ import Position from './position'; import TreeWalker from './treewalker'; /** - * Tree view range. + * Range in the view tree. A range is represented by its start and end {@link module:engine/view/position~Position positions}. + * + * In order to create a new position instance use the `createPosition*()` factory methods available in: + * + * * {@module:engine/view/view~View} + * * {@module:engine/view/downcastwriter~DowncastWriter} + * * {@module:engine/view/upcastwriter~UpcastWriter} */ export default class Range { /** @@ -20,7 +26,7 @@ export default class Range { * **Note:** Constructor creates it's own {@link module:engine/view/position~Position} instances basing on passed values. * * @param {module:engine/view/position~Position} start Start position. - * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position. + * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at the `start` position. */ constructor( start, end = null ) { /** @@ -91,13 +97,14 @@ export default class Range { * * For example: * - *

Foo

{Bar}

->

Foo

[

Bar]

- *

foo{bar}

->

foo[bar]

+ *

Foo

{Bar}

->

Foo

[

Bar]

+ *

foo{bar}

->

foo[bar]

* * Note that in the sample above: - * - `

` have type of {@link module:engine/view/containerelement~ContainerElement}, - * - `` have type of {@link module:engine/view/attributeelement~AttributeElement}, - * - `` have type of {@link module:engine/view/uielement~UIElement}. + * + * - `

` have type of {@link module:engine/view/containerelement~ContainerElement}, + * - `` have type of {@link module:engine/view/attributeelement~AttributeElement}, + * - `` have type of {@link module:engine/view/uielement~UIElement}. * * @returns {module:engine/view/range~Range} Enlarged range. */ @@ -123,13 +130,14 @@ export default class Range { * * For example: * - *

Foo

[

Bar]

->

Foo

{Bar}

- *

foo[bar]

->

foo{bar}

+ *

Foo

[

Bar]

->

Foo

{Bar}

+ *

foo[bar]

->

foo{bar}

* * Note that in the sample above: - * - `

` have type of {@link module:engine/view/containerelement~ContainerElement}, - * - `` have type of {@link module:engine/view/attributeelement~AttributeElement}, - * - `` have type of {@link module:engine/view/uielement~UIElement}. + * + * - `

` have type of {@link module:engine/view/containerelement~ContainerElement}, + * - `` have type of {@link module:engine/view/attributeelement~AttributeElement}, + * - `` have type of {@link module:engine/view/uielement~UIElement}. * * @returns {module:engine/view/range~Range} Shrink range. */ @@ -309,6 +317,7 @@ export default class Range { * @param {Boolean} [options.singleCharacters=false] * @param {Boolean} [options.shallow=false] * @param {Boolean} [options.ignoreElementEnd=false] + * @returns {module:engine/view/treewalker~TreeWalker} */ getWalker( options = {} ) { options.boundaries = this; @@ -326,6 +335,11 @@ export default class Range { return this.start.getCommonAncestor( this.end ); } + /** + * Clones this range. + * + * @returns {module:engine/view/range~Range} + */ clone() { return new Range( this.start, this.end ); } @@ -381,7 +395,7 @@ export default class Range { } /** - * Checks and returns whether this range intersects with given range. + * Checks and returns whether this range intersects with the given range. * * @param {module:engine/view/range~Range} otherRange Range to compare with. * @returns {Boolean} True if ranges intersect. @@ -391,7 +405,7 @@ export default class Range { } /** - * Creates a range from given parents and offsets. + * Creates a range from the given parents and offsets. * * @protected * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} startElement Start position diff --git a/src/view/uielement.js b/src/view/uielement.js index eee385a1e..fd1c643f8 100644 --- a/src/view/uielement.js +++ b/src/view/uielement.js @@ -13,10 +13,21 @@ import Node from './node'; import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard'; /** - * UIElement class. It is used to represent UI not a content of the document. - * This element can't be split and selection can't be placed inside this element. + * UI element class. It should be used to represent editing UI which needs to be injected into the editing view + * If possible, you should keep your UI outside the editing view. However, if that is not possible, + * UI elements can be used. * - * The constructor of this class shouldn't be used directly. To create new `UIElement` use the + * How a UI element is rendered is in your control (you pass a callback to + * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}). + * The editor will ignore your UI element – the selection cannot be placed in it, it is skipped (invisible) when + * the user modifies the selection by using arrow keys and the editor does not listen to any mutations which + * happen inside your UI elements. + * + * The limitation is that you cannot convert a model element to a UI element. UI elements need to be + * created for {@link module:engine/model/markercollection~Marker markers} or as additinal elements + * inside normal {@link module:engine/view/containerelement~ContainerElement container elements}. + * + * To create a new UI element use the * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`} method. */ export default class UIElement extends Element { diff --git a/src/view/view.js b/src/view/view.js index 74acd760b..404d5a5b7 100644 --- a/src/view/view.js +++ b/src/view/view.js @@ -53,10 +53,10 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; * * {@link module:engine/view/observer/fakeselectionobserver~FakeSelectionObserver}. * * {@link module:engine/view/observer/compositionobserver~CompositionObserver}. * - * This class also {@link module:engine/view/view~View#attachDomRoot bind DOM and View elements}. + * This class also {@link module:engine/view/view~View#attachDomRoot binds the DOM and the view elements}. * - * If you do not need full DOM - View management, and want to only transform the tree of view elements to the DOM - * elements you do not need this controller, you can use the {@link module:engine/view/domconverter~DomConverter DomConverter}. + * If you do not need full a DOM - view management, and only want to transform a tree of view elements to a tree of DOM + * elements you do not need this controller. You can use the {@link module:engine/view/domconverter~DomConverter DomConverter} instead. * * @mixes module:utils/observablemixin~ObservableMixin */ @@ -308,13 +308,12 @@ export default class View { } /** - * Change method is the primary way of changing the view. You should use it to modify any node in the view tree. - * It makes sure that after all changes are made view is rendered to DOM. It prevents situations when DOM is updated - * when view state is not yet correct. It allows to nest calls one inside another and still perform single rendering - * after all changes are applied. It also returns the return value of its callback. + * The `change()` method is the primary way of changing the view. You should use it to modify any node in the view tree. + * It makes sure that after all changes are made the view is rendered to the DOM. It prevents situations when the DOM is updated + * when the view state is not yet correct. It allows to nest calls one inside another and still performs a single rendering + * after all those changes are made. It also returns the return value of its callback. * * const text = view.change( writer => { - * * const newText = writer.createText( 'foo' ); * writer.insert( position1, newText ); * @@ -327,13 +326,11 @@ export default class View { * return newText; * } ); * - * Change block is executed immediately. - * - * When the outermost change block is done and rendering to DOM is over it fires - * {@link module:engine/view/view~View#event:render} event. + * When the outermost change block is done and rendering to the DOM is over the + * {@link module:engine/view/view~View#event:render `View#render`} event is fired. * - * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `applying-view-changes-on-rendering` when - * change block is used after rendering to DOM has started. + * This method throws a `applying-view-changes-on-rendering` error when + * the change block is used after rendering to the DOM has started. * * @param {Function} callback Callback function which may modify the view. * @returns {*} Value returned by the callback. @@ -348,11 +345,13 @@ export default class View { * * calling {@link #change} or {@link #render} during rendering process, * * calling {@link #change} or {@link #render} inside of * {@link module:engine/view/document~Document#registerPostFixer post-fixer function}. + * + * @error cannot-change-view-tree */ throw new CKEditorError( 'cannot-change-view-tree: ' + - 'Attempting to make changes to the view when it is in incorrect state: rendering or post-fixers are in progress. ' + - 'This may cause some unexpected behaviour and inconsistency between the DOM and the view.' + 'Attempting to make changes to the view when it is in an incorrect state: rendering or post-fixers are in progress. ' + + 'This may cause some unexpected behavior and inconsistency between the DOM and the view.' ); }