Merge remote-tracking branch 'origin' into y-richtext-rewrite

This commit is contained in:
Kevin Jahns 2018-02-26 02:19:08 +01:00
commit 250050e83b
11 changed files with 95 additions and 78 deletions

View File

@ -18,7 +18,7 @@ window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
}) })
document.onkeydown = function interceptUndoRedo (e) { document.onkeydown = function interceptUndoRedo (e) {
if (e.keyCode === 90 && e.metaKey) { if (e.keyCode === 90 && (e.metaKey || e.ctrlKey)) {
if (!e.shiftKey) { if (!e.shiftKey) {
window.undoManager.undo() window.undoManager.undo()
} else { } else {

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-50", "version": "13.0.0-53",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "yjs", "name": "yjs",
"version": "13.0.0-50", "version": "13.0.0-53",
"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",

View File

@ -4,8 +4,10 @@ import { readDeleteSet, writeDeleteSet } from './deleteSet.js'
import BinaryEncoder from '../Binary/Encoder.js' import BinaryEncoder from '../Binary/Encoder.js'
export function fromBinary (y, decoder) { export function fromBinary (y, decoder) {
integrateRemoteStructs(y, decoder) y.transact(function () {
readDeleteSet(y, decoder) integrateRemoteStructs(y, decoder)
readDeleteSet(y, decoder)
})
} }
export function toBinary (y) { export function toBinary (y) {

View File

@ -56,22 +56,56 @@ export default class Item {
this._parent = null this._parent = null
this._parentSub = null this._parentSub = null
this._deleted = false this._deleted = false
this._redone = null
} }
/** /**
* Copy the effect of struct * Create a operation with the same effect (without position effect)
*/ */
_copy (undeleteChildren, copyPosition) { _copy () {
let struct = new this.constructor() return new this.constructor()
if (copyPosition) { }
struct._origin = this._left /**
struct._left = this._left * Redo the effect of this operation.
struct._right = this */
struct._right_origin = this _redo (y) {
struct._parent = this._parent if (this._redone !== null) {
struct._parentSub = this._parentSub return this._redone
} }
let struct = this._copy()
let left = this._left
let right = this
let parent = this._parent
// make sure that parent is redone
if (parent._deleted === true && parent._redone === null) {
parent._redo(y)
}
if (parent._redone !== null) {
parent = parent._redone
// find next cloned items
while (left !== null && left._redone === null) {
left = left._left
}
if (left !== null) {
left = left._redone
}
while (right !== null && right._redone === null) {
right = right._right
}
if (right !== null) {
right = right._redone
}
}
struct._origin = left
struct._left = left
struct._right = right
struct._right_origin = right
struct._parent = parent
struct._parentSub = this._parentSub
struct._integrate(y)
this._redone = struct
return struct return struct
} }
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)
} }
@ -104,11 +138,15 @@ export default class Item {
if (!this._deleted) { if (!this._deleted) {
this._deleted = true this._deleted = true
y.ds.markDeleted(this._id, this._length) y.ds.markDeleted(this._id, this._length)
let del = new Delete()
del._targetID = this._id
del._length = this._length
if (createDelete) { if (createDelete) {
let del = new Delete() // broadcast and persists Delete
del._targetID = this._id
del._length = this._length
del._integrate(y, true) del._integrate(y, true)
} else if (y.persistence !== null) {
// only persist Delete
y.persistence.saveStruct(y, del)
} }
transactionTypeChanged(y, this._parent, this._parentSub) transactionTypeChanged(y, this._parent, this._parentSub)
y._transaction.deletedStructs.add(this) y._transaction.deletedStructs.add(this)

View File

@ -6,8 +6,8 @@ export default class ItemJSON extends Item {
super() super()
this._content = null this._content = null
} }
_copy (undeleteChildren, copyPosition) { _copy () {
let struct = super._copy(undeleteChildren, copyPosition) let struct = super._copy()
struct._content = this._content struct._content = this._content
return struct return struct
} }

View File

@ -6,8 +6,8 @@ export default class ItemString extends Item {
super() super()
this._content = null this._content = null
} }
_copy (undeleteChildren, copyPosition) { _copy () {
let struct = super._copy(undeleteChildren, copyPosition) let struct = super._copy()
struct._content = this._content struct._content = this._content
return struct return struct
} }

View File

@ -79,40 +79,6 @@ export default class Type extends Item {
type = type._parent type = type._parent
} }
} }
_copy (undeleteChildren, copyPosition) {
let copy = super._copy(undeleteChildren, copyPosition)
let map = new Map()
copy._map = map
for (let [key, value] of this._map) {
if (undeleteChildren.has(value) || !value.deleted) {
let _item = value._copy(undeleteChildren, false)
_item._parent = copy
_item._parentSub = key
map.set(key, _item)
}
}
let prevUndeleted = null
copy._start = null
let item = this._start
while (item !== null) {
if (undeleteChildren.has(item) || !item.deleted) {
let _item = item._copy(undeleteChildren, false)
_item._left = prevUndeleted
_item._origin = prevUndeleted
_item._right = null
_item._right_origin = null
_item._parent = copy
if (prevUndeleted === null) {
copy._start = _item
} else {
prevUndeleted._right = _item
}
prevUndeleted = _item
}
item = item._right
}
return copy
}
_transact (f) { _transact (f) {
const y = this._y const y = this._y
if (y !== null) { if (y !== null) {

View File

@ -20,8 +20,8 @@ export default class YXmlElement extends YXmlFragment {
this._domFilter = arg2 this._domFilter = arg2
} }
} }
_copy (undeleteChildren, copyPosition) { _copy () {
let struct = super._copy(undeleteChildren, copyPosition) let struct = super._copy()
struct.nodeName = this.nodeName struct.nodeName = this.nodeName
return struct return struct
} }
@ -36,7 +36,8 @@ export default class YXmlElement extends YXmlFragment {
let attributes = new Map() let attributes = new Map()
for (let i = 0; i < dom.attributes.length; i++) { for (let i = 0; i < dom.attributes.length; i++) {
let attr = dom.attributes[i] let attr = dom.attributes[i]
attributes.set(attr.name, attr.value) // get attribute via getAttribute for custom element support (some write something different in attr.value)
attributes.set(attr.name, dom.getAttribute(attr.name))
} }
attributes = this._domFilter(dom, attributes) attributes = this._domFilter(dom, attributes)
attributes.forEach((value, name) => { attributes.forEach((value, name) => {

View File

@ -14,8 +14,8 @@ export default class YXmlHook extends YMap {
getHook(hookName).fillType(dom, this) getHook(hookName).fillType(dom, this)
} }
} }
_copy (undeleteChildren, copyPosition) { _copy () {
const struct = super._copy(undeleteChildren, copyPosition) const struct = super._copy()
struct.hookName = this.hookName struct.hookName = this.hookName
return struct return struct
} }

View File

@ -4,11 +4,12 @@ class ReverseOperation {
constructor (y, transaction) { constructor (y, transaction) {
this.created = new Date() this.created = new Date()
const beforeState = transaction.beforeState const beforeState = transaction.beforeState
this.toState = new ID(y.userID, y.ss.getState(y.userID) - 1)
if (beforeState.has(y.userID)) { if (beforeState.has(y.userID)) {
this.toState = new ID(y.userID, y.ss.getState(y.userID) - 1)
this.fromState = new ID(y.userID, beforeState.get(y.userID)) this.fromState = new ID(y.userID, beforeState.get(y.userID))
} else { } else {
this.fromState = this.toState this.toState = null
this.fromState = null
} }
this.deletedStructs = transaction.deletedStructs this.deletedStructs = transaction.deletedStructs
} }
@ -30,28 +31,32 @@ function applyReverseOperation (y, scope, reverseBuffer) {
while (!performedUndo && reverseBuffer.length > 0) { while (!performedUndo && reverseBuffer.length > 0) {
let undoOp = reverseBuffer.pop() let undoOp = reverseBuffer.pop()
// make sure that it is possible to iterate {from}-{to} // make sure that it is possible to iterate {from}-{to}
y.os.getItemCleanStart(undoOp.fromState) if (undoOp.fromState !== null) {
y.os.getItemCleanEnd(undoOp.toState) y.os.getItemCleanStart(undoOp.fromState)
y.os.iterate(undoOp.fromState, undoOp.toState, op => { y.os.getItemCleanEnd(undoOp.toState)
if (!op._deleted && isStructInScope(y, op, scope)) { y.os.iterate(undoOp.fromState, undoOp.toState, op => {
performedUndo = true while (op._deleted && op._redone !== null) {
op._delete(y) op = op._redone
} }
}) if (op._deleted === false && isStructInScope(y, op, scope)) {
performedUndo = true
op._delete(y)
}
})
}
for (let op of undoOp.deletedStructs) { for (let op of undoOp.deletedStructs) {
if ( if (
isStructInScope(y, op, scope) && isStructInScope(y, op, scope) &&
op._parent !== y && op._parent !== y &&
!op._parent._deleted &&
( (
op._parent._id.user !== y.userID || op._id.user !== y.userID ||
op._parent._id.clock < undoOp.fromState.clock || undoOp.fromState === null ||
op._parent._id.clock > undoOp.fromState.clock op._id.clock < undoOp.fromState.clock ||
op._id.clock > undoOp.toState.clock
) )
) { ) {
performedUndo = true performedUndo = true
op = op._copy(undoOp.deletedStructs, true) op._redo(y)
op._integrate(y)
} }
} }
} }
@ -77,7 +82,12 @@ export default class UndoManager {
let lastUndoOp = this._undoBuffer.length > 0 ? this._undoBuffer[this._undoBuffer.length - 1] : null let lastUndoOp = this._undoBuffer.length > 0 ? this._undoBuffer[this._undoBuffer.length - 1] : null
if (lastUndoOp !== null && reverseOperation.created - lastUndoOp.created <= options.captureTimeout) { if (lastUndoOp !== null && reverseOperation.created - lastUndoOp.created <= options.captureTimeout) {
lastUndoOp.created = reverseOperation.created lastUndoOp.created = reverseOperation.created
lastUndoOp.toState = reverseOperation.toState if (reverseOperation.toState !== null) {
lastUndoOp.toState = reverseOperation.toState
if (lastUndoOp.fromState === null) {
lastUndoOp.fromState = reverseOperation.fromState
}
}
reverseOperation.deletedStructs.forEach(lastUndoOp.deletedStructs.add, lastUndoOp.deletedStructs) reverseOperation.deletedStructs.forEach(lastUndoOp.deletedStructs.add, lastUndoOp.deletedStructs)
} else { } else {
this._undoBuffer.push(reverseOperation) this._undoBuffer.push(reverseOperation)