|
|
@@ -7,6 +7,8 @@
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
+import CKEditorError from '../ckeditorerror.js';
|
|
|
+
|
|
|
/**
|
|
|
* Basic Template class.
|
|
|
*
|
|
|
@@ -30,31 +32,60 @@ export default class Template {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Renders HTMLElement using {@link #def}.
|
|
|
+ * Renders DOM Node using {@link #def}.
|
|
|
*
|
|
|
* @returns {HTMLElement}
|
|
|
*/
|
|
|
render() {
|
|
|
- return this._renderElement( this.def, true );
|
|
|
+ return this._renderNode( this.def, true );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Renders an element from definition.
|
|
|
+ * Renders a DOM Node from definition.
|
|
|
*
|
|
|
* @protected
|
|
|
- * @param {TemplateDefinition} def Definition of an element.
|
|
|
+ * @param {TemplateDefinition} def Definition of a Node.
|
|
|
* @param {Boolean} intoFragment If set, children are rendered into DocumentFragment.
|
|
|
- * @returns {HTMLElement} A rendered element.
|
|
|
+ * @returns {HTMLElement} A rendered Node.
|
|
|
*/
|
|
|
- _renderElement( def, intoFragment ) {
|
|
|
+ _renderNode( def, intoFragment ) {
|
|
|
if ( !def ) {
|
|
|
- return null;
|
|
|
+ /**
|
|
|
+ * Node definition must have either "tag" or "text" property.
|
|
|
+ *
|
|
|
+ * @error ui-template-wrong-syntax
|
|
|
+ */
|
|
|
+ throw new CKEditorError( 'ui-template-wrong-syntax' );
|
|
|
}
|
|
|
|
|
|
- const el = document.createElement( def.tag );
|
|
|
+ const isText = def.text || typeof def == 'string';
|
|
|
+
|
|
|
+ // !XOR( def.tag, isText )
|
|
|
+ if ( ( def.tag ? isText : !isText ) ) {
|
|
|
+ throw new CKEditorError( 'ui-template-wrong-syntax' );
|
|
|
+ }
|
|
|
+
|
|
|
+ let el;
|
|
|
+
|
|
|
+ if ( isText ) {
|
|
|
+ el = this._renderText( def );
|
|
|
+ } else {
|
|
|
+ el = this._renderElement( def, intoFragment );
|
|
|
+ }
|
|
|
+
|
|
|
+ return el;
|
|
|
+ }
|
|
|
|
|
|
- // Set the text first.
|
|
|
- this._renderElementText( def, el );
|
|
|
+ /**
|
|
|
+ * Renders a HTMLElement from TemplateDefinition.
|
|
|
+ *
|
|
|
+ * @protected
|
|
|
+ * @param {TemplateDefinition} def Definition of an element.
|
|
|
+ * @param {Boolean} intoFragment If set, children are rendered into DocumentFragment.
|
|
|
+ * @returns {HTMLElement} A rendered element.
|
|
|
+ */
|
|
|
+ _renderElement( def, intoFragment ) {
|
|
|
+ const el = document.createElement( def.tag );
|
|
|
|
|
|
// Set attributes.
|
|
|
this._renderElementAttributes( def, el );
|
|
|
@@ -70,27 +101,39 @@ export default class Template {
|
|
|
this._renderElementChildren( def, el );
|
|
|
}
|
|
|
|
|
|
- // Activate DOM binding for event listeners.
|
|
|
+ // Activate DOM bindings for event listeners.
|
|
|
this._activateElementListeners( def, el );
|
|
|
|
|
|
return el;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Renders element text content from definition.
|
|
|
+ * Renders a Text from TemplateDefinition or String.
|
|
|
*
|
|
|
* @protected
|
|
|
- * @param {TemplateDefinition} def Definition of an element.
|
|
|
- * @param {HTMLElement} el Element which is rendered.
|
|
|
+ * @param {TemplateDefinition|String} def Definition of Text or its value.
|
|
|
+ * @returns {Text} A rendered Text.
|
|
|
*/
|
|
|
- _renderElementText( def, el ) {
|
|
|
- if ( def.text ) {
|
|
|
- if ( typeof def.text == 'function' ) {
|
|
|
- def.text( el, getTextUpdater() );
|
|
|
- } else {
|
|
|
- el.textContent = def.text;
|
|
|
+ _renderText( defOrText ) {
|
|
|
+ const el = document.createTextNode( '' );
|
|
|
+
|
|
|
+ // Case: { text: ... }
|
|
|
+ if ( defOrText.text ) {
|
|
|
+ // Case: { text: func }, like binding
|
|
|
+ if ( typeof defOrText.text == 'function' ) {
|
|
|
+ defOrText.text( el, getTextUpdater() );
|
|
|
+ }
|
|
|
+ // Case: { text: 'foo' }
|
|
|
+ else {
|
|
|
+ el.textContent = defOrText.text;
|
|
|
}
|
|
|
}
|
|
|
+ // Case: 'foo'
|
|
|
+ else {
|
|
|
+ el.textContent = defOrText;
|
|
|
+ }
|
|
|
+
|
|
|
+ return el;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -132,12 +175,10 @@ export default class Template {
|
|
|
* @param {HTMLElement} el Element which is rendered.
|
|
|
*/
|
|
|
_renderElementChildren( def, el ) {
|
|
|
- let child;
|
|
|
-
|
|
|
if ( def.children ) {
|
|
|
- for ( child of def.children ) {
|
|
|
- el.appendChild( this._renderElement( child ) );
|
|
|
- }
|
|
|
+ def.children.map( childDef => {
|
|
|
+ el.appendChild( this._renderNode( childDef ) );
|
|
|
+ } );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -205,11 +246,13 @@ function getAttributeUpdater( attr ) {
|
|
|
* {
|
|
|
* tag: 'span',
|
|
|
* attrs: { ... },
|
|
|
- * on: { ... }
|
|
|
+ * children: [ ... ],
|
|
|
+ * ...
|
|
|
* },
|
|
|
* {
|
|
|
- * ...
|
|
|
+ * text: 'abc'
|
|
|
* },
|
|
|
+ * 'def',
|
|
|
* ...
|
|
|
* ],
|
|
|
* attrs: {
|
|
|
@@ -224,8 +267,7 @@ function getAttributeUpdater( attr ) {
|
|
|
* 'event3@selector': 'd',
|
|
|
* 'event4@selector': [ 'e', 'f', callback ],
|
|
|
* ...
|
|
|
- * },
|
|
|
- * text: 'abc'
|
|
|
+ * }
|
|
|
* }
|
|
|
*
|
|
|
* @typedef TemplateDefinition
|