|
@@ -5,6 +5,8 @@
|
|
|
|
|
|
|
|
'use strict';
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
+import TextProxy from '../treemodel/textproxy.js';
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Manages a list of consumable values for {@link engine.treeModel.Item model items}.
|
|
* Manages a list of consumable values for {@link engine.treeModel.Item model items}.
|
|
|
*
|
|
*
|
|
@@ -50,7 +52,7 @@
|
|
|
* // ├─ <img />
|
|
* // ├─ <img />
|
|
|
* // └─ <caption>
|
|
* // └─ <caption>
|
|
|
* // └─ foo
|
|
* // └─ foo
|
|
|
- * modelConversionDispatcher.on( 'insert:element:image', ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
|
|
+ * modelConversionDispatcher.on( 'insert:image', ( evt, data, consumable, conversionApi ) => {
|
|
|
* // First, consume the `image` element.
|
|
* // First, consume the `image` element.
|
|
|
* consumable.consume( data.item, 'insert' );
|
|
* consumable.consume( data.item, 'insert' );
|
|
|
*
|
|
*
|
|
@@ -67,7 +69,7 @@
|
|
|
* // It will not be converted by other converters, but it's children (probably some text) will be.
|
|
* // It will not be converted by other converters, but it's children (probably some text) will be.
|
|
|
* // Through mapping, converters for text will know where to insert contents of `modelCaption`.
|
|
* // Through mapping, converters for text will know where to insert contents of `modelCaption`.
|
|
|
* if ( consumable.consume( modelCaption, 'insert' ) ) {
|
|
* if ( consumable.consume( modelCaption, 'insert' ) ) {
|
|
|
- * const viewCaption = new ViewElement( 'figuaption' );
|
|
|
|
|
|
|
+ * const viewCaption = new ViewElement( 'figcaption' );
|
|
|
*
|
|
*
|
|
|
* const viewImageHolder = new ViewElement( 'figure', null, [ viewImage, viewCaption ] );
|
|
* const viewImageHolder = new ViewElement( 'figure', null, [ viewImage, viewCaption ] );
|
|
|
*
|
|
*
|
|
@@ -94,9 +96,22 @@ export default class ModelConsumable {
|
|
|
* Contains list of consumable values.
|
|
* Contains list of consumable values.
|
|
|
*
|
|
*
|
|
|
* @private
|
|
* @private
|
|
|
- * @member {Map} engine.treeController.ModelConsumable#_consumable.
|
|
|
|
|
|
|
+ * @member {Map} engine.treeController.ModelConsumable#_consumable
|
|
|
*/
|
|
*/
|
|
|
this._consumable = new Map();
|
|
this._consumable = new Map();
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * For each {@link engine.treeModel.TextProxy} added to `ModelConsumable`, this registry holds parent
|
|
|
|
|
+ * of that `TextProxy` and start and end indices of that `TextProxy`. This allows identification of `TextProxy`
|
|
|
|
|
+ * instances that points to the same part of the model but are different instances. Each distinct `TextProxy`
|
|
|
|
|
+ * is given unique `Symbol` which is then registered as consumable. This process is transparent for `ModelConsumable`
|
|
|
|
|
+ * API user because whenever `TextProxy` is added, tested, consumed or reverted, internal mechanisms of
|
|
|
|
|
+ * `ModelConsumable` translates `TextProxy` to that unique `Symbol`.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ * @member {Map} engine.treeController.ModelConsumable#_textParentsRegistry
|
|
|
|
|
+ */
|
|
|
|
|
+ this._textProxyRegistry = new Map();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -110,6 +125,10 @@ export default class ModelConsumable {
|
|
|
* @param {String} type Consumable type.
|
|
* @param {String} type Consumable type.
|
|
|
*/
|
|
*/
|
|
|
add( item, type ) {
|
|
add( item, type ) {
|
|
|
|
|
+ if ( item instanceof TextProxy ) {
|
|
|
|
|
+ item = this._getSymbolForTextProxy( item );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if ( !this._consumable.has( item ) ) {
|
|
if ( !this._consumable.has( item ) ) {
|
|
|
this._consumable.set( item, new Map() );
|
|
this._consumable.set( item, new Map() );
|
|
|
}
|
|
}
|
|
@@ -129,6 +148,10 @@ export default class ModelConsumable {
|
|
|
* @returns {Boolean} `true` if consumable value was available and was consumed, `false` otherwise.
|
|
* @returns {Boolean} `true` if consumable value was available and was consumed, `false` otherwise.
|
|
|
*/
|
|
*/
|
|
|
consume( item, type ) {
|
|
consume( item, type ) {
|
|
|
|
|
+ if ( item instanceof TextProxy ) {
|
|
|
|
|
+ item = this._getSymbolForTextProxy( item );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if ( this.test( item, type ) ) {
|
|
if ( this.test( item, type ) ) {
|
|
|
this._consumable.get( item ).set( type, false );
|
|
this._consumable.get( item ).set( type, false );
|
|
|
|
|
|
|
@@ -151,6 +174,10 @@ export default class ModelConsumable {
|
|
|
* already consumed or `true` if it was added and not consumed yet.
|
|
* already consumed or `true` if it was added and not consumed yet.
|
|
|
*/
|
|
*/
|
|
|
test( item, type ) {
|
|
test( item, type ) {
|
|
|
|
|
+ if ( item instanceof TextProxy ) {
|
|
|
|
|
+ item = this._getSymbolForTextProxy( item );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const itemConsumables = this._consumable.get( item );
|
|
const itemConsumables = this._consumable.get( item );
|
|
|
|
|
|
|
|
if ( itemConsumables === undefined ) {
|
|
if ( itemConsumables === undefined ) {
|
|
@@ -179,6 +206,10 @@ export default class ModelConsumable {
|
|
|
* never been added.
|
|
* never been added.
|
|
|
*/
|
|
*/
|
|
|
revert( item, type ) {
|
|
revert( item, type ) {
|
|
|
|
|
+ if ( item instanceof TextProxy ) {
|
|
|
|
|
+ item = this._getSymbolForTextProxy( item );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const test = this.test( item, type );
|
|
const test = this.test( item, type );
|
|
|
|
|
|
|
|
if ( test === false ) {
|
|
if ( test === false ) {
|
|
@@ -191,4 +222,72 @@ export default class ModelConsumable {
|
|
|
|
|
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Gets a unique symbol for passed {@link engine.treeModel.TextProxy} instance. All `TextProxy` instances that
|
|
|
|
|
+ * have same parent, same start index and same end index will get the same symbol.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Used internally to correctly consume `TextProxy` instances.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ * @param {engine.treeModel.TextProxy} textProxy `TextProxy` instance to get a symbol for.
|
|
|
|
|
+ * @returns {Symbol} Symbol representing all equal instances of `TextProxy`.
|
|
|
|
|
+ */
|
|
|
|
|
+ _getSymbolForTextProxy( textProxy ) {
|
|
|
|
|
+ let symbol = null;
|
|
|
|
|
+
|
|
|
|
|
+ const startIndex = textProxy.first.getIndex();
|
|
|
|
|
+ const endIndex = startIndex + textProxy.text.length;
|
|
|
|
|
+ const parent = textProxy.commonParent;
|
|
|
|
|
+
|
|
|
|
|
+ const startIndexMap = this._textProxyRegistry.get( startIndex );
|
|
|
|
|
+
|
|
|
|
|
+ if ( startIndexMap ) {
|
|
|
|
|
+ const endIndexMap = startIndexMap.get( endIndex );
|
|
|
|
|
+
|
|
|
|
|
+ if ( endIndexMap ) {
|
|
|
|
|
+ symbol = endIndexMap.get( parent );
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( !symbol ) {
|
|
|
|
|
+ symbol = this._addSymbolForTextProxy( startIndex, endIndex, parent );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return symbol;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Adds a symbol for given properties that characterizes a {@link engine.treeModel.TextProxy} instance.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Used internally to correctly consume `TextProxy` instances.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @private
|
|
|
|
|
+ * @param {Number} startIndex Text proxy start index in it's parent.
|
|
|
|
|
+ * @param {Number} endIndex Text proxy end index in it's parent.
|
|
|
|
|
+ * @param {engine.treeModel.Element} parent Text proxy parent.
|
|
|
|
|
+ * @returns {Symbol} Symbol generated for given properties.
|
|
|
|
|
+ */
|
|
|
|
|
+ _addSymbolForTextProxy( startIndex, endIndex, parent ) {
|
|
|
|
|
+ const symbol = Symbol();
|
|
|
|
|
+ let startIndexMap, endIndexMap;
|
|
|
|
|
+
|
|
|
|
|
+ startIndexMap = this._textProxyRegistry.get( startIndex );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !startIndexMap ) {
|
|
|
|
|
+ startIndexMap = new Map();
|
|
|
|
|
+ this._textProxyRegistry.set( startIndex, startIndexMap );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ endIndexMap = startIndexMap.get( endIndex );
|
|
|
|
|
+
|
|
|
|
|
+ if ( !endIndexMap ) {
|
|
|
|
|
+ endIndexMap = new Map();
|
|
|
|
|
+ startIndexMap.set( endIndex, endIndexMap );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ endIndexMap.set( parent, symbol );
|
|
|
|
|
+
|
|
|
|
|
+ return symbol;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|