working on snapshotting and version history
This commit is contained in:
@@ -9,6 +9,8 @@ import * as stringify from '../utils/structStringify.js'
|
||||
import { YEvent } from '../utils/YEvent.js'
|
||||
import { Transaction } from '../utils/Transaction.js' // eslint-disable-line
|
||||
import { Item } from '../structs/Item.js' // eslint-disable-line
|
||||
import { ItemBinary } from '../structs/ItemBinary.js'
|
||||
import { isVisible } from '../utils/snapshot.js'
|
||||
|
||||
/**
|
||||
* Event that describes the changes on a YArray
|
||||
@@ -89,6 +91,7 @@ export class YArray extends Type {
|
||||
* Returns the i-th element from a YArray.
|
||||
*
|
||||
* @param {number} index The index of the element to return from the YArray
|
||||
* @return {any}
|
||||
*/
|
||||
get (index) {
|
||||
let n = this._start
|
||||
@@ -112,10 +115,11 @@ export class YArray extends Type {
|
||||
/**
|
||||
* Transforms this YArray to a JavaScript Array.
|
||||
*
|
||||
* @param {Object} [snapshot]
|
||||
* @return {Array}
|
||||
*/
|
||||
toArray () {
|
||||
return this.map(c => c)
|
||||
toArray (snapshot) {
|
||||
return this.map(c => c, snapshot)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,14 +141,15 @@ export class YArray extends Type {
|
||||
* element of this YArray.
|
||||
*
|
||||
* @param {Function} f Function that produces an element of the new Array
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
* @return {Array} A new array with each element being the result of the
|
||||
* callback function
|
||||
*/
|
||||
map (f) {
|
||||
map (f, snapshot) {
|
||||
const res = []
|
||||
this.forEach((c, i) => {
|
||||
res.push(f(c, i, this))
|
||||
})
|
||||
}, snapshot)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -152,14 +157,17 @@ export class YArray extends Type {
|
||||
* Executes a provided function on once on overy element of this YArray.
|
||||
*
|
||||
* @param {Function} f A function to execute on every element of this YArray.
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
*/
|
||||
forEach (f) {
|
||||
forEach (f, snapshot) {
|
||||
let index = 0
|
||||
let n = this._start
|
||||
while (n !== null) {
|
||||
if (!n._deleted && n._countable) {
|
||||
if (isVisible(n, snapshot) && n._countable) {
|
||||
if (n instanceof Type) {
|
||||
f(n, index++, this)
|
||||
} else if (n.constructor === ItemBinary) {
|
||||
f(n._content, index++, this)
|
||||
} else {
|
||||
const content = n._content
|
||||
const contentLen = content.length
|
||||
@@ -239,7 +247,7 @@ export class YArray extends Type {
|
||||
*
|
||||
* @private
|
||||
* @param {Item} left The element container to use as a reference.
|
||||
* @param {Array} content The Array of content to insert (see {@see insert})
|
||||
* @param {Array<number|string|Object|ArrayBuffer>} content The Array of content to insert (see {@see insert})
|
||||
*/
|
||||
insertAfter (left, content) {
|
||||
this._transact(y => {
|
||||
@@ -276,6 +284,29 @@ export class YArray extends Type {
|
||||
left._right = c
|
||||
}
|
||||
left = c
|
||||
} else if (c.constructor === ArrayBuffer) {
|
||||
if (prevJsonIns !== null) {
|
||||
if (y !== null) {
|
||||
prevJsonIns._integrate(y)
|
||||
}
|
||||
left = prevJsonIns
|
||||
prevJsonIns = null
|
||||
}
|
||||
const itemBinary = new ItemBinary()
|
||||
itemBinary._origin = left
|
||||
itemBinary._left = left
|
||||
itemBinary._right = right
|
||||
itemBinary._right_origin = right
|
||||
itemBinary._parent = this
|
||||
itemBinary._content = c
|
||||
if (y !== null) {
|
||||
itemBinary._integrate(y)
|
||||
} else if (left === null) {
|
||||
this._start = itemBinary
|
||||
} else {
|
||||
left._right = itemBinary
|
||||
}
|
||||
left = itemBinary
|
||||
} else {
|
||||
if (prevJsonIns === null) {
|
||||
prevJsonIns = new ItemJSON()
|
||||
@@ -294,6 +325,8 @@ export class YArray extends Type {
|
||||
prevJsonIns._integrate(y)
|
||||
} else if (prevJsonIns._left === null) {
|
||||
this._start = prevJsonIns
|
||||
} else {
|
||||
left._right = prevJsonIns
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -314,7 +347,7 @@ export class YArray extends Type {
|
||||
* yarray.insert(2, [1, 2])
|
||||
*
|
||||
* @param {number} index The index to insert content at.
|
||||
* @param {Array} content The array of content
|
||||
* @param {Array<number|string|ArrayBuffer|Type>} content The array of content
|
||||
*/
|
||||
insert (index, content) {
|
||||
this._transact(() => {
|
||||
@@ -347,7 +380,7 @@ export class YArray extends Type {
|
||||
/**
|
||||
* Appends content to this YArray.
|
||||
*
|
||||
* @param {Array} content Array of content to append.
|
||||
* @param {Array<number|string|ArrayBuffer|Type>} content Array of content to append.
|
||||
*/
|
||||
push (content) {
|
||||
let n = this._start
|
||||
|
||||
@@ -7,6 +7,8 @@ import { Type } from '../structs/Type.js'
|
||||
import { ItemJSON } from '../structs/ItemJSON.js'
|
||||
import * as stringify from '../utils/structStringify.js'
|
||||
import { YEvent } from '../utils/YEvent.js'
|
||||
import { ItemBinary } from '../structs/ItemBinary.js'
|
||||
import { isVisible } from '../utils/snapshot.js';
|
||||
|
||||
/**
|
||||
* Event that describes the changes on a YMap.
|
||||
@@ -53,6 +55,8 @@ export class YMap extends Type {
|
||||
} else {
|
||||
res = item.toString()
|
||||
}
|
||||
} else if (item.constructor === ItemBinary) {
|
||||
res = item._content
|
||||
} else {
|
||||
res = item._content[0]
|
||||
}
|
||||
@@ -65,14 +69,23 @@ export class YMap extends Type {
|
||||
/**
|
||||
* Returns the keys for each element in the YMap Type.
|
||||
*
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
* @return {Array}
|
||||
*/
|
||||
keys () {
|
||||
keys (snapshot) {
|
||||
// TODO: Should return either Iterator or Set!
|
||||
let keys = []
|
||||
for (let [key, value] of this._map) {
|
||||
if (!value._deleted) {
|
||||
keys.push(key)
|
||||
if (snapshot === undefined) {
|
||||
for (let [key, value] of this._map) {
|
||||
if (value._deleted) {
|
||||
keys.push(key)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let key in this._map) {
|
||||
if (this.has(key, snapshot)) {
|
||||
keys.push(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
return keys
|
||||
@@ -96,7 +109,7 @@ export class YMap extends Type {
|
||||
* Adds or updates an element with a specified key and value.
|
||||
*
|
||||
* @param {string} key The key of the element to add to this YMap
|
||||
* @param {Object | string | number | Type} value The value of the element to add
|
||||
* @param {Object | string | number | Type | ArrayBuffer } value The value of the element to add
|
||||
*/
|
||||
set (key, value) {
|
||||
this._transact(y => {
|
||||
@@ -120,6 +133,9 @@ export class YMap extends Type {
|
||||
value = v
|
||||
} else if (value instanceof Item) {
|
||||
v = value
|
||||
} else if (value.constructor === ArrayBuffer) {
|
||||
v = new ItemBinary()
|
||||
v._content = value
|
||||
} else {
|
||||
v = new ItemJSON()
|
||||
v._content = [value]
|
||||
@@ -141,16 +157,27 @@ export class YMap extends Type {
|
||||
* Returns a specified element from this YMap.
|
||||
*
|
||||
* @param {string} key The key of the element to return.
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
*/
|
||||
get (key) {
|
||||
get (key, snapshot) {
|
||||
let v = this._map.get(key)
|
||||
if (v === undefined || v._deleted) {
|
||||
if (v === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (v instanceof Type) {
|
||||
return v
|
||||
} else {
|
||||
return v._content[v._content.length - 1]
|
||||
if (snapshot !== undefined) {
|
||||
// iterate until found element that exists
|
||||
while (!snapshot.sm.has(v._id.user) || v._id.clock >= snapshot.sm.get(v._id.user)) {
|
||||
v = v._right
|
||||
}
|
||||
}
|
||||
if (isVisible(v, snapshot)) {
|
||||
if (v instanceof Type) {
|
||||
return v
|
||||
} else if (v.constructor === ItemBinary) {
|
||||
return v._content
|
||||
} else {
|
||||
return v._content[v._content.length - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,14 +185,20 @@ export class YMap extends Type {
|
||||
* Returns a boolean indicating whether the specified key exists or not.
|
||||
*
|
||||
* @param {string} key The key to test.
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
*/
|
||||
has (key) {
|
||||
has (key, snapshot) {
|
||||
let v = this._map.get(key)
|
||||
if (v === undefined || v._deleted) {
|
||||
if (v === undefined) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
if (snapshot !== undefined) {
|
||||
// iterate until found element that exists
|
||||
while (!snapshot.sm.has(v._id.user) || v._id.clock >= snapshot.sm.get(v._id.user)) {
|
||||
v = v._right
|
||||
}
|
||||
}
|
||||
return isVisible(v, snapshot)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ItemString } from '../structs/ItemString.js'
|
||||
import { ItemFormat } from '../structs/ItemFormat.js'
|
||||
import * as stringify from '../utils/structStringify.js'
|
||||
import { YArrayEvent, YArray } from './YArray.js'
|
||||
import { isVisible } from '../utils/snapshot.js'
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -570,11 +571,12 @@ export class YText extends YArray {
|
||||
/**
|
||||
* Returns the Delta representation of this YText type.
|
||||
*
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
* @return {Delta} The Delta representation of this type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
toDelta () {
|
||||
toDelta (snapshot) {
|
||||
let ops = []
|
||||
let currentAttributes = new Map()
|
||||
let str = ''
|
||||
@@ -600,7 +602,7 @@ export class YText extends YArray {
|
||||
}
|
||||
}
|
||||
while (n !== null) {
|
||||
if (!n._deleted) {
|
||||
if (isVisible(n, snapshot)) {
|
||||
switch (n.constructor) {
|
||||
case ItemString:
|
||||
str += n._content
|
||||
|
||||
@@ -300,26 +300,34 @@ export class YXmlElement extends YXmlFragment {
|
||||
*
|
||||
* @param {String} attributeName The attribute name that identifies the
|
||||
* queried value.
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
* @return {String} The queried attribute value.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
getAttribute (attributeName) {
|
||||
return YMap.prototype.get.call(this, attributeName)
|
||||
getAttribute (attributeName, snapshot) {
|
||||
return YMap.prototype.get.call(this, attributeName, snapshot)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all attribute name/value pairs in a JSON Object.
|
||||
*
|
||||
* @param {import('../protocols/history.js').HistorySnapshot} [snapshot]
|
||||
* @return {Object} A JSON Object that describes the attributes.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
getAttributes () {
|
||||
getAttributes (snapshot) {
|
||||
const obj = {}
|
||||
for (let [key, value] of this._map) {
|
||||
if (!value._deleted) {
|
||||
obj[key] = value._content[0]
|
||||
if (snapshot === undefined) {
|
||||
for (let [key, value] of this._map) {
|
||||
if (!value._deleted) {
|
||||
obj[key] = value._content[0]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let key in this._map) {
|
||||
return YMap.prototype.get.call(this, key, snapshot)
|
||||
}
|
||||
}
|
||||
return obj
|
||||
|
||||
Reference in New Issue
Block a user