Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c67428d715 | ||
|
|
45a9af96af | ||
|
|
249c4f9c45 | ||
|
|
cdc7d3ffe6 | ||
|
|
ac6a0e7667 | ||
|
|
12881e2be7 | ||
|
|
77958da657 | ||
|
|
8a8a60efde | ||
|
|
7a1d648e79 | ||
|
|
3af420e790 |
@@ -698,7 +698,7 @@ Y.applyUpdate(ydoc2, state1)
|
||||
This example shows how to sync two clients with the minimal amount of exchanged
|
||||
data by computing only the differences using the state vector of the remote
|
||||
client. Syncing clients using the state vector requires another roundtrip, but
|
||||
can safe a lot of bandwidth.
|
||||
can save a lot of bandwidth.
|
||||
|
||||
```js
|
||||
const stateVector1 = Y.encodeStateVector(ydoc1)
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yjs",
|
||||
"version": "13.5.2",
|
||||
"version": "13.5.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"name": "yjs",
|
||||
"version": "13.5.2",
|
||||
"version": "13.5.4",
|
||||
"description": "Shared Editing Library",
|
||||
"main": "./dist/yjs.cjs",
|
||||
"module": "./dist/yjs.mjs",
|
||||
"unpkg": "./dist/yjs.mjs",
|
||||
"types": "./dist/src/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"funding": {
|
||||
@@ -31,7 +30,8 @@
|
||||
"require": "./dist/yjs.cjs"
|
||||
},
|
||||
"./src/index.js": "./src/index.js",
|
||||
"./tests/testHelper.js": "./tests/testHelper.js"
|
||||
"./tests/testHelper.js": "./tests/testHelper.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"dist/yjs.*",
|
||||
|
||||
@@ -502,14 +502,6 @@ const deleteText = (transaction, currPos, length) => {
|
||||
* @typedef {Object} TextAttributes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} DeltaItem
|
||||
* @property {number|undefined} DeltaItem.delete
|
||||
* @property {number|undefined} DeltaItem.retain
|
||||
* @property {string|undefined} DeltaItem.insert
|
||||
* @property {Object<string,any>} DeltaItem.attributes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Event that describes the changes on a YText type.
|
||||
*/
|
||||
@@ -521,10 +513,6 @@ export class YTextEvent extends YEvent {
|
||||
*/
|
||||
constructor (ytext, transaction, subs) {
|
||||
super(ytext, transaction)
|
||||
/**
|
||||
* @type {Array<DeltaItem>|null}
|
||||
*/
|
||||
this._delta = null
|
||||
/**
|
||||
* Whether the children changed.
|
||||
* @type {Boolean}
|
||||
@@ -545,20 +533,41 @@ export class YTextEvent extends YEvent {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert?:Array<any>|string, delete?:number, retain?:number}>}}
|
||||
*/
|
||||
get changes () {
|
||||
if (this._changes === null) {
|
||||
/**
|
||||
* @type {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert?:Array<any>|string, delete?:number, retain?:number}>}}
|
||||
*/
|
||||
const changes = {
|
||||
keys: this.keys,
|
||||
delta: this.delta,
|
||||
added: new Set(),
|
||||
deleted: new Set()
|
||||
}
|
||||
this._changes = changes
|
||||
}
|
||||
return /** @type {any} */ (this._changes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the changes in the delta format.
|
||||
* A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document.
|
||||
*
|
||||
* @type {Array<DeltaItem>}
|
||||
* @type {Array<{insert?:string, delete?:number, retain?:number, attributes?: Object<string,any>}>}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
get delta () {
|
||||
if (this._delta === null) {
|
||||
const y = /** @type {Doc} */ (this.target.doc)
|
||||
this._delta = []
|
||||
/**
|
||||
* @type {Array<{insert?:string, delete?:number, retain?:number, attributes?: Object<string,any>}>}
|
||||
*/
|
||||
const delta = []
|
||||
transact(y, transaction => {
|
||||
const delta = /** @type {Array<DeltaItem>} */ (this._delta)
|
||||
const currentAttributes = new Map() // saves all current attributes for insert
|
||||
const oldAttributes = new Map()
|
||||
let item = this.target._start
|
||||
@@ -728,8 +737,9 @@ export class YTextEvent extends YEvent {
|
||||
}
|
||||
}
|
||||
})
|
||||
this._delta = delta
|
||||
}
|
||||
return this._delta
|
||||
return /** @type {any} */ (this._delta)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ export class YXmlTreeWalker {
|
||||
* @type {Item|null}
|
||||
*/
|
||||
let n = this._currentNode
|
||||
let type = /** @type {any} */ (n.content).type
|
||||
let type = n && n.content && /** @type {any} */ (n.content).type
|
||||
if (n !== null && (!this._firstCall || n.deleted || !this._filter(type))) { // if first call, we check if we can use the first item
|
||||
do {
|
||||
type = /** @type {any} */ (n.content).type
|
||||
|
||||
@@ -35,6 +35,14 @@ export class YEvent {
|
||||
* @type {Object|null}
|
||||
*/
|
||||
this._changes = null
|
||||
/**
|
||||
* @type {null | Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
|
||||
*/
|
||||
this._keys = null
|
||||
/**
|
||||
* @type {null | Array<{ insert?: string | Array<any>, retain?: number, delete?: number, attributes?: Object<string, any> }>}
|
||||
*/
|
||||
this._delta = null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +75,66 @@ export class YEvent {
|
||||
return isDeleted(this.transaction.deleteSet, struct.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Map<string, { action: 'add' | 'update' | 'delete', oldValue: any, newValue: any }>}
|
||||
*/
|
||||
get keys () {
|
||||
if (this._keys === null) {
|
||||
const keys = new Map()
|
||||
const target = this.target
|
||||
const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target))
|
||||
changed.forEach(key => {
|
||||
if (key !== null) {
|
||||
const item = /** @type {Item} */ (target._map.get(key))
|
||||
/**
|
||||
* @type {'delete' | 'add' | 'update'}
|
||||
*/
|
||||
let action
|
||||
let oldValue
|
||||
if (this.adds(item)) {
|
||||
let prev = item.left
|
||||
while (prev !== null && this.adds(prev)) {
|
||||
prev = prev.left
|
||||
}
|
||||
if (this.deletes(item)) {
|
||||
if (prev !== null && this.deletes(prev)) {
|
||||
action = 'delete'
|
||||
oldValue = array.last(prev.content.getContent())
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (prev !== null && this.deletes(prev)) {
|
||||
action = 'update'
|
||||
oldValue = array.last(prev.content.getContent())
|
||||
} else {
|
||||
action = 'add'
|
||||
oldValue = undefined
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.deletes(item)) {
|
||||
action = 'delete'
|
||||
oldValue = array.last(/** @type {Item} */ item.content.getContent())
|
||||
} else {
|
||||
return // nop
|
||||
}
|
||||
}
|
||||
keys.set(key, { action, oldValue })
|
||||
}
|
||||
})
|
||||
this._keys = keys
|
||||
}
|
||||
return this._keys
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Array<{insert?: string | Array<any>, retain?: number, delete?: number, attributes?: Object<string, any>}>}
|
||||
*/
|
||||
get delta () {
|
||||
return this.changes.delta
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a struct is added by this event.
|
||||
*
|
||||
@@ -80,7 +148,7 @@ export class YEvent {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert:Array<any>}|{delete:number}|{retain:number}>}}
|
||||
* @type {{added:Set<Item>,deleted:Set<Item>,keys:Map<string,{action:'add'|'update'|'delete',oldValue:any}>,delta:Array<{insert?:Array<any>|string, delete?:number, retain?:number}>}}
|
||||
*/
|
||||
get changes () {
|
||||
let changes = this._changes
|
||||
@@ -92,12 +160,11 @@ export class YEvent {
|
||||
* @type {Array<{insert:Array<any>}|{delete:number}|{retain:number}>}
|
||||
*/
|
||||
const delta = []
|
||||
/**
|
||||
* @type {Map<string,{ action: 'add' | 'update' | 'delete', oldValue: any}>}
|
||||
*/
|
||||
const keys = new Map()
|
||||
changes = {
|
||||
added, deleted, delta, keys
|
||||
added,
|
||||
deleted,
|
||||
delta,
|
||||
keys: this.keys
|
||||
}
|
||||
const changed = /** @type Set<string|null> */ (this.transaction.changed.get(target))
|
||||
if (changed.has(null)) {
|
||||
@@ -141,46 +208,6 @@ export class YEvent {
|
||||
packOp()
|
||||
}
|
||||
}
|
||||
changed.forEach(key => {
|
||||
if (key !== null) {
|
||||
const item = /** @type {Item} */ (target._map.get(key))
|
||||
/**
|
||||
* @type {'delete' | 'add' | 'update'}
|
||||
*/
|
||||
let action
|
||||
let oldValue
|
||||
if (this.adds(item)) {
|
||||
let prev = item.left
|
||||
while (prev !== null && this.adds(prev)) {
|
||||
prev = prev.left
|
||||
}
|
||||
if (this.deletes(item)) {
|
||||
if (prev !== null && this.deletes(prev)) {
|
||||
action = 'delete'
|
||||
oldValue = array.last(prev.content.getContent())
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (prev !== null && this.deletes(prev)) {
|
||||
action = 'update'
|
||||
oldValue = array.last(prev.content.getContent())
|
||||
} else {
|
||||
action = 'add'
|
||||
oldValue = undefined
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.deletes(item)) {
|
||||
action = 'delete'
|
||||
oldValue = array.last(/** @type {Item} */ item.content.getContent())
|
||||
} else {
|
||||
return // nop
|
||||
}
|
||||
}
|
||||
keys.set(key, { action, oldValue })
|
||||
}
|
||||
})
|
||||
this._changes = changes
|
||||
}
|
||||
return /** @type {any} */ (changes)
|
||||
|
||||
Reference in New Issue
Block a user