|
|
@@ -8,28 +8,82 @@
|
|
|
import diff from '../utils-diff.js';
|
|
|
import CKEditorError from '../ckeditorerror.js';
|
|
|
|
|
|
+/**
|
|
|
+ * Renderer updates DOM tree, to make it a reflection of the view tree. Changed nodes need to be
|
|
|
+ * {@link treeView.Renderer#markToSync marked} to be rendered. Then, on {@link treeView.Renderer#render}, renderer
|
|
|
+ * ensure they need to be refreshed and creates DOM nodes from view nodes,
|
|
|
+ * {@link treeView.Converter#bindElements bind} them and insert into DOM tree. Renderer use {@link treeView.Converter}
|
|
|
+ * to transform and bind nodes.
|
|
|
+ *
|
|
|
+ * @class treeView.Renderer
|
|
|
+ */
|
|
|
export default class Renderer {
|
|
|
+ /**
|
|
|
+ * Creates a renderer instance.
|
|
|
+ *
|
|
|
+ * @param {treeView.Converter} converter Converter instance.
|
|
|
+ * @constructor
|
|
|
+ */
|
|
|
constructor( converter ) {
|
|
|
+ /**
|
|
|
+ * Converter instance.
|
|
|
+ *
|
|
|
+ * @readonly
|
|
|
+ * @type {treeView.Converter}
|
|
|
+ */
|
|
|
this.converter = converter;
|
|
|
|
|
|
- this.markedAttrs = new Set();
|
|
|
+ /**
|
|
|
+ * Set of nodes which attributes changed and may need to be rendered.
|
|
|
+ *
|
|
|
+ * @readonly
|
|
|
+ * @type {Set.<treeView.Node>}
|
|
|
+ */
|
|
|
+ this.markedAttributes = new Set();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set of elements which child lists changed and may need to be rendered.
|
|
|
+ *
|
|
|
+ * @readonly
|
|
|
+ * @type {Set.<treeView.Node>}
|
|
|
+ */
|
|
|
this.markedChildren = new Set();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set of text nodes which text data changed and may need to be rendered.
|
|
|
+ *
|
|
|
+ * @readonly
|
|
|
+ * @type {Set.<treeView.Node>}
|
|
|
+ */
|
|
|
this.markedTexts = new Set();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Mark node to be synchronized.
|
|
|
+ *
|
|
|
+ * Note that only view nodes which parents have corresponding DOM elements need to be marked to be synchronized.
|
|
|
+ *
|
|
|
+ * @see treeView.Renderer#markedAttributes
|
|
|
+ * @see treeView.Renderer#markedChildren
|
|
|
+ * @see treeView.Renderer#markedTexts
|
|
|
+ *
|
|
|
+ * @param {treeView.ChangeType} type Type of the change.
|
|
|
+ * @param {treeView.Node} node Node to be marked.
|
|
|
+ */
|
|
|
markToSync( type, node ) {
|
|
|
if ( type === 'TEXT' ) {
|
|
|
if ( this.converter.getCorrespondingDom( node.parent ) ) {
|
|
|
this.markedTexts.add( node );
|
|
|
}
|
|
|
} else {
|
|
|
- // If the node has no DOM element it is not rendered yet, its children/attributes do not need to be marked to be sync.
|
|
|
+ // If the node has no DOM element it is not rendered yet,
|
|
|
+ // its children/attributes do not need to be marked to be sync.
|
|
|
if ( !this.converter.getCorrespondingDom( node ) ) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if ( type === 'ATTRIBUTES' ) {
|
|
|
- this.markedAttrs.add( node );
|
|
|
+ this.markedAttributes.add( node );
|
|
|
} else if ( type === 'CHILDREN' ) {
|
|
|
this.markedChildren.add( node );
|
|
|
} else {
|
|
|
@@ -43,6 +97,24 @@ export default class Renderer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Render method check {@link treeView.Renderer#markedAttributes}, {@link treeView.Renderer#markedChildren} and
|
|
|
+ * {@link treeView.Renderer#markedTexts} and updated all nodes which needs to be updated. Then it clear all three
|
|
|
+ * sets.
|
|
|
+ *
|
|
|
+ * Renderer try not to bread IME, so it do as little as it is possible to update DOM.
|
|
|
+ *
|
|
|
+ * For attributes it adds new attributes to DOM elements, update attributes with different values and remove
|
|
|
+ * attributes which does not exists in the view element.
|
|
|
+ *
|
|
|
+ * For text nodes it update the text string if it is different. Note that if parent element is marked as an element
|
|
|
+ * which changed child list, text node update will not be done, because it may not be possible do find a
|
|
|
+ * {@link @treeView.Converter#getCorrespondingDomText corresponding DOM text}. The change will be handled in the
|
|
|
+ * parent element.
|
|
|
+ *
|
|
|
+ * For nodes which changed child list it calculates a {@link diff} using {@link @treeView.Converter#compareNodes}
|
|
|
+ * and add or removed nodes which changed.
|
|
|
+ */
|
|
|
render() {
|
|
|
const converter = this.converter;
|
|
|
|
|
|
@@ -52,7 +124,7 @@ export default class Renderer {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for ( let element of this.markedAttrs ) {
|
|
|
+ for ( let element of this.markedAttributes ) {
|
|
|
updateAttrs( element );
|
|
|
}
|
|
|
|
|
|
@@ -61,7 +133,7 @@ export default class Renderer {
|
|
|
}
|
|
|
|
|
|
this.markedTexts.clear();
|
|
|
- this.markedAttrs.clear();
|
|
|
+ this.markedAttributes.clear();
|
|
|
this.markedChildren.clear();
|
|
|
|
|
|
function updateText( viewText ) {
|
|
|
@@ -96,7 +168,9 @@ export default class Renderer {
|
|
|
const viewChildren = Array.from( viewElement.getChildren() );
|
|
|
const domDocument = domElement.ownerDocument;
|
|
|
|
|
|
- const actions = diff( domChildren, viewChildren, ( domNode, viewNode ) => converter.compareNodes( domNode, viewNode ) );
|
|
|
+ const actions = diff( domChildren, viewChildren,
|
|
|
+ ( domNode, viewNode ) => converter.compareNodes( domNode, viewNode ) );
|
|
|
+
|
|
|
let i = 0;
|
|
|
|
|
|
for ( let action of actions ) {
|