Compare commits
12 Commits
v13.0.0-60
...
v13.0.0-61
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d50d408cdd | ||
|
|
db5312443e | ||
|
|
dbda07424b | ||
|
|
684d38d6c8 | ||
|
|
44fa064eb2 | ||
|
|
9b6fffd880 | ||
|
|
e9993b2643 | ||
|
|
762e9e8a3a | ||
|
|
6ddeb788c7 | ||
|
|
b9245f323c | ||
|
|
c0e630b635 | ||
|
|
ed2273e2ed |
@@ -70,7 +70,6 @@ missing modules.
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/y-websockets-client@8/dist/y-websockets-client.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/y-websockets-client@8/dist/y-websockets-client.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/y-memory@8/dist/y-memory.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/y-memory@8/dist/y-memory.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/y-map@10/dist/y-map.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/y-map@10/dist/y-map.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/y-text@9/dist/y-text.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/y-text@9/dist/y-text.js"></script>
|
||||||
// ..
|
// ..
|
||||||
@@ -89,7 +88,6 @@ var Y = require('yjs')
|
|||||||
require('y-array')(Y) // add the y-array type to Yjs
|
require('y-array')(Y) // add the y-array type to Yjs
|
||||||
require('y-websockets-client')(Y)
|
require('y-websockets-client')(Y)
|
||||||
require('y-memory')(Y)
|
require('y-memory')(Y)
|
||||||
require('y-array')(Y)
|
|
||||||
require('y-map')(Y)
|
require('y-map')(Y)
|
||||||
require('y-text')(Y)
|
require('y-text')(Y)
|
||||||
// ..
|
// ..
|
||||||
@@ -102,7 +100,6 @@ import Y from 'yjs'
|
|||||||
import yArray from 'y-array'
|
import yArray from 'y-array'
|
||||||
import yWebsocketsClient from 'y-webrtc'
|
import yWebsocketsClient from 'y-webrtc'
|
||||||
import yMemory from 'y-memory'
|
import yMemory from 'y-memory'
|
||||||
import yArray from 'y-array'
|
|
||||||
import yMap from 'y-map'
|
import yMap from 'y-map'
|
||||||
import yText from 'y-text'
|
import yText from 'y-text'
|
||||||
// ..
|
// ..
|
||||||
|
|||||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -1,9 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-60",
|
"version": "13.0.0-61",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/estree": {
|
||||||
|
"version": "0.0.38",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.38.tgz",
|
||||||
|
"integrity": "sha512-F/v7t1LwS4vnXuPooJQGBRKRGIoxWUTmA4VHfqjOccFsNDThD5bfUNpITive6s352O7o384wcpEaDV8rHCehDA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"version": "6.0.110",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.110.tgz",
|
||||||
|
"integrity": "sha512-LiaH3mF+OAqR+9Wo1OTJDbZDtCewAVjTbMhF1ZgUJ3fc8xqOJq6VqbpBh9dJVCVzByGmYIg2fREbuXNX0TKiJA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"abab": {
|
"abab": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
||||||
@@ -1498,6 +1510,7 @@
|
|||||||
"version": "2.6.8",
|
"version": "2.6.8",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
|
||||||
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
|
"integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
@@ -4806,7 +4819,8 @@
|
|||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"mute-stream": {
|
"mute-stream": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.5",
|
||||||
@@ -5629,6 +5643,16 @@
|
|||||||
"glob": "7.1.2"
|
"glob": "7.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rollup": {
|
||||||
|
"version": "0.58.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-0.58.2.tgz",
|
||||||
|
"integrity": "sha512-RZVvCWm9BHOYloaE6LLiE/ibpjv1CmI8F8k0B0Cp+q1eezo3cswszJH1DN0djgzSlo0hjuuCmyeI+1XOYLl4wg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/estree": "0.0.38",
|
||||||
|
"@types/node": "6.0.110"
|
||||||
|
}
|
||||||
|
},
|
||||||
"rollup-plugin-babel": {
|
"rollup-plugin-babel": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-2.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-2.7.1.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-60",
|
"version": "13.0.0-61",
|
||||||
"description": "A framework for real-time p2p shared editing on any data",
|
"description": "A framework for real-time p2p shared editing on any data",
|
||||||
"main": "./y.node.js",
|
"main": "./y.node.js",
|
||||||
"browser": "./y.js",
|
"browser": "./y.js",
|
||||||
@@ -61,6 +61,7 @@
|
|||||||
"esdoc-standard-plugin": "^1.0.0",
|
"esdoc-standard-plugin": "^1.0.0",
|
||||||
"quill": "^1.3.5",
|
"quill": "^1.3.5",
|
||||||
"quill-cursors": "^1.0.2",
|
"quill-cursors": "^1.0.2",
|
||||||
|
"rollup": "^0.58.2",
|
||||||
"rollup-plugin-babel": "^2.7.1",
|
"rollup-plugin-babel": "^2.7.1",
|
||||||
"rollup-plugin-commonjs": "^8.0.2",
|
"rollup-plugin-commonjs": "^8.0.2",
|
||||||
"rollup-plugin-inject": "^2.0.0",
|
"rollup-plugin-inject": "^2.0.0",
|
||||||
|
|||||||
@@ -121,12 +121,11 @@ export default class DomBinding extends Binding {
|
|||||||
destroy () {
|
destroy () {
|
||||||
this.domToType = null
|
this.domToType = null
|
||||||
this.typeToDom = null
|
this.typeToDom = null
|
||||||
this.type.unobserve(this._typeObserver)
|
this.type.unobserveDeep(this._typeObserver)
|
||||||
this._mutationObserver.disconnect()
|
this._mutationObserver.disconnect()
|
||||||
const y = this.type._y
|
const y = this.type._y
|
||||||
y.off('beforeTransaction', this._beforeTransactionHandler)
|
y.off('beforeTransaction', this._beforeTransactionHandler)
|
||||||
y.off('beforeObserverCalls', this._beforeObserverCallsHandler)
|
y.off('beforeObserverCalls', this._beforeObserverCallsHandler)
|
||||||
y.off('afterObserverCalls', this._afterObserverCallsHandler)
|
|
||||||
y.off('afterTransaction', this._afterTransactionHandler)
|
y.off('afterTransaction', this._afterTransactionHandler)
|
||||||
super.destroy()
|
super.destroy()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export default function domObserver (mutations, _document) {
|
|||||||
let parent = dom
|
let parent = dom
|
||||||
let yParent
|
let yParent
|
||||||
do {
|
do {
|
||||||
parent = parent.parentNode
|
parent = parent.parentElement
|
||||||
yParent = this.domToType.get(parent)
|
yParent = this.domToType.get(parent)
|
||||||
} while (yParent === undefined && parent !== null)
|
} while (yParent === undefined && parent !== null)
|
||||||
if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
|
if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
import { YXmlText, YXmlElement, YXmlHook } from '../../Types/YXml/YXml.js'
|
import YXmlText from '../../Types/YXml/YXmlText.js'
|
||||||
|
import YXmlHook from '../../Types/YXml/YXmlHook.js'
|
||||||
|
import YXmlElement from '../../Types/YXml/YXmlElement.js'
|
||||||
import { createAssociation, domsToTypes } from './util.js'
|
import { createAssociation, domsToTypes } from './util.js'
|
||||||
import { filterDomAttributes, defaultFilter } from './filter.js'
|
import { filterDomAttributes, defaultFilter } from './filter.js'
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ export default function typeObserver (events) {
|
|||||||
if (dom !== undefined && dom !== false) {
|
if (dom !== undefined && dom !== false) {
|
||||||
if (yxml.constructor === YXmlText) {
|
if (yxml.constructor === YXmlText) {
|
||||||
dom.nodeValue = yxml.toString()
|
dom.nodeValue = yxml.toString()
|
||||||
// TODO: use hasOwnProperty instead of === undefined check
|
|
||||||
} else if (event.attributesChanged !== undefined) {
|
} else if (event.attributesChanged !== undefined) {
|
||||||
// update attributes
|
// update attributes
|
||||||
event.attributesChanged.forEach(attributeName => {
|
event.attributesChanged.forEach(attributeName => {
|
||||||
|
|||||||
@@ -61,5 +61,5 @@ export function logID (id) {
|
|||||||
export function logItemHelper (name, item, append) {
|
export function logItemHelper (name, item, append) {
|
||||||
const left = item._left !== null ? item._left._lastId : null
|
const left = item._left !== null ? item._left._lastId : null
|
||||||
const origin = item._origin !== null ? item._origin._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 : ''})`
|
return `${name}(id:${logID(item._id)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ function insertAttributes (y, parent, left, right, attributes, currentAttributes
|
|||||||
*/
|
*/
|
||||||
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[key] === undefined) {
|
||||||
attributes[key] = null
|
attributes[key] = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,8 +189,9 @@ function formatText (y, length, parent, left, right, currentAttributes, attribut
|
|||||||
if (right._deleted === false) {
|
if (right._deleted === false) {
|
||||||
switch (right.constructor) {
|
switch (right.constructor) {
|
||||||
case ItemFormat:
|
case ItemFormat:
|
||||||
if (attributes.hasOwnProperty(right.key)) {
|
const attr = attributes[right.key]
|
||||||
if (attributes[right.key] === right.value) {
|
if (attr !== undefined) {
|
||||||
|
if (attr === right.value) {
|
||||||
negatedAttributes.delete(right.key)
|
negatedAttributes.delete(right.key)
|
||||||
} else {
|
} else {
|
||||||
negatedAttributes.set(right.key, right.value)
|
negatedAttributes.set(right.key, right.value)
|
||||||
@@ -405,8 +406,9 @@ class YTextEvent extends YArrayEvent {
|
|||||||
}
|
}
|
||||||
} else if (item._deleted === false) {
|
} else if (item._deleted === false) {
|
||||||
oldAttributes.set(item.key, item.value)
|
oldAttributes.set(item.key, item.value)
|
||||||
if (attributes.hasOwnProperty(item.key)) {
|
const attr = attributes[item.key]
|
||||||
if (attributes[item.key] !== item.value) {
|
if (attr !== undefined) {
|
||||||
|
if (attr !== item.value) {
|
||||||
if (action === 'retain') {
|
if (action === 'retain') {
|
||||||
addOp()
|
addOp()
|
||||||
}
|
}
|
||||||
@@ -433,7 +435,7 @@ class YTextEvent extends YArrayEvent {
|
|||||||
addOp()
|
addOp()
|
||||||
while (this._delta.length > 0) {
|
while (this._delta.length > 0) {
|
||||||
let lastOp = this._delta[this._delta.length - 1]
|
let lastOp = this._delta[this._delta.length - 1]
|
||||||
if (lastOp.hasOwnProperty('retain') && !lastOp.hasOwnProperty('attributes')) {
|
if (lastOp.retain !== undefined && lastOp.attributes === undefined) {
|
||||||
// retain delta's if they don't assign attributes
|
// retain delta's if they don't assign attributes
|
||||||
this._delta.pop()
|
this._delta.pop()
|
||||||
} else {
|
} else {
|
||||||
@@ -505,11 +507,11 @@ export default class YText extends YArray {
|
|||||||
const currentAttributes = new Map()
|
const currentAttributes = new Map()
|
||||||
for (let i = 0; i < delta.length; i++) {
|
for (let i = 0; i < delta.length; i++) {
|
||||||
let op = delta[i]
|
let op = delta[i]
|
||||||
if (op.hasOwnProperty('insert')) {
|
if (op.insert !== undefined) {
|
||||||
;[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {})
|
;[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {})
|
||||||
} else if (op.hasOwnProperty('retain')) {
|
} else if (op.retain !== undefined) {
|
||||||
;[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {})
|
;[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {})
|
||||||
} else if (op.hasOwnProperty('delete')) {
|
} else if (op.delete !== undefined) {
|
||||||
;[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes)
|
;[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
import YXmlFragment from './YXmlFragment.js'
|
|
||||||
import YXmlElement from './YXmlElement.js'
|
|
||||||
import YXmlHook from './YXmlHook.js'
|
|
||||||
|
|
||||||
export { default as YXmlFragment } from './YXmlFragment.js'
|
|
||||||
export { default as YXmlElement } from './YXmlElement.js'
|
|
||||||
export { default as YXmlText } from './YXmlText.js'
|
|
||||||
export { default as YXmlHook } from './YXmlHook.js'
|
|
||||||
|
|
||||||
YXmlFragment._YXmlElement = YXmlElement
|
|
||||||
YXmlFragment._YXmlHook = YXmlHook
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import YMap from '../YMap/YMap.js'
|
import YMap from '../YMap/YMap.js'
|
||||||
import { YXmlFragment } from './YXml.js'
|
import YXmlFragment from './YXmlFragment.js'
|
||||||
import { createAssociation } from '../../Bindings/DomBinding/util.js'
|
import { createAssociation } from '../../Bindings/DomBinding/util.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,3 +186,5 @@ export default class YXmlElement extends YXmlFragment {
|
|||||||
return dom
|
return dom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YXmlFragment._YXmlElement = YXmlElement
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import YArray from '../Types/YArray/YArray.js'
|
import YArray from '../Types/YArray/YArray.js'
|
||||||
import YMap from '../Types/YMap/YMap.js'
|
import YMap from '../Types/YMap/YMap.js'
|
||||||
import YText from '../Types/YText/YText.js'
|
import YText from '../Types/YText/YText.js'
|
||||||
import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from '../Types/YXml/YXml.js'
|
import YXmlText from '../Types/YXml/YXmlText.js'
|
||||||
|
import YXmlHook from '../Types/YXml/YXmlHook.js'
|
||||||
|
import YXmlFragment from '../Types/YXml/YXmlFragment.js'
|
||||||
|
import YXmlElement from '../Types/YXml/YXmlElement.js'
|
||||||
|
|
||||||
import Delete from '../Struct/Delete.js'
|
import Delete from '../Struct/Delete.js'
|
||||||
import ItemJSON from '../Struct/ItemJSON.js'
|
import ItemJSON from '../Struct/ItemJSON.js'
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import Persistence from './Persistence.js'
|
|||||||
import YArray from './Types/YArray/YArray.js'
|
import YArray from './Types/YArray/YArray.js'
|
||||||
import YMap from './Types/YMap/YMap.js'
|
import YMap from './Types/YMap/YMap.js'
|
||||||
import YText from './Types/YText/YText.js'
|
import YText from './Types/YText/YText.js'
|
||||||
import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from './Types/YXml/YXml.js'
|
import YXmlText from './Types/YXml/YXmlText.js'
|
||||||
|
import YXmlHook from './Types/YXml/YXmlHook.js'
|
||||||
|
import YXmlFragment from './Types/YXml/YXmlFragment.js'
|
||||||
|
import YXmlElement from './Types/YXml/YXmlElement.js'
|
||||||
import BinaryDecoder from './Util/Binary/Decoder.js'
|
import BinaryDecoder from './Util/Binary/Decoder.js'
|
||||||
import { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
|
import { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
|
||||||
import { registerStruct } from './Util/structReferences.js'
|
import { registerStruct } from './Util/structReferences.js'
|
||||||
|
|||||||
779
y.node.js
779
y.node.js
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* yjs - A framework for real-time p2p shared editing on any data
|
* yjs - A framework for real-time p2p shared editing on any data
|
||||||
* @version v13.0.0-60
|
* @version v13.0.0-61
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1341,7 +1341,7 @@ function logID (id) {
|
|||||||
return `(${id.user},${id.clock})`
|
return `(${id.user},${id.clock})`
|
||||||
} else if (id instanceof RootID) {
|
} else if (id instanceof RootID) {
|
||||||
return `(${id.name},${id.type})`
|
return `(${id.name},${id.type})`
|
||||||
} else if (id.constructor === Y$1) {
|
} else if (id.constructor === Y) {
|
||||||
return `y`
|
return `y`
|
||||||
} else {
|
} else {
|
||||||
throw new Error('This is not a valid ID!')
|
throw new Error('This is not a valid ID!')
|
||||||
@@ -1362,7 +1362,7 @@ function logID (id) {
|
|||||||
function logItemHelper (name, item, append) {
|
function logItemHelper (name, item, append) {
|
||||||
const left = item._left !== null ? item._left._lastId : null;
|
const left = item._left !== null ? item._left._lastId : null;
|
||||||
const origin = item._origin !== null ? item._origin._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 : ''})`
|
return `${name}(id:${logID(item._id)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1835,9 +1835,7 @@ class Item {
|
|||||||
const userState = y.ss.getState(user);
|
const userState = y.ss.getState(user);
|
||||||
if (selfID === null) {
|
if (selfID === null) {
|
||||||
this._id = y.ss.getNextID(this._length);
|
this._id = y.ss.getNextID(this._length);
|
||||||
} else if (selfID.user === RootFakeUserID) {
|
} else if (selfID.user === RootFakeUserID) ; else if (selfID.clock < userState) {
|
||||||
// nop
|
|
||||||
} else if (selfID.clock < userState) {
|
|
||||||
// already applied..
|
// already applied..
|
||||||
return []
|
return []
|
||||||
} else if (selfID.clock === userState) {
|
} else if (selfID.clock === userState) {
|
||||||
@@ -2165,8 +2163,6 @@ function integrateChildren (y, start) {
|
|||||||
} while (right !== null)
|
} while (right !== null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function gcChildren (y, item) {
|
function gcChildren (y, item) {
|
||||||
while (item !== null) {
|
while (item !== null) {
|
||||||
item._delete(y, false, true);
|
item._delete(y, false, true);
|
||||||
@@ -3252,9 +3248,7 @@ function minimizeAttributeChanges (left, right, currentAttributes, attributes) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
if (right === null) {
|
if (right === null) {
|
||||||
break
|
break
|
||||||
} else if (right._deleted === true) {
|
} else if (right._deleted === true) ; else if (right.constructor === ItemFormat && (attributes[right.key] || null) === right.value) {
|
||||||
// continue
|
|
||||||
} else if (right.constructor === ItemFormat && (attributes[right.key] || null) === right.value) {
|
|
||||||
// found a format, update currentAttributes and continue
|
// found a format, update currentAttributes and continue
|
||||||
updateCurrentAttributes(currentAttributes, right);
|
updateCurrentAttributes(currentAttributes, right);
|
||||||
} else {
|
} else {
|
||||||
@@ -3293,7 +3287,7 @@ function insertAttributes (y, parent, left, right, attributes, currentAttributes
|
|||||||
*/
|
*/
|
||||||
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[key] === undefined) {
|
||||||
attributes[key] = null;
|
attributes[key] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3327,8 +3321,9 @@ function formatText (y, length, parent, left, right, currentAttributes, attribut
|
|||||||
if (right._deleted === false) {
|
if (right._deleted === false) {
|
||||||
switch (right.constructor) {
|
switch (right.constructor) {
|
||||||
case ItemFormat:
|
case ItemFormat:
|
||||||
if (attributes.hasOwnProperty(right.key)) {
|
const attr = attributes[right.key];
|
||||||
if (attributes[right.key] === right.value) {
|
if (attr !== undefined) {
|
||||||
|
if (attr === right.value) {
|
||||||
negatedAttributes.delete(right.key);
|
negatedAttributes.delete(right.key);
|
||||||
} else {
|
} else {
|
||||||
negatedAttributes.set(right.key, right.value);
|
negatedAttributes.set(right.key, right.value);
|
||||||
@@ -3543,8 +3538,9 @@ class YTextEvent extends YArrayEvent {
|
|||||||
}
|
}
|
||||||
} else if (item._deleted === false) {
|
} else if (item._deleted === false) {
|
||||||
oldAttributes.set(item.key, item.value);
|
oldAttributes.set(item.key, item.value);
|
||||||
if (attributes.hasOwnProperty(item.key)) {
|
const attr = attributes[item.key];
|
||||||
if (attributes[item.key] !== item.value) {
|
if (attr !== undefined) {
|
||||||
|
if (attr !== item.value) {
|
||||||
if (action === 'retain') {
|
if (action === 'retain') {
|
||||||
addOp();
|
addOp();
|
||||||
}
|
}
|
||||||
@@ -3571,7 +3567,7 @@ class YTextEvent extends YArrayEvent {
|
|||||||
addOp();
|
addOp();
|
||||||
while (this._delta.length > 0) {
|
while (this._delta.length > 0) {
|
||||||
let lastOp = this._delta[this._delta.length - 1];
|
let lastOp = this._delta[this._delta.length - 1];
|
||||||
if (lastOp.hasOwnProperty('retain') && !lastOp.hasOwnProperty('attributes')) {
|
if (lastOp.retain !== undefined && lastOp.attributes === undefined) {
|
||||||
// retain delta's if they don't assign attributes
|
// retain delta's if they don't assign attributes
|
||||||
this._delta.pop();
|
this._delta.pop();
|
||||||
} else {
|
} else {
|
||||||
@@ -3643,12 +3639,12 @@ class YText extends YArray {
|
|||||||
const currentAttributes = new Map();
|
const currentAttributes = new Map();
|
||||||
for (let i = 0; i < delta.length; i++) {
|
for (let i = 0; i < delta.length; i++) {
|
||||||
let op = delta[i];
|
let op = delta[i];
|
||||||
if (op.hasOwnProperty('insert')) {
|
if (op.insert !== undefined) {
|
||||||
[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {});
|
[left, right] = insertText(y, op.insert, this, left, right, currentAttributes, op.attributes || {});
|
||||||
} else if (op.hasOwnProperty('retain')) {
|
} else if (op.retain !== undefined) {
|
||||||
[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {});
|
[left, right] = formatText(y, op.retain, this, left, right, currentAttributes, op.attributes || {});
|
||||||
} else if (op.hasOwnProperty('delete')) {
|
} else if (op.delete !== undefined) {
|
||||||
[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes);
|
[left, right] = deleteText(y, op.delete, this, left, right, currentAttributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3792,258 +3788,108 @@ class YText extends YArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if `parent` is a parent of `child`.
|
* You can manage binding to a custom type with YXmlHook.
|
||||||
*
|
|
||||||
* @param {Type} parent
|
|
||||||
* @param {Type} child
|
|
||||||
* @return {Boolean} Whether `parent` is a parent of `child`.
|
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
function isParentOf (parent, child) {
|
class YXmlHook extends YMap {
|
||||||
child = child._parent;
|
/**
|
||||||
while (child !== null) {
|
* @param {String} hookName nodeName of the Dom Node.
|
||||||
if (child === parent) {
|
*/
|
||||||
return true
|
constructor (hookName) {
|
||||||
|
super();
|
||||||
|
this.hookName = null;
|
||||||
|
if (hookName !== undefined) {
|
||||||
|
this.hookName = hookName;
|
||||||
}
|
}
|
||||||
child = child._parent;
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default filter method (does nothing).
|
* Creates an Item with the same effect as this Item (without position effect)
|
||||||
*
|
*
|
||||||
* @param {String} nodeName The nodeName of the element
|
* @private
|
||||||
* @param {Map} attrs Map of key-value pairs that are attributes of the node.
|
*/
|
||||||
* @return {Map | null} The allowed attributes or null, if the element should be
|
_copy () {
|
||||||
* filtered.
|
const struct = super._copy();
|
||||||
*/
|
struct.hookName = this.hookName;
|
||||||
function defaultFilter (nodeName, attrs) {
|
return struct
|
||||||
// TODO: implement basic filter that filters out dangerous properties!
|
|
||||||
return attrs
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function filterDomAttributes (dom, filter) {
|
|
||||||
const attrs = new Map();
|
|
||||||
for (let i = dom.attributes.length - 1; i >= 0; i--) {
|
|
||||||
const attr = dom.attributes[i];
|
|
||||||
attrs.set(attr.name, attr.value);
|
|
||||||
}
|
}
|
||||||
return filter(dom.nodeName, attrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a filter on a type.
|
* Creates a Dom Element that mirrors this YXmlElement.
|
||||||
*
|
*
|
||||||
* @param {Y} y The Yjs instance.
|
* @param {Document} [_document=document] The document object (you must define
|
||||||
* @param {DomBinding} binding The DOM binding instance that has the dom filter.
|
* this when calling this method in
|
||||||
* @param {YXmlElement | YXmlFragment } type The type to apply the filter to.
|
* nodejs)
|
||||||
*
|
* @param {Object<key:hookDefinition>} [hooks] Optional property to customize how hooks
|
||||||
* @private
|
* are presented in the DOM
|
||||||
*/
|
* @param {DomBinding} [binding] You should not set this property. This is
|
||||||
function applyFilterOnType (y, binding, type) {
|
* used if DomBinding wants to create a
|
||||||
if (isParentOf(binding.type, type)) {
|
* association to the created DOM type
|
||||||
const nodeName = type.nodeName;
|
* @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
|
||||||
let attributes = new Map();
|
*
|
||||||
if (type.getAttributes !== undefined) {
|
* @public
|
||||||
let attrs = type.getAttributes();
|
*/
|
||||||
for (let key in attrs) {
|
toDom (_document = document, hooks = {}, binding) {
|
||||||
attributes.set(key, attrs[key]);
|
const hook = hooks[this.hookName];
|
||||||
}
|
let dom;
|
||||||
}
|
if (hook !== undefined) {
|
||||||
const filteredAttributes = binding.filter(nodeName, new Map(attributes));
|
dom = hook.createDom(this);
|
||||||
if (filteredAttributes === null) {
|
|
||||||
type._delete(y);
|
|
||||||
} else {
|
} else {
|
||||||
// iterate original attributes
|
dom = document.createElement(this.hookName);
|
||||||
attributes.forEach((value, key) => {
|
|
||||||
// delete all attributes that are not in filteredAttributes
|
|
||||||
if (filteredAttributes.has(key) === false) {
|
|
||||||
type.removeAttribute(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
dom.setAttribute('data-yjs-hook', this.hookName);
|
||||||
|
createAssociation(binding, dom, this);
|
||||||
|
return dom
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Yjs type (YXml) based on the contents of a DOM Element.
|
* Read the next Item in a Decoder and fill this Item with the read data.
|
||||||
*
|
*
|
||||||
* @param {Element|TextNode} element The DOM Element
|
* This is called when data is received from a remote peer.
|
||||||
* @param {?Document} _document Optional. Provide the global document object
|
*
|
||||||
* @param {Hooks} [hooks = {}] Optional. Set of Yjs Hooks
|
* @param {Y} y The Yjs instance that this Item belongs to.
|
||||||
* @param {Filter} [filter=defaultFilter] Optional. Dom element filter
|
* @param {BinaryDecoder} decoder The decoder object to read data from.
|
||||||
* @param {?DomBinding} binding Warning: This property is for internal use only!
|
*
|
||||||
* @return {YXmlElement | YXmlText}
|
* @private
|
||||||
*/
|
*/
|
||||||
function domToType (element, _document = document, hooks = {}, filter = defaultFilter, binding) {
|
_fromBinary (y, decoder) {
|
||||||
let type;
|
const missing = super._fromBinary(y, decoder);
|
||||||
switch (element.nodeType) {
|
this.hookName = decoder.readVarString();
|
||||||
case _document.ELEMENT_NODE:
|
return missing
|
||||||
let hookName = null;
|
|
||||||
let hook;
|
|
||||||
// configure `hookName !== undefined` if element is a hook.
|
|
||||||
if (element.hasAttribute('data-yjs-hook')) {
|
|
||||||
hookName = element.getAttribute('data-yjs-hook');
|
|
||||||
hook = hooks[hookName];
|
|
||||||
if (hook === undefined) {
|
|
||||||
console.error(`Unknown hook "${hookName}". Deleting yjsHook dataset property.`);
|
|
||||||
delete element.removeAttribute('data-yjs-hook');
|
|
||||||
hookName = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hookName === null) {
|
|
||||||
// Not a hook
|
|
||||||
const attrs = filterDomAttributes(element, filter);
|
|
||||||
if (attrs === null) {
|
|
||||||
type = false;
|
|
||||||
} else {
|
|
||||||
type = new YXmlElement(element.nodeName);
|
|
||||||
attrs.forEach((val, key) => {
|
|
||||||
type.setAttribute(key, val);
|
|
||||||
});
|
|
||||||
type.insert(0, domsToTypes(element.childNodes, document, hooks, filter, binding));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Is a hook
|
|
||||||
type = new YXmlHook(hookName);
|
|
||||||
hook.fillType(element, type);
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case _document.TEXT_NODE:
|
|
||||||
type = new YXmlText();
|
|
||||||
type.insert(0, element.nodeValue);
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
throw new Error('Can\'t transform this node type to a YXml type!')
|
|
||||||
}
|
}
|
||||||
createAssociation(binding, element, type);
|
|
||||||
return type
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates items until an undeleted item is found.
|
* Transform the properties of this type to binary and write it to an
|
||||||
*
|
* BinaryEncoder.
|
||||||
* @private
|
*
|
||||||
*/
|
* This is called when this Item is sent to a remote peer.
|
||||||
function iterateUntilUndeleted (item) {
|
*
|
||||||
while (item !== null && item._deleted) {
|
* @param {BinaryEncoder} encoder The encoder to write data to.
|
||||||
item = item._right;
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_toBinary (encoder) {
|
||||||
|
super._toBinary(encoder);
|
||||||
|
encoder.writeVarString(this.hookName);
|
||||||
}
|
}
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an association (the information that a DOM element belongs to a
|
* Integrate this type into the Yjs instance.
|
||||||
* type).
|
*
|
||||||
*
|
* * Save this struct in the os
|
||||||
* @param {DomBinding} domBinding The binding object
|
* * This type is sent to other client
|
||||||
* @param {Element} dom The dom that is to be associated with type
|
* * Observer functions are fired
|
||||||
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
|
*
|
||||||
*
|
* @param {Y} y The Yjs instance
|
||||||
*/
|
*
|
||||||
function removeAssociation (domBinding, dom, type) {
|
* @private
|
||||||
domBinding.domToType.delete(dom);
|
*/
|
||||||
domBinding.typeToDom.delete(type);
|
_integrate (y) {
|
||||||
}
|
if (this.hookName === null) {
|
||||||
|
throw new Error('hookName must be defined!')
|
||||||
/**
|
|
||||||
* Creates an association (the information that a DOM element belongs to a
|
|
||||||
* type).
|
|
||||||
*
|
|
||||||
* @param {DomBinding} domBinding The binding object
|
|
||||||
* @param {Element} dom The dom that is to be associated with type
|
|
||||||
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function createAssociation (domBinding, dom, type) {
|
|
||||||
if (domBinding !== undefined) {
|
|
||||||
domBinding.domToType.set(dom, type);
|
|
||||||
domBinding.typeToDom.set(type, dom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If oldDom is associated with a type, associate newDom with the type and
|
|
||||||
* forget about oldDom. If oldDom is not associated with any type, nothing happens.
|
|
||||||
*
|
|
||||||
* @param {DomBinding} domBinding The binding object
|
|
||||||
* @param {Element} oldDom The existing dom
|
|
||||||
* @param {Element} newDom The new dom object
|
|
||||||
*/
|
|
||||||
function switchAssociation (domBinding, oldDom, newDom) {
|
|
||||||
if (domBinding !== undefined) {
|
|
||||||
const type = domBinding.domToType.get(oldDom);
|
|
||||||
if (type !== undefined) {
|
|
||||||
removeAssociation(domBinding, oldDom, type);
|
|
||||||
createAssociation(domBinding, newDom, type);
|
|
||||||
}
|
}
|
||||||
}
|
super._integrate(y);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert Dom Elements after one of the children of this YXmlFragment.
|
|
||||||
* The Dom elements will be bound to a new YXmlElement and inserted at the
|
|
||||||
* specified position.
|
|
||||||
*
|
|
||||||
* @param {YXmlElement} type The type in which to insert DOM elements.
|
|
||||||
* @param {YXmlElement|null} prev The reference node. New YxmlElements are
|
|
||||||
* inserted after this node. Set null to insert at
|
|
||||||
* the beginning.
|
|
||||||
* @param {Array<Element>} doms The Dom elements to insert.
|
|
||||||
* @param {?Document} _document Optional. Provide the global document object.
|
|
||||||
* @param {DomBinding} binding The dom binding
|
|
||||||
* @return {Array<YXmlElement>} The YxmlElements that are inserted.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function insertDomElementsAfter (type, prev, doms, _document, binding) {
|
|
||||||
const types = domsToTypes(doms, _document, binding.opts.hooks, binding.filter, binding);
|
|
||||||
return type.insertAfter(prev, types)
|
|
||||||
}
|
|
||||||
|
|
||||||
function domsToTypes (doms, _document, hooks, filter, binding) {
|
|
||||||
const types = [];
|
|
||||||
for (let dom of doms) {
|
|
||||||
const t = domToType(dom, _document, hooks, filter, binding);
|
|
||||||
if (t !== false) {
|
|
||||||
types.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return types
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function insertNodeHelper (yxml, prevExpectedNode, child, _document, binding) {
|
|
||||||
let insertedNodes = insertDomElementsAfter(yxml, prevExpectedNode, [child], _document, binding);
|
|
||||||
if (insertedNodes.length > 0) {
|
|
||||||
return insertedNodes[0]
|
|
||||||
} else {
|
|
||||||
return prevExpectedNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove children until `elem` is found.
|
|
||||||
*
|
|
||||||
* @param {Element} parent The parent of `elem` and `currentChild`.
|
|
||||||
* @param {Element} currentChild Start removing elements with `currentChild`. If
|
|
||||||
* `currentChild` is `elem` it won't be removed.
|
|
||||||
* @param {Element|null} elem The elemnt to look for.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function removeDomChildrenUntilElementFound (parent, currentChild, elem) {
|
|
||||||
while (currentChild !== elem) {
|
|
||||||
const del = currentChild;
|
|
||||||
currentChild = currentChild.nextSibling;
|
|
||||||
parent.removeChild(del);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4514,109 +4360,261 @@ class YXmlElement extends YXmlFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YXmlFragment._YXmlElement = YXmlElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You can manage binding to a custom type with YXmlHook.
|
* Check if `parent` is a parent of `child`.
|
||||||
|
*
|
||||||
|
* @param {Type} parent
|
||||||
|
* @param {Type} child
|
||||||
|
* @return {Boolean} Whether `parent` is a parent of `child`.
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
class YXmlHook extends YMap {
|
function isParentOf (parent, child) {
|
||||||
/**
|
child = child._parent;
|
||||||
* @param {String} hookName nodeName of the Dom Node.
|
while (child !== null) {
|
||||||
*/
|
if (child === parent) {
|
||||||
constructor (hookName) {
|
return true
|
||||||
super();
|
|
||||||
this.hookName = null;
|
|
||||||
if (hookName !== undefined) {
|
|
||||||
this.hookName = hookName;
|
|
||||||
}
|
}
|
||||||
|
child = child._parent;
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an Item with the same effect as this Item (without position effect)
|
* Default filter method (does nothing).
|
||||||
*
|
*
|
||||||
* @private
|
* @param {String} nodeName The nodeName of the element
|
||||||
*/
|
* @param {Map} attrs Map of key-value pairs that are attributes of the node.
|
||||||
_copy () {
|
* @return {Map | null} The allowed attributes or null, if the element should be
|
||||||
const struct = super._copy();
|
* filtered.
|
||||||
struct.hookName = this.hookName;
|
*/
|
||||||
return struct
|
function defaultFilter (nodeName, attrs) {
|
||||||
|
// TODO: implement basic filter that filters out dangerous properties!
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function filterDomAttributes (dom, filter) {
|
||||||
|
const attrs = new Map();
|
||||||
|
for (let i = dom.attributes.length - 1; i >= 0; i--) {
|
||||||
|
const attr = dom.attributes[i];
|
||||||
|
attrs.set(attr.name, attr.value);
|
||||||
}
|
}
|
||||||
|
return filter(dom.nodeName, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Dom Element that mirrors this YXmlElement.
|
* Applies a filter on a type.
|
||||||
*
|
*
|
||||||
* @param {Document} [_document=document] The document object (you must define
|
* @param {Y} y The Yjs instance.
|
||||||
* this when calling this method in
|
* @param {DomBinding} binding The DOM binding instance that has the dom filter.
|
||||||
* nodejs)
|
* @param {YXmlElement | YXmlFragment } type The type to apply the filter to.
|
||||||
* @param {Object<key:hookDefinition>} [hooks] Optional property to customize how hooks
|
*
|
||||||
* are presented in the DOM
|
* @private
|
||||||
* @param {DomBinding} [binding] You should not set this property. This is
|
*/
|
||||||
* used if DomBinding wants to create a
|
function applyFilterOnType (y, binding, type) {
|
||||||
* association to the created DOM type
|
if (isParentOf(binding.type, type)) {
|
||||||
* @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
|
const nodeName = type.nodeName;
|
||||||
*
|
let attributes = new Map();
|
||||||
* @public
|
if (type.getAttributes !== undefined) {
|
||||||
*/
|
let attrs = type.getAttributes();
|
||||||
toDom (_document = document, hooks = {}, binding) {
|
for (let key in attrs) {
|
||||||
const hook = hooks[this.hookName];
|
attributes.set(key, attrs[key]);
|
||||||
let dom;
|
}
|
||||||
if (hook !== undefined) {
|
}
|
||||||
dom = hook.createDom(this);
|
const filteredAttributes = binding.filter(nodeName, new Map(attributes));
|
||||||
|
if (filteredAttributes === null) {
|
||||||
|
type._delete(y);
|
||||||
} else {
|
} else {
|
||||||
dom = document.createElement(this.hookName);
|
// iterate original attributes
|
||||||
|
attributes.forEach((value, key) => {
|
||||||
|
// delete all attributes that are not in filteredAttributes
|
||||||
|
if (filteredAttributes.has(key) === false) {
|
||||||
|
type.removeAttribute(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
dom.setAttribute('data-yjs-hook', this.hookName);
|
|
||||||
createAssociation(binding, dom, this);
|
|
||||||
return dom
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the next Item in a Decoder and fill this Item with the read data.
|
* Creates a Yjs type (YXml) based on the contents of a DOM Element.
|
||||||
*
|
*
|
||||||
* This is called when data is received from a remote peer.
|
* @param {Element|TextNode} element The DOM Element
|
||||||
*
|
* @param {?Document} _document Optional. Provide the global document object
|
||||||
* @param {Y} y The Yjs instance that this Item belongs to.
|
* @param {Hooks} [hooks = {}] Optional. Set of Yjs Hooks
|
||||||
* @param {BinaryDecoder} decoder The decoder object to read data from.
|
* @param {Filter} [filter=defaultFilter] Optional. Dom element filter
|
||||||
*
|
* @param {?DomBinding} binding Warning: This property is for internal use only!
|
||||||
* @private
|
* @return {YXmlElement | YXmlText}
|
||||||
*/
|
*/
|
||||||
_fromBinary (y, decoder) {
|
function domToType (element, _document = document, hooks = {}, filter = defaultFilter, binding) {
|
||||||
const missing = super._fromBinary(y, decoder);
|
let type;
|
||||||
this.hookName = decoder.readVarString();
|
switch (element.nodeType) {
|
||||||
return missing
|
case _document.ELEMENT_NODE:
|
||||||
|
let hookName = null;
|
||||||
|
let hook;
|
||||||
|
// configure `hookName !== undefined` if element is a hook.
|
||||||
|
if (element.hasAttribute('data-yjs-hook')) {
|
||||||
|
hookName = element.getAttribute('data-yjs-hook');
|
||||||
|
hook = hooks[hookName];
|
||||||
|
if (hook === undefined) {
|
||||||
|
console.error(`Unknown hook "${hookName}". Deleting yjsHook dataset property.`);
|
||||||
|
delete element.removeAttribute('data-yjs-hook');
|
||||||
|
hookName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hookName === null) {
|
||||||
|
// Not a hook
|
||||||
|
const attrs = filterDomAttributes(element, filter);
|
||||||
|
if (attrs === null) {
|
||||||
|
type = false;
|
||||||
|
} else {
|
||||||
|
type = new YXmlElement(element.nodeName);
|
||||||
|
attrs.forEach((val, key) => {
|
||||||
|
type.setAttribute(key, val);
|
||||||
|
});
|
||||||
|
type.insert(0, domsToTypes(element.childNodes, document, hooks, filter, binding));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Is a hook
|
||||||
|
type = new YXmlHook(hookName);
|
||||||
|
hook.fillType(element, type);
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case _document.TEXT_NODE:
|
||||||
|
type = new YXmlText();
|
||||||
|
type.insert(0, element.nodeValue);
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error('Can\'t transform this node type to a YXml type!')
|
||||||
}
|
}
|
||||||
|
createAssociation(binding, element, type);
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the properties of this type to binary and write it to an
|
* Iterates items until an undeleted item is found.
|
||||||
* BinaryEncoder.
|
*
|
||||||
*
|
* @private
|
||||||
* This is called when this Item is sent to a remote peer.
|
*/
|
||||||
*
|
function iterateUntilUndeleted (item) {
|
||||||
* @param {BinaryEncoder} encoder The encoder to write data to.
|
while (item !== null && item._deleted) {
|
||||||
*
|
item = item._right;
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_toBinary (encoder) {
|
|
||||||
super._toBinary(encoder);
|
|
||||||
encoder.writeVarString(this.hookName);
|
|
||||||
}
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integrate this type into the Yjs instance.
|
* Removes an association (the information that a DOM element belongs to a
|
||||||
*
|
* type).
|
||||||
* * Save this struct in the os
|
*
|
||||||
* * This type is sent to other client
|
* @param {DomBinding} domBinding The binding object
|
||||||
* * Observer functions are fired
|
* @param {Element} dom The dom that is to be associated with type
|
||||||
*
|
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
|
||||||
* @param {Y} y The Yjs instance
|
*
|
||||||
*
|
*/
|
||||||
* @private
|
function removeAssociation (domBinding, dom, type) {
|
||||||
*/
|
domBinding.domToType.delete(dom);
|
||||||
_integrate (y) {
|
domBinding.typeToDom.delete(type);
|
||||||
if (this.hookName === null) {
|
}
|
||||||
throw new Error('hookName must be defined!')
|
|
||||||
|
/**
|
||||||
|
* Creates an association (the information that a DOM element belongs to a
|
||||||
|
* type).
|
||||||
|
*
|
||||||
|
* @param {DomBinding} domBinding The binding object
|
||||||
|
* @param {Element} dom The dom that is to be associated with type
|
||||||
|
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function createAssociation (domBinding, dom, type) {
|
||||||
|
if (domBinding !== undefined) {
|
||||||
|
domBinding.domToType.set(dom, type);
|
||||||
|
domBinding.typeToDom.set(type, dom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If oldDom is associated with a type, associate newDom with the type and
|
||||||
|
* forget about oldDom. If oldDom is not associated with any type, nothing happens.
|
||||||
|
*
|
||||||
|
* @param {DomBinding} domBinding The binding object
|
||||||
|
* @param {Element} oldDom The existing dom
|
||||||
|
* @param {Element} newDom The new dom object
|
||||||
|
*/
|
||||||
|
function switchAssociation (domBinding, oldDom, newDom) {
|
||||||
|
if (domBinding !== undefined) {
|
||||||
|
const type = domBinding.domToType.get(oldDom);
|
||||||
|
if (type !== undefined) {
|
||||||
|
removeAssociation(domBinding, oldDom, type);
|
||||||
|
createAssociation(domBinding, newDom, type);
|
||||||
}
|
}
|
||||||
super._integrate(y);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert Dom Elements after one of the children of this YXmlFragment.
|
||||||
|
* The Dom elements will be bound to a new YXmlElement and inserted at the
|
||||||
|
* specified position.
|
||||||
|
*
|
||||||
|
* @param {YXmlElement} type The type in which to insert DOM elements.
|
||||||
|
* @param {YXmlElement|null} prev The reference node. New YxmlElements are
|
||||||
|
* inserted after this node. Set null to insert at
|
||||||
|
* the beginning.
|
||||||
|
* @param {Array<Element>} doms The Dom elements to insert.
|
||||||
|
* @param {?Document} _document Optional. Provide the global document object.
|
||||||
|
* @param {DomBinding} binding The dom binding
|
||||||
|
* @return {Array<YXmlElement>} The YxmlElements that are inserted.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function insertDomElementsAfter (type, prev, doms, _document, binding) {
|
||||||
|
const types = domsToTypes(doms, _document, binding.opts.hooks, binding.filter, binding);
|
||||||
|
return type.insertAfter(prev, types)
|
||||||
|
}
|
||||||
|
|
||||||
|
function domsToTypes (doms, _document, hooks, filter, binding) {
|
||||||
|
const types = [];
|
||||||
|
for (let dom of doms) {
|
||||||
|
const t = domToType(dom, _document, hooks, filter, binding);
|
||||||
|
if (t !== false) {
|
||||||
|
types.push(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function insertNodeHelper (yxml, prevExpectedNode, child, _document, binding) {
|
||||||
|
let insertedNodes = insertDomElementsAfter(yxml, prevExpectedNode, [child], _document, binding);
|
||||||
|
if (insertedNodes.length > 0) {
|
||||||
|
return insertedNodes[0]
|
||||||
|
} else {
|
||||||
|
return prevExpectedNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove children until `elem` is found.
|
||||||
|
*
|
||||||
|
* @param {Element} parent The parent of `elem` and `currentChild`.
|
||||||
|
* @param {Element} currentChild Start removing elements with `currentChild`. If
|
||||||
|
* `currentChild` is `elem` it won't be removed.
|
||||||
|
* @param {Element|null} elem The elemnt to look for.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function removeDomChildrenUntilElementFound (parent, currentChild, elem) {
|
||||||
|
while (currentChild !== elem) {
|
||||||
|
const del = currentChild;
|
||||||
|
currentChild = currentChild.nextSibling;
|
||||||
|
parent.removeChild(del);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4664,9 +4662,6 @@ class YXmlText extends YText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
YXmlFragment._YXmlElement = YXmlElement;
|
|
||||||
YXmlFragment._YXmlHook = YXmlHook;
|
|
||||||
|
|
||||||
const structs = new Map();
|
const structs = new Map();
|
||||||
const references = new Map();
|
const references = new Map();
|
||||||
|
|
||||||
@@ -5315,7 +5310,6 @@ function typeObserver (events) {
|
|||||||
if (dom !== undefined && dom !== false) {
|
if (dom !== undefined && dom !== false) {
|
||||||
if (yxml.constructor === YXmlText) {
|
if (yxml.constructor === YXmlText) {
|
||||||
dom.nodeValue = yxml.toString();
|
dom.nodeValue = yxml.toString();
|
||||||
// TODO: use hasOwnProperty instead of === undefined check
|
|
||||||
} else if (event.attributesChanged !== undefined) {
|
} else if (event.attributesChanged !== undefined) {
|
||||||
// update attributes
|
// update attributes
|
||||||
event.attributesChanged.forEach(attributeName => {
|
event.attributesChanged.forEach(attributeName => {
|
||||||
@@ -5498,7 +5492,7 @@ function domObserver (mutations, _document) {
|
|||||||
let parent = dom;
|
let parent = dom;
|
||||||
let yParent;
|
let yParent;
|
||||||
do {
|
do {
|
||||||
parent = parent.parentNode;
|
parent = parent.parentElement;
|
||||||
yParent = this.domToType.get(parent);
|
yParent = this.domToType.get(parent);
|
||||||
} while (yParent === undefined && parent !== null)
|
} while (yParent === undefined && parent !== null)
|
||||||
if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
|
if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
|
||||||
@@ -5663,12 +5657,11 @@ class DomBinding extends Binding {
|
|||||||
destroy () {
|
destroy () {
|
||||||
this.domToType = null;
|
this.domToType = null;
|
||||||
this.typeToDom = null;
|
this.typeToDom = null;
|
||||||
this.type.unobserve(this._typeObserver);
|
this.type.unobserveDeep(this._typeObserver);
|
||||||
this._mutationObserver.disconnect();
|
this._mutationObserver.disconnect();
|
||||||
const y = this.type._y;
|
const y = this.type._y;
|
||||||
y.off('beforeTransaction', this._beforeTransactionHandler);
|
y.off('beforeTransaction', this._beforeTransactionHandler);
|
||||||
y.off('beforeObserverCalls', this._beforeObserverCallsHandler);
|
y.off('beforeObserverCalls', this._beforeObserverCallsHandler);
|
||||||
y.off('afterObserverCalls', this._afterObserverCallsHandler);
|
|
||||||
y.off('afterTransaction', this._afterTransactionHandler);
|
y.off('afterTransaction', this._afterTransactionHandler);
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
@@ -5701,7 +5694,7 @@ class DomBinding extends Binding {
|
|||||||
* @param {Object} opts Connector definition
|
* @param {Object} opts Connector definition
|
||||||
* @param {AbstractPersistence} persistence Persistence adapter instance
|
* @param {AbstractPersistence} persistence Persistence adapter instance
|
||||||
*/
|
*/
|
||||||
class Y$1 extends NamedEventHandler {
|
class Y extends NamedEventHandler {
|
||||||
constructor (room, opts, persistence, conf = {}) {
|
constructor (room, opts, persistence, conf = {}) {
|
||||||
super();
|
super();
|
||||||
this.gcEnabled = conf.gc || false;
|
this.gcEnabled = conf.gc || false;
|
||||||
@@ -5736,7 +5729,7 @@ class Y$1 extends NamedEventHandler {
|
|||||||
this.connected = false;
|
this.connected = false;
|
||||||
let initConnection = () => {
|
let initConnection = () => {
|
||||||
if (opts != null) {
|
if (opts != null) {
|
||||||
this.connector = new Y$1[opts.connector.name](this, opts.connector);
|
this.connector = new Y[opts.connector.name](this, opts.connector);
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
this.emit('connectorReady');
|
this.emit('connectorReady');
|
||||||
}
|
}
|
||||||
@@ -5944,11 +5937,11 @@ class Y$1 extends NamedEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Y$1.extend = function extendYjs () {
|
Y.extend = function extendYjs () {
|
||||||
for (var i = 0; i < arguments.length; i++) {
|
for (var i = 0; i < arguments.length; i++) {
|
||||||
var f = arguments[i];
|
var f = arguments[i];
|
||||||
if (typeof f === 'function') {
|
if (typeof f === 'function') {
|
||||||
f(Y$1);
|
f(Y);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Expected a function!')
|
throw new Error('Expected a function!')
|
||||||
}
|
}
|
||||||
@@ -6242,7 +6235,14 @@ function plural(ms, n, name) {
|
|||||||
return Math.ceil(ms / n) + ' ' + name + 's';
|
return Math.ceil(ms / n) + ' ' + name + 's';
|
||||||
}
|
}
|
||||||
|
|
||||||
var debug$1 = createCommonjsModule(function (module, exports) {
|
var ms$1 = /*#__PURE__*/Object.freeze({
|
||||||
|
default: ms,
|
||||||
|
__moduleExports: ms
|
||||||
|
});
|
||||||
|
|
||||||
|
var require$$0 = ( ms$1 && ms ) || ms$1;
|
||||||
|
|
||||||
|
var debug = createCommonjsModule(function (module, exports) {
|
||||||
/**
|
/**
|
||||||
* This is the common logic for both the Node.js and web browser
|
* This is the common logic for both the Node.js and web browser
|
||||||
* implementations of `debug()`.
|
* implementations of `debug()`.
|
||||||
@@ -6255,7 +6255,7 @@ exports.coerce = coerce;
|
|||||||
exports.disable = disable;
|
exports.disable = disable;
|
||||||
exports.enable = enable;
|
exports.enable = enable;
|
||||||
exports.enabled = enabled;
|
exports.enabled = enabled;
|
||||||
exports.humanize = ms;
|
exports.humanize = require$$0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The currently active debug mode names, and names to skip.
|
* The currently active debug mode names, and names to skip.
|
||||||
@@ -6314,8 +6314,8 @@ function createDebug(namespace) {
|
|||||||
|
|
||||||
// set `diff` timestamp
|
// set `diff` timestamp
|
||||||
var curr = +new Date();
|
var curr = +new Date();
|
||||||
var ms$$1 = curr - (prevTime || curr);
|
var ms = curr - (prevTime || curr);
|
||||||
self.diff = ms$$1;
|
self.diff = ms;
|
||||||
self.prev = prevTime;
|
self.prev = prevTime;
|
||||||
self.curr = curr;
|
self.curr = curr;
|
||||||
prevTime = curr;
|
prevTime = curr;
|
||||||
@@ -6445,15 +6445,29 @@ function coerce(val) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
var debug_1 = debug.coerce;
|
||||||
|
var debug_2 = debug.disable;
|
||||||
|
var debug_3 = debug.enable;
|
||||||
|
var debug_4 = debug.enabled;
|
||||||
|
var debug_5 = debug.humanize;
|
||||||
|
var debug_6 = debug.names;
|
||||||
|
var debug_7 = debug.skips;
|
||||||
|
var debug_8 = debug.formatters;
|
||||||
|
|
||||||
var debug_1 = debug$1.coerce;
|
var debug$1 = /*#__PURE__*/Object.freeze({
|
||||||
var debug_2 = debug$1.disable;
|
default: debug,
|
||||||
var debug_3 = debug$1.enable;
|
__moduleExports: debug,
|
||||||
var debug_4 = debug$1.enabled;
|
coerce: debug_1,
|
||||||
var debug_5 = debug$1.humanize;
|
disable: debug_2,
|
||||||
var debug_6 = debug$1.names;
|
enable: debug_3,
|
||||||
var debug_7 = debug$1.skips;
|
enabled: debug_4,
|
||||||
var debug_8 = debug$1.formatters;
|
humanize: debug_5,
|
||||||
|
names: debug_6,
|
||||||
|
skips: debug_7,
|
||||||
|
formatters: debug_8
|
||||||
|
});
|
||||||
|
|
||||||
|
var require$$0$1 = ( debug$1 && debug ) || debug$1;
|
||||||
|
|
||||||
var browser = createCommonjsModule(function (module, exports) {
|
var browser = createCommonjsModule(function (module, exports) {
|
||||||
/**
|
/**
|
||||||
@@ -6462,7 +6476,7 @@ var browser = createCommonjsModule(function (module, exports) {
|
|||||||
* Expose `debug()` as the module.
|
* Expose `debug()` as the module.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports = module.exports = debug$1;
|
exports = module.exports = require$$0$1;
|
||||||
exports.log = log;
|
exports.log = log;
|
||||||
exports.formatArgs = formatArgs;
|
exports.formatArgs = formatArgs;
|
||||||
exports.save = save;
|
exports.save = save;
|
||||||
@@ -6642,7 +6656,6 @@ function localstorage() {
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var browser_1 = browser.log;
|
var browser_1 = browser.log;
|
||||||
var browser_2 = browser.formatArgs;
|
var browser_2 = browser.formatArgs;
|
||||||
var browser_3 = browser.save;
|
var browser_3 = browser.save;
|
||||||
@@ -7189,25 +7202,25 @@ class QuillBinding extends Binding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: The following assignments should be moved to yjs-dist
|
// TODO: The following assignments should be moved to yjs-dist
|
||||||
Y$1.AbstractConnector = AbstractConnector;
|
Y.AbstractConnector = AbstractConnector;
|
||||||
Y$1.AbstractPersistence = AbstractPersistence;
|
Y.AbstractPersistence = AbstractPersistence;
|
||||||
Y$1.Array = YArray;
|
Y.Array = YArray;
|
||||||
Y$1.Map = YMap;
|
Y.Map = YMap;
|
||||||
Y$1.Text = YText;
|
Y.Text = YText;
|
||||||
Y$1.XmlElement = YXmlElement;
|
Y.XmlElement = YXmlElement;
|
||||||
Y$1.XmlFragment = YXmlFragment;
|
Y.XmlFragment = YXmlFragment;
|
||||||
Y$1.XmlText = YXmlText;
|
Y.XmlText = YXmlText;
|
||||||
Y$1.XmlHook = YXmlHook;
|
Y.XmlHook = YXmlHook;
|
||||||
|
|
||||||
Y$1.TextareaBinding = TextareaBinding;
|
Y.TextareaBinding = TextareaBinding;
|
||||||
Y$1.QuillBinding = QuillBinding;
|
Y.QuillBinding = QuillBinding;
|
||||||
Y$1.DomBinding = DomBinding;
|
Y.DomBinding = DomBinding;
|
||||||
|
|
||||||
DomBinding.domToType = domToType;
|
DomBinding.domToType = domToType;
|
||||||
DomBinding.domsToTypes = domsToTypes;
|
DomBinding.domsToTypes = domsToTypes;
|
||||||
DomBinding.switchAssociation = switchAssociation;
|
DomBinding.switchAssociation = switchAssociation;
|
||||||
|
|
||||||
Y$1.utils = {
|
Y.utils = {
|
||||||
BinaryDecoder,
|
BinaryDecoder,
|
||||||
UndoManager,
|
UndoManager,
|
||||||
getRelativePosition,
|
getRelativePosition,
|
||||||
@@ -7218,9 +7231,9 @@ Y$1.utils = {
|
|||||||
fromBinary
|
fromBinary
|
||||||
};
|
};
|
||||||
|
|
||||||
Y$1.debug = browser;
|
Y.debug = browser;
|
||||||
browser.formatters.Y = messageToString;
|
browser.formatters.Y = messageToString;
|
||||||
browser.formatters.y = messageToRoomname;
|
browser.formatters.y = messageToRoomname;
|
||||||
|
|
||||||
module.exports = Y$1;
|
module.exports = Y;
|
||||||
//# sourceMappingURL=y.node.js.map
|
//# sourceMappingURL=y.node.js.map
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user