documentation and fix tests
This commit is contained in:
		
							parent
							
								
									61149b458a
								
							
						
					
					
						commit
						135c6d31be
					
				| @ -1,15 +1,11 @@ | |||||||
| /* global MutationObserver */ | /* global MutationObserver */ | ||||||
| 
 | 
 | ||||||
| import Binding from '../Binding.js' | import Binding from '../Binding.js' | ||||||
| import diff from '../../Util/simpleDiff.js' | import { createAssociation, removeAssociation } from './util.js' | ||||||
| import YXmlFragment from '../../Types/YXml/YXmlFragment.js' |  | ||||||
| import YXmlHook from '../../Types/YXml/YXmlHook.js' |  | ||||||
| import { removeDomChildrenUntilElementFound, createAssociation } from './util.js' |  | ||||||
| import { beforeTransactionSelectionFixer, afterTransactionSelectionFixer } from './selection.js' | import { beforeTransactionSelectionFixer, afterTransactionSelectionFixer } from './selection.js' | ||||||
| import { defaultFilter, applyFilterOnType } from './filter.js' | import { defaultFilter, applyFilterOnType } from './filter.js' | ||||||
| import typeObserver from './typeObserver.js' | import typeObserver from './typeObserver.js' | ||||||
| import domObserver from './domObserver.js' | import domObserver from './domObserver.js' | ||||||
| import { removeAssociation } from './util.js' |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A binding that binds the children of a YXmlFragment to a DOM element. |  * A binding that binds the children of a YXmlFragment to a DOM element. | ||||||
|  | |||||||
| @ -69,7 +69,6 @@ export function insertNodeHelper (yxml, prevExpectedNode, child, _document, bind | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Remove children until `elem` is found. |  * Remove children until `elem` is found. | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -46,3 +46,20 @@ export function logID (id) { | |||||||
|     throw new Error('This is not a valid ID!') |     throw new Error('This is not a valid ID!') | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Helper utility to convert an item to a readable format. | ||||||
|  |  * | ||||||
|  |  * @param {String} name The name of the item class (YText, ItemString, ..). | ||||||
|  |  * @param {Item} item The item instance. | ||||||
|  |  * @param {String} [append] Additional information to append to the returned | ||||||
|  |  *                          string. | ||||||
|  |  * @return {String} A readable string that represents the item object. | ||||||
|  |  * | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | export function logItemHelper (name, item, append) { | ||||||
|  |   const left = item._left !== null ? item._left._lastId : null | ||||||
|  |   const origin = item._origin !== null ? item._origin._lastId : null | ||||||
|  |   return `${name}(id:${logID(item._id)},start:${logID(item._start)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})` | ||||||
|  | } | ||||||
|  | |||||||
| @ -111,9 +111,10 @@ export default class Delete { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|    * @private |    * @private | ||||||
|    * Transform this Delete to a readable format. |  | ||||||
|    * Useful for logging as all Items implement this method. |  | ||||||
|    */ |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     return `Delete - target: ${logID(this._targetID)}, len: ${this._length}` |     return `Delete - target: ${logID(this._targetID)}, len: ${this._length}` | ||||||
|  | |||||||
| @ -48,33 +48,76 @@ export function splitHelper (y, a, b, diff) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @private |  | ||||||
|  * Abstract class that represents any content. |  * Abstract class that represents any content. | ||||||
|  */ |  */ | ||||||
| export default class Item { | export default class Item { | ||||||
|   constructor () { |   constructor () { | ||||||
|  |     /** | ||||||
|  |      * The uniqe identifier of this type. | ||||||
|  |      * @type {ID} | ||||||
|  |      */ | ||||||
|     this._id = null |     this._id = null | ||||||
|  |     /** | ||||||
|  |      * The item that was originally to the left of this item. | ||||||
|  |      * @type {Item} | ||||||
|  |      */ | ||||||
|     this._origin = null |     this._origin = null | ||||||
|  |     /** | ||||||
|  |      * The item that is currently to the left of this item. | ||||||
|  |      * @type {Item} | ||||||
|  |      */ | ||||||
|     this._left = null |     this._left = null | ||||||
|  |     /** | ||||||
|  |      * The item that is currently to the right of this item. | ||||||
|  |      * @type {Item} | ||||||
|  |      */ | ||||||
|     this._right = null |     this._right = null | ||||||
|  |     /** | ||||||
|  |      * The item that was originally to the right of this item. | ||||||
|  |      * @type {Item} | ||||||
|  |      */ | ||||||
|     this._right_origin = null |     this._right_origin = null | ||||||
|  |     /** | ||||||
|  |      * The parent type. | ||||||
|  |      * @type {Y|YType} | ||||||
|  |      */ | ||||||
|     this._parent = null |     this._parent = null | ||||||
|  |     /** | ||||||
|  |      * If the parent refers to this item with some kind of key (e.g. YMap, the | ||||||
|  |      * key is specified here. The key is then used to refer to the list in which | ||||||
|  |      * to insert this item. If `parentSub = null` type._start is the list in | ||||||
|  |      * which to insert to. Otherwise it is `parent._start`. | ||||||
|  |      * @type {String} | ||||||
|  |      */ | ||||||
|     this._parentSub = null |     this._parentSub = null | ||||||
|  |     /** | ||||||
|  |      * Whether this item was deleted or not. | ||||||
|  |      * @type {Boolean} | ||||||
|  |      */ | ||||||
|     this._deleted = false |     this._deleted = false | ||||||
|  |     /** | ||||||
|  |      * If this type's effect is reundone this type refers to the type that undid | ||||||
|  |      * this operation. | ||||||
|  |      * @type {Item} | ||||||
|  |      */ | ||||||
|     this._redone = null |     this._redone = null | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Creates an Item with the same effect as this Item (without position effect) |    * Creates an Item with the same effect as this Item (without position effect) | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _copy () { |   _copy () { | ||||||
|     return new this.constructor() |     return new this.constructor() | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Redoes the effect of this operation. |    * Redoes the effect of this operation. | ||||||
|  |    * | ||||||
|  |    * @param {Y} y The Yjs instance. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _redo (y) { |   _redo (y) { | ||||||
|     if (this._redone !== null) { |     if (this._redone !== null) { | ||||||
| @ -117,35 +160,37 @@ export default class Item { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Computes the last content address of this Item. |    * Computes the last content address of this Item. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   get _lastId () { |   get _lastId () { | ||||||
|     return new ID(this._id.user, this._id.clock + this._length - 1) |     return new ID(this._id.user, this._id.clock + this._length - 1) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Computes the length of this Item. |    * Computes the length of this Item. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   get _length () { |   get _length () { | ||||||
|     return 1 |     return 1 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Should return false if this Item is some kind of meta information |    * Should return false if this Item is some kind of meta information | ||||||
|    * (e.g. format information). |    * (e.g. format information). | ||||||
|    * |    * | ||||||
|    * * Whether this Item should be addressable via `yarray.get(i)` |    * * Whether this Item should be addressable via `yarray.get(i)` | ||||||
|    * * Whether this Item should be counted when computing yarray.length |    * * Whether this Item should be counted when computing yarray.length | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   get _countable () { |   get _countable () { | ||||||
|     return true |     return true | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Splits this Item so that another Items can be inserted in-between. |    * Splits this Item so that another Items can be inserted in-between. | ||||||
|    * This must be overwritten if _length > 1 |    * This must be overwritten if _length > 1 | ||||||
|    * Returns right part after split |    * Returns right part after split | ||||||
| @ -153,6 +198,8 @@ export default class Item { | |||||||
|    * * diff === length => this._right |    * * diff === length => this._right | ||||||
|    * * otherwise => split _content and return right part of split |    * * otherwise => split _content and return right part of split | ||||||
|    * (see {@link ItemJSON}/{@link ItemString} for implementation) |    * (see {@link ItemJSON}/{@link ItemString} for implementation) | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _splitAt (y, diff) { |   _splitAt (y, diff) { | ||||||
|     if (diff === 0) { |     if (diff === 0) { | ||||||
| @ -162,12 +209,13 @@ export default class Item { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Mark this Item as deleted. |    * Mark this Item as deleted. | ||||||
|    * |    * | ||||||
|    * @param {Y} y The Yjs instance |    * @param {Y} y The Yjs instance | ||||||
|    * @param {boolean} createDelete Whether to propagate a message that this |    * @param {boolean} createDelete Whether to propagate a message that this | ||||||
|    *                               Type was deleted. |    *                               Type was deleted. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _delete (y, createDelete = true) { |   _delete (y, createDelete = true) { | ||||||
|     if (!this._deleted) { |     if (!this._deleted) { | ||||||
| @ -189,16 +237,16 @@ export default class Item { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * This is called right before this Item receives any children. |    * This is called right before this Item receives any children. | ||||||
|    * It can be overwritten to apply pending changes before applying remote changes |    * It can be overwritten to apply pending changes before applying remote changes | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _beforeChange () { |   _beforeChange () { | ||||||
|     // nop
 |     // nop
 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Integrates this Item into the shared structure. |    * Integrates this Item into the shared structure. | ||||||
|    * |    * | ||||||
|    * This method actually applies the change to the Yjs instance. In case of |    * This method actually applies the change to the Yjs instance. In case of | ||||||
| @ -208,6 +256,8 @@ export default class Item { | |||||||
|    * * Integrate the struct so that other types/structs can see it |    * * Integrate the struct so that other types/structs can see it | ||||||
|    * * Add this struct to y.os |    * * Add this struct to y.os | ||||||
|    * * Check if this is struct deleted |    * * Check if this is struct deleted | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _integrate (y) { |   _integrate (y) { | ||||||
|     y._transaction.newTypes.add(this) |     y._transaction.newTypes.add(this) | ||||||
| @ -328,13 +378,14 @@ export default class Item { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Transform the properties of this type to binary and write it to an |    * Transform the properties of this type to binary and write it to an | ||||||
|    * BinaryEncoder. |    * BinaryEncoder. | ||||||
|    * |    * | ||||||
|    * This is called when this Item is sent to a remote peer. |    * This is called when this Item is sent to a remote peer. | ||||||
|    * |    * | ||||||
|    * @param {BinaryEncoder} encoder The encoder to write data to. |    * @param {BinaryEncoder} encoder The encoder to write data to. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _toBinary (encoder) { |   _toBinary (encoder) { | ||||||
|     encoder.writeUint8(getStructReference(this.constructor)) |     encoder.writeUint8(getStructReference(this.constructor)) | ||||||
| @ -378,13 +429,14 @@ export default class Item { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Read the next Item in a Decoder and fill this Item with the read data. |    * Read the next Item in a Decoder and fill this Item with the read data. | ||||||
|    * |    * | ||||||
|    * This is called when data is received from a remote peer. |    * This is called when data is received from a remote peer. | ||||||
|    * |    * | ||||||
|    * @param {Y} y The Yjs instance that this Item belongs to. |    * @param {Y} y The Yjs instance that this Item belongs to. | ||||||
|    * @param {BinaryDecoder} decoder The decoder object to read data from. |    * @param {BinaryDecoder} decoder The decoder object to read data from. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _fromBinary (y, decoder) { |   _fromBinary (y, decoder) { | ||||||
|     let missing = [] |     let missing = [] | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { default as Item } from './Item.js' | import { default as Item } from './Item.js' | ||||||
| import { logID } from '../MessageHandler/messageToString.js' | import { logItemHelper } from '../MessageHandler/messageToString.js' | ||||||
| 
 | 
 | ||||||
| export default class ItemEmbed extends Item { | export default class ItemEmbed extends Item { | ||||||
|   constructor () { |   constructor () { | ||||||
| @ -23,9 +23,13 @@ export default class ItemEmbed extends Item { | |||||||
|     super._toBinary(encoder) |     super._toBinary(encoder) | ||||||
|     encoder.writeVarString(JSON.stringify(this.embed)) |     encoder.writeVarString(JSON.stringify(this.embed)) | ||||||
|   } |   } | ||||||
|  |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|  |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('ItemEmbed', this, `embed:${JSON.stringify(this.embed)}`) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `ItemEmbed(id:${logID(this._id)},embed:${JSON.stringify(this.embed)},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { default as Item } from './Item.js' | import { default as Item } from './Item.js' | ||||||
| import { logID } from '../MessageHandler/messageToString.js' | import { logItemHelper } from '../MessageHandler/messageToString.js' | ||||||
| 
 | 
 | ||||||
| export default class ItemFormat extends Item { | export default class ItemFormat extends Item { | ||||||
|   constructor () { |   constructor () { | ||||||
| @ -30,9 +30,13 @@ export default class ItemFormat extends Item { | |||||||
|     encoder.writeVarString(this.key) |     encoder.writeVarString(this.key) | ||||||
|     encoder.writeVarString(JSON.stringify(this.value)) |     encoder.writeVarString(JSON.stringify(this.value)) | ||||||
|   } |   } | ||||||
|  |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|  |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('ItemFormat', this, `key:${JSON.stringify(this.key)},value:${JSON.stringify(this.value)}`) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `ItemFormat(id:${logID(this._id)},key:${JSON.stringify(this.key)},value:${JSON.stringify(this.value)},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { splitHelper, default as Item } from './Item.js' | import { splitHelper, default as Item } from './Item.js' | ||||||
| import { logID } from '../MessageHandler/messageToString.js' | import { logItemHelper } from '../MessageHandler/messageToString.js' | ||||||
| 
 | 
 | ||||||
| export default class ItemJSON extends Item { | export default class ItemJSON extends Item { | ||||||
|   constructor () { |   constructor () { | ||||||
| @ -45,10 +45,14 @@ export default class ItemJSON extends Item { | |||||||
|       encoder.writeVarString(encoded) |       encoder.writeVarString(encoded) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|  |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('ItemJSON', this, `content:${JSON.stringify(this._content)}`) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `ItemJSON(id:${logID(this._id)},content:${JSON.stringify(this._content)},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
|   _splitAt (y, diff) { |   _splitAt (y, diff) { | ||||||
|     if (diff === 0) { |     if (diff === 0) { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { splitHelper, default as Item } from './Item.js' | import { splitHelper, default as Item } from './Item.js' | ||||||
| import { logID } from '../MessageHandler/messageToString.js' | import { logItemHelper } from '../MessageHandler/messageToString.js' | ||||||
| 
 | 
 | ||||||
| export default class ItemString extends Item { | export default class ItemString extends Item { | ||||||
|   constructor () { |   constructor () { | ||||||
| @ -23,10 +23,14 @@ export default class ItemString extends Item { | |||||||
|     super._toBinary(encoder) |     super._toBinary(encoder) | ||||||
|     encoder.writeVarString(this._content) |     encoder.writeVarString(this._content) | ||||||
|   } |   } | ||||||
|  |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|  |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('ItemString', this, `content:"${this._content}"`) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `ItemJSON(id:${logID(this._id)},content:${JSON.stringify(this._content)},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
|   _splitAt (y, diff) { |   _splitAt (y, diff) { | ||||||
|     if (diff === 0) { |     if (diff === 0) { | ||||||
|  | |||||||
| @ -62,22 +62,22 @@ export default class Type extends Item { | |||||||
|     } |     } | ||||||
|     const path = [] |     const path = [] | ||||||
|     const y = this._y |     const y = this._y | ||||||
|     while (type._parent !== this && this._parent !== y) { |     while (type !== this && type !== y) { | ||||||
|       let parent = type._parent |       let parent = type._parent | ||||||
|       if (type._parentSub !== null) { |       if (type._parentSub !== null) { | ||||||
|         path.push(type._parentSub) |         path.unshift(type._parentSub) | ||||||
|       } else { |       } else { | ||||||
|         // parent is array-ish
 |         // parent is array-ish
 | ||||||
|         for (let [i, child] of parent) { |         for (let [i, child] of parent) { | ||||||
|           if (child === type) { |           if (child === type) { | ||||||
|             path.push(i) |             path.unshift(i) | ||||||
|             break |             break | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       type = parent |       type = parent | ||||||
|     } |     } | ||||||
|     if (this._parent !== this) { |     if (type !== this) { | ||||||
|       throw new Error('The type is not a child of this node') |       throw new Error('The type is not a child of this node') | ||||||
|     } |     } | ||||||
|     return path |     return path | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import Type from '../../Struct/Type.js' | import Type from '../../Struct/Type.js' | ||||||
| import ItemJSON from '../../Struct/ItemJSON.js' | import ItemJSON from '../../Struct/ItemJSON.js' | ||||||
| import ItemString from '../../Struct/ItemString.js' | import ItemString from '../../Struct/ItemString.js' | ||||||
| import { logID } from '../../MessageHandler/messageToString.js' | import { logID, logItemHelper } from '../../MessageHandler/messageToString.js' | ||||||
| import YEvent from '../../Util/YEvent.js' | import YEvent from '../../Util/YEvent.js' | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -367,13 +367,12 @@ export default class YArray extends Type { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|    * @private |    * @private | ||||||
|    * Transform this YArray to a readable format. |  | ||||||
|    * Useful for logging as all Items implement this method. |  | ||||||
|    */ |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('YArray', this, `start:${logID(this._start)}"`) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `YArray(id:${logID(this._id)},start:${logID(this._start)},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import Type from '../../Struct/Type.js' | import Type from '../../Struct/Type.js' | ||||||
| import Item from '../../Struct/Item.js' | import Item from '../../Struct/Item.js' | ||||||
| import ItemJSON from '../../Struct/ItemJSON.js' | import ItemJSON from '../../Struct/ItemJSON.js' | ||||||
| import { logID } from '../../MessageHandler/messageToString.js' | import { logItemHelper } from '../../MessageHandler/messageToString.js' | ||||||
| import YEvent from '../../Util/YEvent.js' | import YEvent from '../../Util/YEvent.js' | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -164,13 +164,12 @@ export default class YMap extends Type { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  |    * Transform this YXml Type to a readable format. | ||||||
|  |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|    * @private |    * @private | ||||||
|    * Transform this YMap to a readable format. |  | ||||||
|    * Useful for logging as all Items implement this method. |  | ||||||
|    */ |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('YMap', this, `mapSize:${this._map.size}`) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `YMap(id:${logID(this._id)},mapSize:${this._map.size},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,12 @@ | |||||||
| import ItemString from '../../Struct/ItemString.js' | import ItemString from '../../Struct/ItemString.js' | ||||||
| import ItemEmbed from '../../Struct/ItemEmbed.js' | import ItemEmbed from '../../Struct/ItemEmbed.js' | ||||||
| import ItemFormat from '../../Struct/ItemFormat.js' | import ItemFormat from '../../Struct/ItemFormat.js' | ||||||
| import { logID } from '../../MessageHandler/messageToString.js' | import { logItemHelper } from '../../MessageHandler/messageToString.js' | ||||||
| import { YArrayEvent, default as YArray } from '../YArray/YArray.js' | import { YArrayEvent, default as YArray } from '../YArray/YArray.js' | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function integrateItem (item, parent, y, left, right) { | function integrateItem (item, parent, y, left, right) { | ||||||
|   item._origin = left |   item._origin = left | ||||||
|   item._left = left |   item._left = left | ||||||
| @ -19,6 +22,9 @@ function integrateItem (item, parent, y, left, right) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function findNextPosition (currentAttributes, parent, left, right, count) { | function findNextPosition (currentAttributes, parent, left, right, count) { | ||||||
|   while (right !== null && count > 0) { |   while (right !== null && count > 0) { | ||||||
|     switch (right.constructor) { |     switch (right.constructor) { | ||||||
| @ -46,6 +52,9 @@ function findNextPosition (currentAttributes, parent, left, right, count) { | |||||||
|   return [left, right, currentAttributes] |   return [left, right, currentAttributes] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function findPosition (parent, index) { | function findPosition (parent, index) { | ||||||
|   let currentAttributes = new Map() |   let currentAttributes = new Map() | ||||||
|   let left = null |   let left = null | ||||||
| @ -53,7 +62,11 @@ function findPosition (parent, index) { | |||||||
|   return findNextPosition(currentAttributes, parent, left, right, index) |   return findNextPosition(currentAttributes, parent, left, right, index) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // negate applied formats
 | /** | ||||||
|  |  * Negate applied formats | ||||||
|  |  * | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function insertNegatedAttributes (y, parent, left, right, negatedAttributes) { | function insertNegatedAttributes (y, parent, left, right, negatedAttributes) { | ||||||
|   // check if we really need to remove attributes
 |   // check if we really need to remove attributes
 | ||||||
|   while ( |   while ( | ||||||
| @ -80,6 +93,9 @@ function insertNegatedAttributes (y, parent, left, right, negatedAttributes) { | |||||||
|   return [left, right] |   return [left, right] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function updateCurrentAttributes (currentAttributes, item) { | function updateCurrentAttributes (currentAttributes, item) { | ||||||
|   const value = item.value |   const value = item.value | ||||||
|   const key = item.key |   const key = item.key | ||||||
| @ -90,6 +106,9 @@ function updateCurrentAttributes (currentAttributes, item) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function minimizeAttributeChanges (left, right, currentAttributes, attributes) { | function minimizeAttributeChanges (left, right, currentAttributes, attributes) { | ||||||
|   // go right while attributes[right.key] === right.value (or right is deleted)
 |   // go right while attributes[right.key] === right.value (or right is deleted)
 | ||||||
|   while (true) { |   while (true) { | ||||||
| @ -109,6 +128,9 @@ function minimizeAttributeChanges (left, right, currentAttributes, attributes) { | |||||||
|   return [left, right] |   return [left, right] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function insertAttributes (y, parent, left, right, attributes, currentAttributes) { | function insertAttributes (y, parent, left, right, attributes, currentAttributes) { | ||||||
|   const negatedAttributes = new Map() |   const negatedAttributes = new Map() | ||||||
|   // insert format-start items
 |   // insert format-start items
 | ||||||
| @ -125,9 +147,12 @@ function insertAttributes (y, parent, left, right, attributes, currentAttributes | |||||||
|       left = format |       left = format | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   return negatedAttributes |   return [left, right, negatedAttributes] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function insertText (y, text, parent, left, right, currentAttributes, attributes) { | function insertText (y, text, parent, left, right, currentAttributes, attributes) { | ||||||
|   for (let [key] of currentAttributes) { |   for (let [key] of currentAttributes) { | ||||||
|     if (attributes.hasOwnProperty(key) === false) { |     if (attributes.hasOwnProperty(key) === false) { | ||||||
| @ -135,7 +160,8 @@ function insertText (y, text, parent, left, right, currentAttributes, attributes | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   [left, right] = minimizeAttributeChanges(left, right, currentAttributes, attributes) |   [left, right] = minimizeAttributeChanges(left, right, currentAttributes, attributes) | ||||||
|   const negatedAttributes = insertAttributes(y, parent, left, right, attributes, currentAttributes) |   let negatedAttributes | ||||||
|  |   [left, right, negatedAttributes] = insertAttributes(y, parent, left, right, attributes, currentAttributes) | ||||||
|   // insert content
 |   // insert content
 | ||||||
|   let item |   let item | ||||||
|   if (text.constructor === String) { |   if (text.constructor === String) { | ||||||
| @ -150,9 +176,13 @@ function insertText (y, text, parent, left, right, currentAttributes, attributes | |||||||
|   return insertNegatedAttributes(y, parent, left, right, negatedAttributes) |   return insertNegatedAttributes(y, parent, left, right, negatedAttributes) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function formatText (y, length, parent, left, right, currentAttributes, attributes) { | function formatText (y, length, parent, left, right, currentAttributes, attributes) { | ||||||
|   [left, right] = minimizeAttributeChanges(left, right, currentAttributes, attributes) |   [left, right] = minimizeAttributeChanges(left, right, currentAttributes, attributes) | ||||||
|   const negatedAttributes = insertAttributes(y, parent, left, right, attributes, currentAttributes) |   let negatedAttributes | ||||||
|  |   [left, right, negatedAttributes] = insertAttributes(y, parent, left, right, attributes, currentAttributes) | ||||||
|   // iterate until first non-format or null is found
 |   // iterate until first non-format or null is found
 | ||||||
|   // delete all formats with attributes[format.key] != null
 |   // delete all formats with attributes[format.key] != null
 | ||||||
|   while (length > 0 && right !== null) { |   while (length > 0 && right !== null) { | ||||||
| @ -182,6 +212,9 @@ function formatText (y, length, parent, left, right, currentAttributes, attribut | |||||||
|   return insertNegatedAttributes(y, parent, left, right, negatedAttributes) |   return insertNegatedAttributes(y, parent, left, right, negatedAttributes) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
| function deleteText (y, length, parent, left, right, currentAttributes) { | function deleteText (y, length, parent, left, right, currentAttributes) { | ||||||
|   while (length > 0 && right !== null) { |   while (length > 0 && right !== null) { | ||||||
|     if (right._deleted === false) { |     if (right._deleted === false) { | ||||||
| @ -234,18 +267,23 @@ function deleteText (y, length, parent, left, right, currentAttributes) { | |||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Event that describes the changes on a YText type. |  * Event that describes the changes on a YText type. | ||||||
|  |  * | ||||||
|  |  * @private | ||||||
|  */ |  */ | ||||||
| class YTextEvent extends YArrayEvent { | class YTextEvent extends YArrayEvent { | ||||||
|   constructor (ytext, remote, transaction) { |   constructor (ytext, remote, transaction) { | ||||||
|     super(ytext, remote, transaction) |     super(ytext, remote, transaction) | ||||||
|     this._delta = null |     this._delta = null | ||||||
|   } |   } | ||||||
| 
 |   // TODO: Should put this in a separate function. toDelta shouldn't be included
 | ||||||
|  |   //       in every Yjs distribution
 | ||||||
|   /** |   /** | ||||||
|    * Compute the changes in the delta format. |    * Compute the changes in the delta format. | ||||||
|    * |    * | ||||||
|    * @return {Delta} A {@link https://quilljs.com/docs/delta/|Quill Delta}) that
 |    * @return {Delta} A {@link https://quilljs.com/docs/delta/|Quill Delta}) that
 | ||||||
|    *                 represents the changes on the document. |    *                 represents the changes on the document. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   get delta () { |   get delta () { | ||||||
|     if (this._delta === null) { |     if (this._delta === null) { | ||||||
| @ -438,6 +476,8 @@ export default class YText extends YArray { | |||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Returns the unformatted string representation of this YText type. |    * Returns the unformatted string representation of this YText type. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toString () { |   toString () { | ||||||
|     let str = '' |     let str = '' | ||||||
| @ -455,6 +495,8 @@ export default class YText extends YArray { | |||||||
|    * Apply a {@link Delta} on this shared YText type. |    * Apply a {@link Delta} on this shared YText type. | ||||||
|    * |    * | ||||||
|    * @param {Delta} delta The changes to apply on this element. |    * @param {Delta} delta The changes to apply on this element. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   applyDelta (delta) { |   applyDelta (delta) { | ||||||
|     this._transact(y => { |     this._transact(y => { | ||||||
| @ -478,6 +520,8 @@ export default class YText extends YArray { | |||||||
|    * Returns the Delta representation of this YText type. |    * Returns the Delta representation of this YText type. | ||||||
|    * |    * | ||||||
|    * @return {Delta} The Delta representation of this type. |    * @return {Delta} The Delta representation of this type. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toDelta () { |   toDelta () { | ||||||
|     let ops = [] |     let ops = [] | ||||||
| @ -527,6 +571,8 @@ export default class YText extends YArray { | |||||||
|    * @param {TextAttributes} attributes Optionally define some formatting |    * @param {TextAttributes} attributes Optionally define some formatting | ||||||
|    *                                    information to apply on the inserted |    *                                    information to apply on the inserted | ||||||
|    *                                    Text. |    *                                    Text. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   insert (index, text, attributes = {}) { |   insert (index, text, attributes = {}) { | ||||||
|     if (text.length <= 0) { |     if (text.length <= 0) { | ||||||
| @ -546,6 +592,7 @@ export default class YText extends YArray { | |||||||
|    * @param {TextAttributes} attributes Attribute information to apply on the |    * @param {TextAttributes} attributes Attribute information to apply on the | ||||||
|    *                                    embed |    *                                    embed | ||||||
|    * |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   insertEmbed (index, embed, attributes = {}) { |   insertEmbed (index, embed, attributes = {}) { | ||||||
|     if (embed.constructor !== Object) { |     if (embed.constructor !== Object) { | ||||||
| @ -562,6 +609,8 @@ export default class YText extends YArray { | |||||||
|    * |    * | ||||||
|    * @param {Integer} index Index at which to start deleting. |    * @param {Integer} index Index at which to start deleting. | ||||||
|    * @param {Integer} length The number of characters to remove. Defaults to 1. |    * @param {Integer} length The number of characters to remove. Defaults to 1. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   delete (index, length) { |   delete (index, length) { | ||||||
|     if (length === 0) { |     if (length === 0) { | ||||||
| @ -580,6 +629,8 @@ export default class YText extends YArray { | |||||||
|    * @param {Integer} length The amount of characters to assign properties to. |    * @param {Integer} length The amount of characters to assign properties to. | ||||||
|    * @param {TextAttributes} attributes Attribute information to apply on the |    * @param {TextAttributes} attributes Attribute information to apply on the | ||||||
|    *                                    text. |    *                                    text. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   format (index, length, attributes) { |   format (index, length, attributes) { | ||||||
|     this._transact(y => { |     this._transact(y => { | ||||||
| @ -590,15 +641,14 @@ export default class YText extends YArray { | |||||||
|       formatText(y, length, this, left, right, currentAttributes, attributes) |       formatText(y, length, this, left, right, currentAttributes, attributes) | ||||||
|     }) |     }) | ||||||
|   } |   } | ||||||
| 
 |   // TODO: De-duplicate code. The following code is in every type.
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Transform this YText to a readable format. |    * Transform this YText to a readable format. | ||||||
|    * Useful for logging as all Items implement this method. |    * Useful for logging as all Items implement this method. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('YText', this) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `YText(id:${logID(this._id)},start:${logID(this._start)},left:${logID(left)},origin:${logID(origin)},right:${logID(this._right)},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -43,13 +43,14 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Transform the properties of this type to binary and write it to an |    * Transform the properties of this type to binary and write it to an | ||||||
|    * BinaryEncoder. |    * BinaryEncoder. | ||||||
|    * |    * | ||||||
|    * This is called when this Item is sent to a remote peer. |    * This is called when this Item is sent to a remote peer. | ||||||
|    * |    * | ||||||
|    * @param {BinaryEncoder} encoder The encoder to write data to. |    * @param {BinaryEncoder} encoder The encoder to write data to. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _toBinary (encoder) { |   _toBinary (encoder) { | ||||||
|     super._toBinary(encoder) |     super._toBinary(encoder) | ||||||
| @ -57,7 +58,6 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Integrates this Item into the shared structure. |    * Integrates this Item into the shared structure. | ||||||
|    * |    * | ||||||
|    * This method actually applies the change to the Yjs instance. In case of |    * This method actually applies the change to the Yjs instance. In case of | ||||||
| @ -66,6 +66,10 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|    * |    * | ||||||
|    * * Checks for nodeName |    * * Checks for nodeName | ||||||
|    * * Sets domFilter |    * * Sets domFilter | ||||||
|  |    * | ||||||
|  |    * @param {Y} y The Yjs instance | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _integrate (y) { |   _integrate (y) { | ||||||
|     if (this.nodeName === null) { |     if (this.nodeName === null) { | ||||||
| @ -78,6 +82,10 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|    * Returns the string representation of this YXmlElement. |    * Returns the string representation of this YXmlElement. | ||||||
|    * The attributes are ordered by attribute-name, so you can easily use this |    * The attributes are ordered by attribute-name, so you can easily use this | ||||||
|    * method to compare YXmlElements |    * method to compare YXmlElements | ||||||
|  |    * | ||||||
|  |    * @return {String} The string representation of this type. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toString () { |   toString () { | ||||||
|     const attrs = this.getAttributes() |     const attrs = this.getAttributes() | ||||||
| @ -101,6 +109,8 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|    * Removes an attribute from this YXmlElement. |    * Removes an attribute from this YXmlElement. | ||||||
|    * |    * | ||||||
|    * @param {String} attributeName The attribute name that is to be removed. |    * @param {String} attributeName The attribute name that is to be removed. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   removeAttribute (attributeName) { |   removeAttribute (attributeName) { | ||||||
|     return YMap.prototype.delete.call(this, attributeName) |     return YMap.prototype.delete.call(this, attributeName) | ||||||
| @ -111,6 +121,8 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|    * |    * | ||||||
|    * @param {String} attributeName The attribute name that is to be set. |    * @param {String} attributeName The attribute name that is to be set. | ||||||
|    * @param {String} attributeValue The attribute value that is to be set. |    * @param {String} attributeValue The attribute value that is to be set. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   setAttribute (attributeName, attributeValue) { |   setAttribute (attributeName, attributeValue) { | ||||||
|     return YMap.prototype.set.call(this, attributeName, attributeValue) |     return YMap.prototype.set.call(this, attributeName, attributeValue) | ||||||
| @ -121,7 +133,9 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|    * |    * | ||||||
|    * @param {String} attributeName The attribute name that identifies the |    * @param {String} attributeName The attribute name that identifies the | ||||||
|    *                               queried value. |    *                               queried value. | ||||||
|    * @return {String} The queried attribute value |    * @return {String} The queried attribute value. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   getAttribute (attributeName) { |   getAttribute (attributeName) { | ||||||
|     return YMap.prototype.get.call(this, attributeName) |     return YMap.prototype.get.call(this, attributeName) | ||||||
| @ -131,6 +145,8 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|    * Returns all attribute name/value pairs in a JSON Object. |    * Returns all attribute name/value pairs in a JSON Object. | ||||||
|    * |    * | ||||||
|    * @return {Object} A JSON Object that describes the attributes. |    * @return {Object} A JSON Object that describes the attributes. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   getAttributes () { |   getAttributes () { | ||||||
|     const obj = {} |     const obj = {} | ||||||
| @ -141,11 +157,19 @@ export default class YXmlElement extends YXmlFragment { | |||||||
|     } |     } | ||||||
|     return obj |     return obj | ||||||
|   } |   } | ||||||
| 
 |   // TODO: outsource the binding property.
 | ||||||
|   /** |   /** | ||||||
|    * Creates a Dom Element that mirrors this YXmlElement. |    * Creates a Dom Element that mirrors this YXmlElement. | ||||||
|    * |    * | ||||||
|  |    * @param {Document} [_document=document] The document object (you must define | ||||||
|  |    *                                        this when calling this method in | ||||||
|  |    *                                        nodejs) | ||||||
|  |    * @param {DomBinding} [binding] You should not set this property. This is | ||||||
|  |    *                               used if DomBinding wants to create a | ||||||
|  |    *                               association to the created DOM type. | ||||||
|    * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 |    * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toDom (_document = document, binding) { |   toDom (_document = document, binding) { | ||||||
|     const dom = _document.createElement(this.nodeName) |     const dom = _document.createElement(this.nodeName) | ||||||
|  | |||||||
| @ -2,13 +2,39 @@ import YEvent from '../../Util/YEvent.js' | |||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * An Event that describes changes on a YXml Element or Yxml Fragment |  * An Event that describes changes on a YXml Element or Yxml Fragment | ||||||
|  |  * | ||||||
|  |  * @protected | ||||||
|  */ |  */ | ||||||
| export default class YXmlEvent extends YEvent { | export default class YXmlEvent extends YEvent { | ||||||
|  |   /** | ||||||
|  |    * @param {YType} target The target on which the event is created. | ||||||
|  |    * @param {Set} subs The set of changed attributes. `null` is included if the | ||||||
|  |    *                   child list changed. | ||||||
|  |    * @param {Boolean} remote Whether this change was created by a remote peer. | ||||||
|  |    * @param {Transaction} transaction The transaction instance with wich the | ||||||
|  |    *                                  change was created. | ||||||
|  |    */ | ||||||
|   constructor (target, subs, remote, transaction) { |   constructor (target, subs, remote, transaction) { | ||||||
|     super(target) |     super(target) | ||||||
|  |     /** | ||||||
|  |      * The transaction instance for the computed change. | ||||||
|  |      * @type {Transaction} | ||||||
|  |      */ | ||||||
|     this._transaction = transaction |     this._transaction = transaction | ||||||
|  |     /** | ||||||
|  |      * Whether the children changed. | ||||||
|  |      * @type {Boolean} | ||||||
|  |      */ | ||||||
|     this.childListChanged = false |     this.childListChanged = false | ||||||
|  |     /** | ||||||
|  |      * Set of all changed attributes. | ||||||
|  |      * @type {Set} | ||||||
|  |      */ | ||||||
|     this.attributesChanged = new Set() |     this.attributesChanged = new Set() | ||||||
|  |     /** | ||||||
|  |      * Whether this change was created by a remote peer. | ||||||
|  |      * @type {Boolean} | ||||||
|  |      */ | ||||||
|     this.remote = remote |     this.remote = remote | ||||||
|     subs.forEach((sub) => { |     subs.forEach((sub) => { | ||||||
|       if (sub === null) { |       if (sub === null) { | ||||||
|  | |||||||
| @ -1,13 +1,18 @@ | |||||||
| /* global MutationObserver */ |  | ||||||
| 
 |  | ||||||
| import { createAssociation } from '../../Bindings/DomBinding/util.js' | import { createAssociation } from '../../Bindings/DomBinding/util.js' | ||||||
| import YXmlTreeWalker from './YXmlTreeWalker.js' | import YXmlTreeWalker from './YXmlTreeWalker.js' | ||||||
| 
 | 
 | ||||||
| import YArray from '../YArray/YArray.js' | import YArray from '../YArray/YArray.js' | ||||||
| import YXmlEvent from './YXmlEvent.js' | import YXmlEvent from './YXmlEvent.js' | ||||||
| import { YXmlText, YXmlHook } from './YXml.js' | import { logItemHelper } from '../../MessageHandler/messageToString.js' | ||||||
| import { logID } from '../../MessageHandler/messageToString.js' | 
 | ||||||
| import diff from '../../Util/simpleDiff.js' | /** | ||||||
|  |  * Dom filter function. | ||||||
|  |  * | ||||||
|  |  * @callback domFilter | ||||||
|  |  * @param {string} nodeName The nodeName of the element | ||||||
|  |  * @param {Map} attributes The map of attributes. | ||||||
|  |  * @return {boolean} Whether to include the Dom node in the YXmlElement. | ||||||
|  |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Define the elements to which a set of CSS queries apply. |  * Define the elements to which a set of CSS queries apply. | ||||||
| @ -21,20 +26,31 @@ import diff from '../../Util/simpleDiff.js' | |||||||
|  * @typedef {string} CSS_Selector |  * @typedef {string} CSS_Selector | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Represents a list of {@link YXmlElement}. |  * Represents a list of {@link YXmlElement}.and {@link YXmlText} types. | ||||||
|  * A YxmlFragment does not have a nodeName and it does not have attributes. |  * A YxmlFragment is similar to a {@link YXmlElement}, but it does not have a | ||||||
|  * Therefore it also must not be added as a childElement. |  * nodeName and it does not have attributes. Though it can be bound to a DOM | ||||||
|  |  * element - in this case the attributes and the nodeName are not shared. | ||||||
|  |  * | ||||||
|  |  * @public | ||||||
|  */ |  */ | ||||||
| export default class YXmlFragment extends YArray { | export default class YXmlFragment extends YArray { | ||||||
|   /** |   /** | ||||||
|    * Create a subtree of childNodes. |    * Create a subtree of childNodes. | ||||||
|    * |    * | ||||||
|  |    * @example | ||||||
|  |    * const walker = elem.createTreeWalker(dom => dom.nodeName === 'div') | ||||||
|  |    * for (let node in walker) { | ||||||
|  |    *   // `node` is a div node
 | ||||||
|  |    *   nop(node) | ||||||
|  |    * } | ||||||
|  |    * | ||||||
|    * @param {Function} filter Function that is called on each child element and |    * @param {Function} filter Function that is called on each child element and | ||||||
|    *                          returns a Boolean indicating whether the child |    *                          returns a Boolean indicating whether the child | ||||||
|    *                          is to be included in the subtree. |    *                          is to be included in the subtree. | ||||||
|    * @return {TreeWalker} A subtree and a position within it. |    * @return {TreeWalker} A subtree and a position within it. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   createTreeWalker (filter) { |   createTreeWalker (filter) { | ||||||
|     return new YXmlTreeWalker(this, filter) |     return new YXmlTreeWalker(this, filter) | ||||||
| @ -52,6 +68,8 @@ export default class YXmlFragment extends YArray { | |||||||
|    * |    * | ||||||
|    * @param {CSS_Selector} query The query on the children. |    * @param {CSS_Selector} query The query on the children. | ||||||
|    * @return {?YXmlElement} The first element that matches the query or null. |    * @return {?YXmlElement} The first element that matches the query or null. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   querySelector (query) { |   querySelector (query) { | ||||||
|     query = query.toUpperCase() |     query = query.toUpperCase() | ||||||
| @ -72,6 +90,8 @@ export default class YXmlFragment extends YArray { | |||||||
|    * |    * | ||||||
|    * @param {CSS_Selector} query The query on the children |    * @param {CSS_Selector} query The query on the children | ||||||
|    * @return {Array<YXmlElement>} The elements that match this query. |    * @return {Array<YXmlElement>} The elements that match this query. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   querySelectorAll (query) { |   querySelectorAll (query) { | ||||||
|     query = query.toUpperCase() |     query = query.toUpperCase() | ||||||
| @ -79,17 +99,9 @@ export default class YXmlFragment extends YArray { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Dom filter function. |  | ||||||
|    * |  | ||||||
|    * @callback domFilter |  | ||||||
|    * @param {string} nodeName The nodeName of the element |  | ||||||
|    * @param {Map} attributes The map of attributes. |  | ||||||
|    * @return {boolean} Whether to include the Dom node in the YXmlElement. |  | ||||||
|    */ |  | ||||||
| 
 |  | ||||||
|   /** |  | ||||||
|    * @private |  | ||||||
|    * Creates YArray Event and calls observers. |    * Creates YArray Event and calls observers. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _callObserver (transaction, parentSubs, remote) { |   _callObserver (transaction, parentSubs, remote) { | ||||||
|     this._callEventHandler(transaction, new YXmlEvent(this, parentSubs, remote, transaction)) |     this._callEventHandler(transaction, new YXmlEvent(this, parentSubs, remote, transaction)) | ||||||
| @ -111,13 +123,25 @@ export default class YXmlFragment extends YArray { | |||||||
|    * @param {Y} y The Yjs instance |    * @param {Y} y The Yjs instance | ||||||
|    * @param {boolean} createDelete Whether to propagate a message that this |    * @param {boolean} createDelete Whether to propagate a message that this | ||||||
|    *                               Type was deleted. |    *                               Type was deleted. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _delete (y, createDelete) { |   _delete (y, createDelete) { | ||||||
|     super._delete(y, createDelete) |     super._delete(y, createDelete) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @return {DocumentFragment} The dom representation of this |    * Creates a Dom Element that mirrors this YXmlElement. | ||||||
|  |    * | ||||||
|  |    * @param {Document} [_document=document] The document object (you must define | ||||||
|  |    *                                        this when calling this method in | ||||||
|  |    *                                        nodejs) | ||||||
|  |    * @param {DomBinding} [binding] You should not set this property. This is | ||||||
|  |    *                               used if DomBinding wants to create a | ||||||
|  |    *                               association to the created DOM type. | ||||||
|  |    * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toDom (_document = document, binding) { |   toDom (_document = document, binding) { | ||||||
|     const fragment = _document.createDocumentFragment() |     const fragment = _document.createDocumentFragment() | ||||||
| @ -128,13 +152,12 @@ export default class YXmlFragment extends YArray { | |||||||
|     return fragment |     return fragment | ||||||
|   } |   } | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Transform this YXml Type to a readable format. |    * Transform this YXml Type to a readable format. | ||||||
|    * Useful for logging as all Items implement this method. |    * Useful for logging as all Items and Delete implement this method. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _logString () { |   _logString () { | ||||||
|     const left = this._left !== null ? this._left._lastId : null |     return logItemHelper('YXml', this) | ||||||
|     const origin = this._origin !== null ? this._origin._lastId : null |  | ||||||
|     return `YXml(id:${logID(this._id)},left:${logID(left)},origin:${logID(origin)},right:${this._right},parent:${logID(this._parent)},parentSub:${this._parentSub})` |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,21 +4,24 @@ import { getHook, addHook } from './hooks.js' | |||||||
| /** | /** | ||||||
|  * You can manage binding to a custom type with YXmlHook. |  * You can manage binding to a custom type with YXmlHook. | ||||||
|  * |  * | ||||||
|  * @param {String} hookName nodeName of the Dom Node. |  * @public | ||||||
|  */ |  */ | ||||||
| export default class YXmlHook extends YMap { | export default class YXmlHook extends YMap { | ||||||
|  |   /** | ||||||
|  |    * @param {String} hookName nodeName of the Dom Node. | ||||||
|  |    */ | ||||||
|   constructor (hookName) { |   constructor (hookName) { | ||||||
|     super() |     super() | ||||||
|     this.hookName = null |     this.hookName = null | ||||||
|     if (hookName !== undefined) { |     if (hookName !== undefined) { | ||||||
|       this.hookName = hookName |       this.hookName = hookName | ||||||
|       dom._yjsHook = hookName |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Creates an Item with the same effect as this Item (without position effect) |    * Creates an Item with the same effect as this Item (without position effect) | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _copy () { |   _copy () { | ||||||
|     const struct = super._copy() |     const struct = super._copy() | ||||||
| @ -27,9 +30,17 @@ export default class YXmlHook extends YMap { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Creates a DOM element that represents this YXmlHook. |    * Creates a Dom Element that mirrors this YXmlElement. | ||||||
|    * |    * | ||||||
|    * @return Element The DOM representation of this Type. |    * @param {Document} [_document=document] The document object (you must define | ||||||
|  |    *                                        this when calling this method in | ||||||
|  |    *                                        nodejs) | ||||||
|  |    * @param {DomBinding} [binding] You should not set this property. This is | ||||||
|  |    *                               used if DomBinding wants to create a | ||||||
|  |    *                               association to the created DOM type. | ||||||
|  |    * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toDom (_document = document) { |   toDom (_document = document) { | ||||||
|     const dom = getHook(this.hookName).createDom(this) |     const dom = getHook(this.hookName).createDom(this) | ||||||
| @ -38,13 +49,14 @@ export default class YXmlHook extends YMap { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Read the next Item in a Decoder and fill this Item with the read data. |    * Read the next Item in a Decoder and fill this Item with the read data. | ||||||
|    * |    * | ||||||
|    * This is called when data is received from a remote peer. |    * This is called when data is received from a remote peer. | ||||||
|    * |    * | ||||||
|    * @param {Y} y The Yjs instance that this Item belongs to. |    * @param {Y} y The Yjs instance that this Item belongs to. | ||||||
|    * @param {BinaryDecoder} decoder The decoder object to read data from. |    * @param {BinaryDecoder} decoder The decoder object to read data from. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _fromBinary (y, decoder) { |   _fromBinary (y, decoder) { | ||||||
|     const missing = super._fromBinary(y, decoder) |     const missing = super._fromBinary(y, decoder) | ||||||
| @ -53,13 +65,14 @@ export default class YXmlHook extends YMap { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Transform the properties of this type to binary and write it to an |    * Transform the properties of this type to binary and write it to an | ||||||
|    * BinaryEncoder. |    * BinaryEncoder. | ||||||
|    * |    * | ||||||
|    * This is called when this Item is sent to a remote peer. |    * This is called when this Item is sent to a remote peer. | ||||||
|    * |    * | ||||||
|    * @param {BinaryEncoder} encoder The encoder to write data to. |    * @param {BinaryEncoder} encoder The encoder to write data to. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _toBinary (encoder) { |   _toBinary (encoder) { | ||||||
|     super._toBinary(encoder) |     super._toBinary(encoder) | ||||||
| @ -67,7 +80,6 @@ export default class YXmlHook extends YMap { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Integrate this type into the Yjs instance. |    * Integrate this type into the Yjs instance. | ||||||
|    * |    * | ||||||
|    * * Save this struct in the os |    * * Save this struct in the os | ||||||
| @ -75,6 +87,8 @@ export default class YXmlHook extends YMap { | |||||||
|    * * Observer functions are fired |    * * Observer functions are fired | ||||||
|    * |    * | ||||||
|    * @param {Y} y The Yjs instance |    * @param {Y} y The Yjs instance | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _integrate (y) { |   _integrate (y) { | ||||||
|     if (this.hookName === null) { |     if (this.hookName === null) { | ||||||
|  | |||||||
| @ -8,11 +8,18 @@ import { createAssociation } from '../../Bindings/DomBinding/util.js' | |||||||
|  * @param {String} arg1 Initial value. |  * @param {String} arg1 Initial value. | ||||||
|  */ |  */ | ||||||
| export default class YXmlText extends YText { | export default class YXmlText extends YText { | ||||||
| 
 |  | ||||||
|   /** |   /** | ||||||
|    * Creates a TextNode with the same textual content. |    * Creates a Dom Element that mirrors this YXmlText. | ||||||
|    * |    * | ||||||
|    * @return TextNode |    * @param {Document} [_document=document] The document object (you must define | ||||||
|  |    *                                        this when calling this method in | ||||||
|  |    *                                        nodejs) | ||||||
|  |    * @param {DomBinding} [binding] You should not set this property. This is | ||||||
|  |    *                               used if DomBinding wants to create a | ||||||
|  |    *                               association to the created DOM type. | ||||||
|  |    * @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
 | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   toDom (_document = document, binding) { |   toDom (_document = document, binding) { | ||||||
|     const dom = _document.createTextNode(this.toString()) |     const dom = _document.createTextNode(this.toString()) | ||||||
| @ -21,12 +28,13 @@ export default class YXmlText extends YText { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * @private |  | ||||||
|    * Mark this Item as deleted. |    * Mark this Item as deleted. | ||||||
|    * |    * | ||||||
|    * @param {Y} y The Yjs instance |    * @param {Y} y The Yjs instance | ||||||
|    * @param {boolean} createDelete Whether to propagate a message that this |    * @param {boolean} createDelete Whether to propagate a message that this | ||||||
|    *                               Type was deleted. |    *                               Type was deleted. | ||||||
|  |    * | ||||||
|  |    * @private | ||||||
|    */ |    */ | ||||||
|   _delete (y, createDelete) { |   _delete (y, createDelete) { | ||||||
|     super._delete(y, createDelete) |     super._delete(y, createDelete) | ||||||
|  | |||||||
| @ -17,6 +17,8 @@ import YXmlFragment from './YXmlFragment.js' | |||||||
|  * position within them. |  * position within them. | ||||||
|  * |  * | ||||||
|  * Can be created with {@link YXmlFragment#createTreeWalker} |  * Can be created with {@link YXmlFragment#createTreeWalker} | ||||||
|  |  * | ||||||
|  |  * @public | ||||||
|  */ |  */ | ||||||
| export default class YXmlTreeWalker { | export default class YXmlTreeWalker { | ||||||
|   constructor (root, f) { |   constructor (root, f) { | ||||||
| @ -32,6 +34,8 @@ export default class YXmlTreeWalker { | |||||||
|    * Get the next node. |    * Get the next node. | ||||||
|    * |    * | ||||||
|    * @return {YXmlElement} The next node. |    * @return {YXmlElement} The next node. | ||||||
|  |    * | ||||||
|  |    * @public | ||||||
|    */ |    */ | ||||||
|   next () { |   next () { | ||||||
|     let n = this._currentNode |     let n = this._currentNode | ||||||
|  | |||||||
| @ -3,6 +3,6 @@ | |||||||
|   <head> |   <head> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <script type="module" src="./index.js"></script> |     <script type="module" src="./diff.tests.js"></script> | ||||||
|   </body> |   </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -14,7 +14,6 @@ test('events', async function xml1 (t) { | |||||||
|   var { users, xml0, xml1 } = await initArrays(t, { users: 2 }) |   var { users, xml0, xml1 } = await initArrays(t, { users: 2 }) | ||||||
|   var event |   var event | ||||||
|   var remoteEvent |   var remoteEvent | ||||||
|   let expectedEvent |  | ||||||
|   xml0.observe(function (e) { |   xml0.observe(function (e) { | ||||||
|     delete e._content |     delete e._content | ||||||
|     delete e.nodes |     delete e.nodes | ||||||
| @ -30,21 +29,21 @@ test('events', async function xml1 (t) { | |||||||
|   xml0.setAttribute('key', 'value') |   xml0.setAttribute('key', 'value') | ||||||
|   t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key') |   t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key') | ||||||
|   await flushAll(t, users) |   await flushAll(t, users) | ||||||
|   t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key (remote)') |   t.assert(remoteEvent.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key (remote)') | ||||||
|   // check attributeRemoved
 |   // check attributeRemoved
 | ||||||
|   xml0.removeAttribute('key') |   xml0.removeAttribute('key') | ||||||
|   t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute') |   t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute') | ||||||
|   await flushAll(t, users) |   await flushAll(t, users) | ||||||
|   t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute (remote)') |   t.assert(remoteEvent.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute (remote)') | ||||||
|   xml0.insert(0, [new Y.XmlText('some text')]) |   xml0.insert(0, [new Y.XmlText('some text')]) | ||||||
|   t.assert(event.childListChanged, 'YXmlEvent.childListChanged on inserted element') |   t.assert(event.childListChanged, 'YXmlEvent.childListChanged on inserted element') | ||||||
|   await flushAll(t, users) |   await flushAll(t, users) | ||||||
|   t.assert(event.childListChanged, 'YXmlEvent.childListChanged on inserted element (remote)') |   t.assert(remoteEvent.childListChanged, 'YXmlEvent.childListChanged on inserted element (remote)') | ||||||
|   // test childRemoved
 |   // test childRemoved
 | ||||||
|   xml0.delete(0) |   xml0.delete(0) | ||||||
|   t.assert(event.childListChanged, 'YXmlEvent.childListChanged on deleted element') |   t.assert(event.childListChanged, 'YXmlEvent.childListChanged on deleted element') | ||||||
|   await flushAll(t, users) |   await flushAll(t, users) | ||||||
|   t.assert(event.childListChanged, 'YXmlEvent.childListChanged on deleted element (remote)') |   t.assert(remoteEvent.childListChanged, 'YXmlEvent.childListChanged on deleted element (remote)') | ||||||
|   await compareUsers(t, users) |   await compareUsers(t, users) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| @ -180,7 +179,7 @@ test('Receive a bunch of elements (with disconnect)', async function xml12 (t) { | |||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| test('move element to a different position', async function xml13 (t) { | test('move element to a different position', async function xml13 (t) { | ||||||
|   var { users, xml0, xml1, dom0, dom1 } = await initArrays(t, { users: 3 }) |   var { users, dom0, dom1 } = await initArrays(t, { users: 3 }) | ||||||
|   dom0.append(document.createElement('div')) |   dom0.append(document.createElement('div')) | ||||||
|   dom0.append(document.createElement('h1')) |   dom0.append(document.createElement('h1')) | ||||||
|   await flushAll(t, users) |   await flushAll(t, users) | ||||||
| @ -193,7 +192,7 @@ test('move element to a different position', async function xml13 (t) { | |||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| test('filter node', async function xml14 (t) { | test('filter node', async function xml14 (t) { | ||||||
|   var { users, xml0, xml1, dom0, dom1, domBinding0, domBinding1 } = await initArrays(t, { users: 3 }) |   var { users, dom0, dom1, domBinding0, domBinding1 } = await initArrays(t, { users: 3 }) | ||||||
|   let domFilter = (nodeName, attrs) => { |   let domFilter = (nodeName, attrs) => { | ||||||
|     if (nodeName === 'H1') { |     if (nodeName === 'H1') { | ||||||
|       return null |       return null | ||||||
| @ -212,7 +211,7 @@ test('filter node', async function xml14 (t) { | |||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| test('filter attribute', async function xml15 (t) { | test('filter attribute', async function xml15 (t) { | ||||||
|   var { users, xml0, xml1, dom0, dom1, domBinding0, domBinding1 } = await initArrays(t, { users: 3 }) |   var { users, dom0, dom1, domBinding0, domBinding1 } = await initArrays(t, { users: 3 }) | ||||||
|   let domFilter = (nodeName, attrs) => { |   let domFilter = (nodeName, attrs) => { | ||||||
|     attrs.delete('hidden') |     attrs.delete('hidden') | ||||||
|     return attrs |     return attrs | ||||||
| @ -231,7 +230,7 @@ test('filter attribute', async function xml15 (t) { | |||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| test('deep element insert', async function xml16 (t) { | test('deep element insert', async function xml16 (t) { | ||||||
|   var { users, xml0, xml1, dom0, dom1 } = await initArrays(t, { users: 3 }) |   var { users, dom0, dom1 } = await initArrays(t, { users: 3 }) | ||||||
|   let deepElement = document.createElement('p') |   let deepElement = document.createElement('p') | ||||||
|   let boldElement = document.createElement('b') |   let boldElement = document.createElement('b') | ||||||
|   let attrElement = document.createElement('img') |   let attrElement = document.createElement('img') | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| /* global Y */ |  | ||||||
| import { wait } from './helper' | import { wait } from './helper' | ||||||
| import { messageToString } from '../src/MessageHandler/messageToString' | import { messageToString } from '../src/MessageHandler/messageToString' | ||||||
| import AbstractConnector from '../src/Connector.js' | import AbstractConnector from '../src/Connector.js' | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user