|
|
@@ -20,12 +20,18 @@ import Range from '../view/range.js';
|
|
|
import Position from '../view/position.js';
|
|
|
import AttributeElement from '../view/attributeelement.js';
|
|
|
import ContainerElement from '../view/containerelement.js';
|
|
|
+import EmptyElement from '../view/emptyelement.js';
|
|
|
import ViewText from '../view/text.js';
|
|
|
|
|
|
const ELEMENT_RANGE_START_TOKEN = '[';
|
|
|
const ELEMENT_RANGE_END_TOKEN = ']';
|
|
|
const TEXT_RANGE_START_TOKEN = '{';
|
|
|
const TEXT_RANGE_END_TOKEN = '}';
|
|
|
+const allowedTypes = {
|
|
|
+ 'container': ContainerElement,
|
|
|
+ 'attribute': AttributeElement,
|
|
|
+ 'empty': EmptyElement,
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
* Writes the contents of the {@link engine.view.Document Document} to an HTML-like string.
|
|
|
@@ -38,7 +44,7 @@ const TEXT_RANGE_END_TOKEN = '}';
|
|
|
* @param {Boolean} [options.rootName='main'] Name of the root from which data should be stringified. If not provided
|
|
|
* default `main` name will be used.
|
|
|
* @param {Boolean} [options.showType=false] When set to `true` type of elements will be printed (`<container:p>`
|
|
|
- * instead of `<p>` and `<attribute:b>` instead of `<b>`).
|
|
|
+ * instead of `<p>`, `<attribute:b>` instead of `<b>` and `<empty:img>` instead of `<img>`).
|
|
|
* @param {Boolean} [options.showPriority=false] When set to `true` AttributeElement's priority will be printed
|
|
|
* (`<span view-priority="12">`, `<b view-priority="10">`).
|
|
|
* @returns {String} The stringified data.
|
|
|
@@ -162,13 +168,15 @@ setData._parse = parse;
|
|
|
*
|
|
|
* Additional options object can be provided.
|
|
|
* If `options.showType` is set to `true`, element's types will be
|
|
|
- * presented for {@link engine.view.AttributeElement AttributeElements} and {@link engine.view.ContainerElement
|
|
|
- * ContainerElements}:
|
|
|
+ * presented for {@link engine.view.AttributeElement AttributeElements}, {@link engine.view.ContainerElement
|
|
|
+ * ContainerElements} and {@link engine.view.EmptyElement EmptyElements}:
|
|
|
*
|
|
|
* const attribute = new AttributeElement( 'b' );
|
|
|
* const container = new ContainerElement( 'p' );
|
|
|
+ * const empty = new EmptyElement( 'img' );
|
|
|
* getData( attribute, null, { showType: true } ); // '<attribute:b></attribute:b>'
|
|
|
* getData( container, null, { showType: true } ); // '<container:p></container:p>'
|
|
|
+ * getData( empty, null, { showType: true } ); // '<empty:img></empty:img>'
|
|
|
*
|
|
|
* If `options.showPriority` is set to `true`, priority will be displayed for all
|
|
|
* {@link engine.view.AttributeElement AttributeElements}.
|
|
|
@@ -185,7 +193,7 @@ setData._parse = parse;
|
|
|
* containing one range collapsed at this position.
|
|
|
* @param {Object} [options] Object with additional options.
|
|
|
* @param {Boolean} [options.showType=false] When set to `true` type of elements will be printed (`<container:p>`
|
|
|
- * instead of `<p>` and `<attribute:b>` instead of `<b>`).
|
|
|
+ * instead of `<p>`, `<attribute:b>` instead of `<b>` and `<empty:img>` instead of `<img>`).
|
|
|
* @param {Boolean} [options.showPriority=false] When set to `true` AttributeElement's priority will be printed
|
|
|
* (`<span view-priority="12">`, `<b view-priority="10">`).
|
|
|
* @param {Boolean} [options.ignoreRoot=false] When set to `true` root's element opening and closing will not be printed.
|
|
|
@@ -288,7 +296,7 @@ export function parse( data, options = {} ) {
|
|
|
sameSelectionCharacters: options.sameSelectionCharacters
|
|
|
} );
|
|
|
const processor = new XmlDataProcessor( {
|
|
|
- namespaces: [ 'attribute', 'container' ]
|
|
|
+ namespaces: Object.keys( allowedTypes )
|
|
|
} );
|
|
|
|
|
|
// Convert data to view.
|
|
|
@@ -560,8 +568,8 @@ class ViewStringify {
|
|
|
* @param root
|
|
|
* @param {engine.view.Selection} [selection=null] Selection which ranges should be also converted to string.
|
|
|
* @param {Object} [options] Options object.
|
|
|
- * @param {Boolean} [options.showType=false] When set to `true` type of elements will be printed ( `<container:p>`
|
|
|
- * instead of `<p>` and `<attribute:b>` instead of `<b>`.
|
|
|
+ * @param {Boolean} [options.showType=false] When set to `true` type of elements will be printed (`<container:p>`
|
|
|
+ * instead of `<p>`, `<attribute:b>` instead of `<b>` and `<empty:img>` instead of `<img>`).
|
|
|
* @param {Boolean} [options.showPriority=false] When set to `true` AttributeElement's priority will be printed.
|
|
|
* @param {Boolean} [options.ignoreRoot=false] When set to `true` root's element opening and closing tag will not
|
|
|
* be outputted.
|
|
|
@@ -719,9 +727,9 @@ class ViewStringify {
|
|
|
|
|
|
/**
|
|
|
* Converts passed {@link engine.view.Element Element} to opening tag.
|
|
|
- * Depending on current configuration opening tag can be simple (`<a>`), contain type prefix (`<container:p>` or
|
|
|
- * `<attribute:a>`), contain priority information ( `<attribute:a view-priority="20">` ). Element's attributes also
|
|
|
- * will be included (`<a href="http://ckeditor.com" name="foobar">`).
|
|
|
+ * Depending on current configuration opening tag can be simple (`<a>`), contain type prefix (`<container:p>`,
|
|
|
+ * `<attribute:a>` or `<empty:img>`), contain priority information ( `<attribute:a view-priority="20">` ).
|
|
|
+ * Element's attributes also will be included (`<a href="http://ckeditor.com" name="foobar">`).
|
|
|
*
|
|
|
* @private
|
|
|
* @param {engine.view.Element} element
|
|
|
@@ -740,8 +748,8 @@ class ViewStringify {
|
|
|
|
|
|
/**
|
|
|
* Converts passed {@link engine.view.Element Element} to closing tag.
|
|
|
- * Depending on current configuration closing tag can be simple (`</a>`) or contain type prefix (`</container:p>` or
|
|
|
- * `</attribute:a>`).
|
|
|
+ * Depending on current configuration closing tag can be simple (`</a>`) or contain type prefix (`</container:p>`,
|
|
|
+ * `</attribute:a>` or `</empty:img>`).
|
|
|
*
|
|
|
* @private
|
|
|
* @param {engine.view.Element} element
|
|
|
@@ -756,9 +764,10 @@ class ViewStringify {
|
|
|
|
|
|
/**
|
|
|
* Converts passed {@link engine.view.Element Element's} type to its string representation
|
|
|
- * Returns 'attribute' for {@link engine.view.AttributeElement AttributeElements} and
|
|
|
- * 'container' for {@link engine.view.ContainerElement ContainerElements}. Returns empty string when current
|
|
|
- * configuration is preventing showing elements' types.
|
|
|
+ * Returns 'attribute' for {@link engine.view.AttributeElement AttributeElements},
|
|
|
+ * 'container' for {@link engine.view.ContainerElement ContainerElements} and 'empty' for
|
|
|
+ * {@link engine.view.EmptyElement EmptyElements}. Returns empty string when current configuration is preventing
|
|
|
+ * showing elements' types.
|
|
|
*
|
|
|
* @private
|
|
|
* @param {engine.view.Element} element
|
|
|
@@ -766,12 +775,10 @@ class ViewStringify {
|
|
|
*/
|
|
|
_stringifyElementType( element ) {
|
|
|
if ( this.showType ) {
|
|
|
- if ( element instanceof AttributeElement ) {
|
|
|
- return 'attribute';
|
|
|
- }
|
|
|
-
|
|
|
- if ( element instanceof ContainerElement ) {
|
|
|
- return 'container';
|
|
|
+ for ( let type in allowedTypes ) {
|
|
|
+ if ( element instanceof allowedTypes[ type ] ) {
|
|
|
+ return type;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -816,13 +823,14 @@ class ViewStringify {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// Converts {@link engine.view.Element Elements} to {@link engine.view.AttributeElement AttributeElements} and
|
|
|
-// {@link engine.view.ContainerElement ContainerElements}. It converts whole tree starting from the `rootNode`.
|
|
|
-// Conversion is based on element names. See `_convertElement` method for more details.
|
|
|
+// Converts {@link engine.view.Element Elements} to {@link engine.view.AttributeElement AttributeElements},
|
|
|
+// {@link engine.view.ContainerElement ContainerElements} or {@link engine.view.EmptyElement EmptyElements}.
|
|
|
+// It converts whole tree starting from the `rootNode`. Conversion is based on element names.
|
|
|
+// See `_convertElement` method for more details.
|
|
|
//
|
|
|
// @param {engine.view.Element|engine.view.DocumentFragment|engine.view.Text} rootNode Root node to convert.
|
|
|
// @returns {engine.view.Element|engine.view.DocumentFragment|engine.view.Text|engine.view.AttributeElement|
|
|
|
-// engine.view.ContainerElement} Root node of converted elements.
|
|
|
+// engine.view.ContainerElement|engine.view.EmptyElement} Root node of converted elements.
|
|
|
function _convertViewElements( rootNode ) {
|
|
|
const isFragment = rootNode instanceof ViewDocumentFragment;
|
|
|
|
|
|
@@ -832,6 +840,10 @@ function _convertViewElements( rootNode ) {
|
|
|
|
|
|
// Convert all child nodes.
|
|
|
for ( let child of rootNode.getChildren() ) {
|
|
|
+ if ( convertedElement instanceof EmptyElement ) {
|
|
|
+ throw new Error( `Parse error - cannot parse inside EmptyElement.` );
|
|
|
+ }
|
|
|
+
|
|
|
convertedElement.appendChildren( _convertViewElements( child ) );
|
|
|
}
|
|
|
|
|
|
@@ -841,12 +853,14 @@ function _convertViewElements( rootNode ) {
|
|
|
return rootNode;
|
|
|
}
|
|
|
|
|
|
-// Converts {@link engine.view.Element Element} to {@link engine.view.AttributeElement AttributeElement} or
|
|
|
-// {@link engine.view.ContainerElement ContainerElement}.
|
|
|
+// Converts {@link engine.view.Element Element} to {@link engine.view.AttributeElement AttributeElement},
|
|
|
+// {@link engine.view.ContainerElement ContainerElement} or {@link engine.view.EmptyElement EmptyElement}.
|
|
|
// If element's name is in format `attribute:b` with `view-priority="11"` attribute it will be converted to
|
|
|
// {@link engine.view.AttributeElement AttributeElement} with priority 11.
|
|
|
// If element's name is in format `container:p` - it will be converted to
|
|
|
// {@link engine.view.ContainerElement ContainerElement}.
|
|
|
+// If element's name is in format `empty:img` - it will be converted to
|
|
|
+// {@link engine.view.EmptyElement EmptyElement}.
|
|
|
// If element's name will not contain any additional information - {@link engine.view.Element view Element} will be
|
|
|
// returned.
|
|
|
//
|
|
|
@@ -854,19 +868,14 @@ function _convertViewElements( rootNode ) {
|
|
|
// @returns {engine.view.Element|engine.view.AttributeElement|engine.view.ContainerElement} Tree view
|
|
|
// element converted according to it's name.
|
|
|
function _convertElement( viewElement ) {
|
|
|
- let newElement;
|
|
|
const info = _convertElementNameAndPriority( viewElement );
|
|
|
+ const ElementConstructor = allowedTypes[ info.type ];
|
|
|
+ const newElement = ElementConstructor ? new ElementConstructor( info.name ) : new ViewElement( info.name );
|
|
|
|
|
|
- if ( info.type == 'attribute' ) {
|
|
|
- newElement = new AttributeElement( info.name );
|
|
|
-
|
|
|
+ if ( newElement instanceof AttributeElement ) {
|
|
|
if ( info.priority !== null ) {
|
|
|
newElement.priority = info.priority;
|
|
|
}
|
|
|
- } else if ( info.type == 'container' ) {
|
|
|
- newElement = new ContainerElement( info.name );
|
|
|
- } else {
|
|
|
- newElement = new ViewElement( info.name );
|
|
|
}
|
|
|
|
|
|
// Move attributes.
|
|
|
@@ -878,14 +887,15 @@ function _convertElement( viewElement ) {
|
|
|
}
|
|
|
|
|
|
// Converts `view-priority` attribute and {@link engine.view.Element#name Element's name} information needed for creating
|
|
|
-// {@link engine.view.AttributeElement AttributeElement} or {@link engine.view.ContainerElement ContainerElement} instance.
|
|
|
+// {@link engine.view.AttributeElement AttributeElement}, {@link engine.view.ContainerElement ContainerElement} or
|
|
|
+// {@link engine.view.EmptyElement EmptyElement} instance.
|
|
|
// Name can be provided in two formats: as a simple element's name (`div`), or as a type and name (`container:div`,
|
|
|
-// `attribute:span`);
|
|
|
+// `attribute:span`, `empty:img`);
|
|
|
//
|
|
|
// @param {engine.view.Element} element Element which name should be converted.
|
|
|
// @returns {Object} info Object with parsed information.
|
|
|
// @returns {String} info.name Parsed name of the element.
|
|
|
-// @returns {String|null} info.type Parsed type of the element, can be `attribute` or `container`.
|
|
|
+// @returns {String|null} info.type Parsed type of the element, can be `attribute`, `container` or `empty`.
|
|
|
// returns {Number|null} info.priority Parsed priority of the element.
|
|
|
function _convertElementNameAndPriority( viewElement ) {
|
|
|
const parts = viewElement.name.split( ':' );
|
|
|
@@ -914,16 +924,12 @@ function _convertElementNameAndPriority( viewElement ) {
|
|
|
throw new Error( `Parse error - cannot parse element's name: ${ viewElement.name }.` );
|
|
|
}
|
|
|
|
|
|
-// Checks if element's type is allowed. Returns `attribute`, `container` or `null`.
|
|
|
+// Checks if element's type is allowed. Returns `attribute`, `container`, `empty` or `null`.
|
|
|
//
|
|
|
// @param {String} type
|
|
|
// @returns {String|null}
|
|
|
function _convertType( type ) {
|
|
|
- if ( type == 'container' || type == 'attribute' ) {
|
|
|
- return type;
|
|
|
- }
|
|
|
-
|
|
|
- return null;
|
|
|
+ return allowedTypes[ type ] ? type : null;
|
|
|
}
|
|
|
|
|
|
// Checks if given priority is allowed. Returns null if priority cannot be converted.
|