Compare commits
10 Commits
v13.0.0-17
...
v13.0.0-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5844c810a2 | ||
|
|
725273167e | ||
|
|
581264c5e3 | ||
|
|
be537c9f8c | ||
|
|
4028eee39d | ||
|
|
0e3e561ec7 | ||
|
|
7df46cb731 | ||
|
|
40fb16ef32 | ||
|
|
ada5d36cd5 | ||
|
|
f537a43e29 |
@@ -7,8 +7,7 @@ Y({
|
|||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
// url: 'http://127.0.0.1:1234',
|
url: 'http://127.0.0.1:1234',
|
||||||
url: 'http://192.168.178.81:1234',
|
|
||||||
room: 'html-editor-example6'
|
room: 'html-editor-example6'
|
||||||
},
|
},
|
||||||
share: {
|
share: {
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
<textarea style="width:80%;" rows=40 id="textfield" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
|
<textarea style="width:80%;" rows=40 id="textfield" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
|
||||||
<script src="../../y.js"></script>
|
<script src="../../y.js"></script>
|
||||||
<script src="../../../y-array/y-array.js"></script>
|
<script src="../../../y-array/y-array.js"></script>
|
||||||
<script src="../../../y-text/dist/y-text.js"></script>
|
<script src="../../../y-text/y-text.js"></script>
|
||||||
<script src="../../../y-memory/y-memory.js"></script>
|
|
||||||
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
<script src="../../../y-websockets-client/y-websockets-client.js"></script>
|
||||||
<script src="./index.js"></script>
|
<script src="./index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
/* global Y */
|
/* global Y */
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
let search = new URLSearchParams(location.search)
|
|
||||||
|
|
||||||
// initialize a shared object. This function call returns a promise!
|
// initialize a shared object. This function call returns a promise!
|
||||||
Y({
|
Y({
|
||||||
db: {
|
db: {
|
||||||
@@ -10,10 +7,9 @@ Y({
|
|||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
room: 'Textarea-example',
|
room: 'Textarea-example2',
|
||||||
// url: '//localhost:1234',
|
// url: '//localhost:1234',
|
||||||
url: 'https://yjs-v13.herokuapp.com/'
|
url: 'https://yjs-v13.herokuapp.com/'
|
||||||
// options: { transports: ['websocket'], upgrade: false }
|
|
||||||
},
|
},
|
||||||
share: {
|
share: {
|
||||||
textarea: 'Text'
|
textarea: 'Text'
|
||||||
@@ -24,7 +20,4 @@ Y({
|
|||||||
|
|
||||||
// bind the textarea to a shared text element
|
// bind the textarea to a shared text element
|
||||||
y.share.textarea.bind(document.getElementById('textfield'))
|
y.share.textarea.bind(document.getElementById('textfield'))
|
||||||
// thats it..
|
|
||||||
}).catch(() => {
|
|
||||||
console.log('Something went wrong while creating the instance..')
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-17",
|
"version": "13.0.0-20",
|
||||||
"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",
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
if (opts.generateUserId !== false) {
|
if (opts.generateUserId !== false) {
|
||||||
this.setUserId(Y.utils.generateUserId())
|
this.setUserId(Y.utils.generateUserId())
|
||||||
}
|
}
|
||||||
|
if (opts.maxBufferLength == null) {
|
||||||
|
this.maxBufferLength = -1
|
||||||
|
} else {
|
||||||
|
this.maxBufferLength = opts.maxBufferLength
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnect () {
|
reconnect () {
|
||||||
@@ -197,14 +202,19 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
encoder.writeVarString(self.opts.room)
|
encoder.writeVarString(self.opts.room)
|
||||||
encoder.writeVarString('update')
|
encoder.writeVarString('update')
|
||||||
let ops = self.broadcastOpBuffer
|
let ops = self.broadcastOpBuffer
|
||||||
self.broadcastOpBuffer = []
|
|
||||||
let length = ops.length
|
let length = ops.length
|
||||||
encoder.writeUint32(length)
|
let encoderPosLen = encoder.pos
|
||||||
for (var i = 0; i < length; i++) {
|
encoder.writeUint32(0)
|
||||||
|
for (var i = 0; i < length && (self.maxBufferLength < 0 || encoder.length < self.maxBufferLength); i++) {
|
||||||
let op = ops[i]
|
let op = ops[i]
|
||||||
Y.Struct[op.struct].binaryEncode(encoder, op)
|
Y.Struct[op.struct].binaryEncode(encoder, op)
|
||||||
}
|
}
|
||||||
|
encoder.setUint32(encoderPosLen, i)
|
||||||
|
self.broadcastOpBuffer = ops.slice(i)
|
||||||
self.broadcast(encoder.createBuffer())
|
self.broadcast(encoder.createBuffer())
|
||||||
|
if (i !== length) {
|
||||||
|
setTimeout(broadcastOperations, 100)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.broadcastOpBuffer.length === 0) {
|
if (this.broadcastOpBuffer.length === 0) {
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ export class BinaryEncoder {
|
|||||||
this.data = []
|
this.data = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get length () {
|
||||||
|
return this.data.length
|
||||||
|
}
|
||||||
|
|
||||||
get pos () {
|
get pos () {
|
||||||
return this.data.length
|
return this.data.length
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/Utils.js
51
src/Utils.js
@@ -49,6 +49,51 @@ export default function Utils (Y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Y.utils.getRelativePosition = function (type, offset) {
|
||||||
|
if (type == null) {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
if (type._content.length <= offset) {
|
||||||
|
return ['endof', type._model[0], type._model[1]]
|
||||||
|
} else {
|
||||||
|
return type._content[offset].id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Y.utils.fromRelativePosition = function (y, id) {
|
||||||
|
var offset = 0
|
||||||
|
var op
|
||||||
|
if (id[0] === 'endof') {
|
||||||
|
id = y.db.os.find(id.slice(1)).end
|
||||||
|
op = y.db.os.findNodeWithUpperBound(id).val
|
||||||
|
if (!op.deleted) {
|
||||||
|
offset = op.content != null ? op.content.length : 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
op = y.db.os.findNodeWithUpperBound(id).val
|
||||||
|
if (!op.deleted) {
|
||||||
|
offset = id[1] - op.id[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = y.db.getType(op.parent)
|
||||||
|
if (type == null || y.db.os.find(op.parent).deleted) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
while (op.left != null) {
|
||||||
|
op = y.db.os.findNodeWithUpperBound(op.left).val
|
||||||
|
if (!op.deleted) {
|
||||||
|
offset += op.content != null ? op.content.length : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
offset: offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NamedEventHandler {
|
class NamedEventHandler {
|
||||||
constructor () {
|
constructor () {
|
||||||
this._eventListener = {}
|
this._eventListener = {}
|
||||||
@@ -67,7 +112,11 @@ export default function Utils (Y) {
|
|||||||
this._eventListener[name] = listener.filter(e => e !== f)
|
this._eventListener[name] = listener.filter(e => e !== f)
|
||||||
}
|
}
|
||||||
emit (name, value) {
|
emit (name, value) {
|
||||||
(this._eventListener[name] || []).forEach(l => l(value))
|
let listener = this._eventListener[name] || []
|
||||||
|
if (name === 'error' && listener.length === 0) {
|
||||||
|
console.error(value)
|
||||||
|
}
|
||||||
|
listener.forEach(l => l(value))
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
this._eventListener = null
|
this._eventListener = null
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import extendRBTree from './RedBlackTree'
|
import extendRBTree from './RedBlackTree'
|
||||||
|
|
||||||
export default function extend (Y) {
|
export default function extend (Y) {
|
||||||
@@ -48,9 +47,13 @@ export default function extend (Y) {
|
|||||||
}
|
}
|
||||||
transact (makeGen) {
|
transact (makeGen) {
|
||||||
const t = new Transaction(this)
|
const t = new Transaction(this)
|
||||||
while (makeGen != null) {
|
try {
|
||||||
makeGen.call(t)
|
while (makeGen != null) {
|
||||||
makeGen = this.getNextRequest()
|
makeGen.call(t)
|
||||||
|
makeGen = this.getNextRequest()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.y.emit('error', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
|
|||||||
@@ -224,16 +224,65 @@ test('move element to a different position', async function xml13 (t) {
|
|||||||
await compareUsers(t, users)
|
await compareUsers(t, users)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('filter node', async function xml14 (t) {
|
||||||
|
var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
|
||||||
|
let dom0 = xml0.getDom()
|
||||||
|
let dom1 = xml1.getDom()
|
||||||
|
let domFilter = (node, attrs) => {
|
||||||
|
if (node.nodeName === 'H1') {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xml0.setDomFilter(domFilter)
|
||||||
|
xml1.setDomFilter(domFilter)
|
||||||
|
dom0.append(document.createElement('div'))
|
||||||
|
dom0.append(document.createElement('h1'))
|
||||||
|
await flushAll(t, users)
|
||||||
|
t.assert(dom1.childNodes.length === 1, 'Only one node was not transmitted')
|
||||||
|
t.assert(dom1.childNodes[0].nodeName === 'DIV', 'div node was transmitted')
|
||||||
|
await compareUsers(t, users)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('filter attribute', async function xml15 (t) {
|
||||||
|
var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
|
||||||
|
let dom0 = xml0.getDom()
|
||||||
|
let dom1 = xml1.getDom()
|
||||||
|
let domFilter = (node, attrs) => {
|
||||||
|
return attrs.filter(name => name !== 'hidden')
|
||||||
|
}
|
||||||
|
xml0.setDomFilter(domFilter)
|
||||||
|
xml1.setDomFilter(domFilter)
|
||||||
|
dom0.setAttribute('hidden', 'true')
|
||||||
|
dom0.setAttribute('style', 'height: 30px')
|
||||||
|
dom0.setAttribute('data-me', '77')
|
||||||
|
await flushAll(t, users)
|
||||||
|
t.assert(dom0.getAttribute('hidden') === 'true', 'User 0 still has the attribute')
|
||||||
|
t.assert(dom1.getAttribute('hidden') == null, 'User 1 did not receive update')
|
||||||
|
t.assert(dom1.getAttribute('style') === 'height: 30px', 'User 1 received style update')
|
||||||
|
t.assert(dom1.getAttribute('data-me') === '77', 'User 1 received data update')
|
||||||
|
await compareUsers(t, users)
|
||||||
|
})
|
||||||
|
|
||||||
// TODO: move elements
|
// TODO: move elements
|
||||||
var xmlTransactions = [
|
var xmlTransactions = [
|
||||||
function attributeChange (t, user, chance) {
|
function attributeChange (t, user, chance) {
|
||||||
user.share.xml.getDom().setAttribute(chance.word(), chance.word())
|
user.share.xml.getDom().setAttribute(chance.word(), chance.word())
|
||||||
},
|
},
|
||||||
|
function attributeChangeHidden (t, user, chance) {
|
||||||
|
user.share.xml.getDom().setAttribute('hidden', chance.word())
|
||||||
|
},
|
||||||
function insertText (t, user, chance) {
|
function insertText (t, user, chance) {
|
||||||
let dom = user.share.xml.getDom()
|
let dom = user.share.xml.getDom()
|
||||||
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
|
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
|
||||||
dom.insertBefore(document.createTextNode(chance.word()), succ)
|
dom.insertBefore(document.createTextNode(chance.word()), succ)
|
||||||
},
|
},
|
||||||
|
function insertHiddenDom (t, user, chance) {
|
||||||
|
let dom = user.share.xml.getDom()
|
||||||
|
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
|
||||||
|
dom.insertBefore(document.createElement('hidden'), succ)
|
||||||
|
},
|
||||||
function insertDom (t, user, chance) {
|
function insertDom (t, user, chance) {
|
||||||
let dom = user.share.xml.getDom()
|
let dom = user.share.xml.getDom()
|
||||||
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
|
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
|
||||||
@@ -274,30 +323,30 @@ var xmlTransactions = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
test('y-xml: Random tests (10)', async function randomXml10 (t) {
|
test('y-xml: Random tests (10)', async function xmlRandom10 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 10)
|
await applyRandomTests(t, xmlTransactions, 10)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (42)', async function randomXml42 (t) {
|
test('y-xml: Random tests (42)', async function xmlRandom42 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 42)
|
await applyRandomTests(t, xmlTransactions, 42)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (43)', async function randomXml43 (t) {
|
test('y-xml: Random tests (43)', async function xmlRandom43 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 43)
|
await applyRandomTests(t, xmlTransactions, 43)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (44)', async function randomXml44 (t) {
|
test('y-xml: Random tests (44)', async function xmlRandom44 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 44)
|
await applyRandomTests(t, xmlTransactions, 44)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (45)', async function randomXml45 (t) {
|
test('y-xml: Random tests (45)', async function xmlRandom45 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 45)
|
await applyRandomTests(t, xmlTransactions, 45)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (46)', async function randomXml46 (t) {
|
test('y-xml: Random tests (46)', async function xmlRandom46 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 46)
|
await applyRandomTests(t, xmlTransactions, 46)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (47)', async function randomXml47 (t) {
|
test('y-xml: Random tests (47)', async function xmlRandom47 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 47)
|
await applyRandomTests(t, xmlTransactions, 47)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import _Y from '../../yjs/src/y.js'
|
import _Y from '../../yjs/src/y.js'
|
||||||
|
|
||||||
import yArray from '../../y-array/src/y-array.js'
|
import yArray from '../../y-array/src/y-array.js'
|
||||||
import yText from '../../y-text/src/Text.js'
|
import yText from '../../y-text/src/y-text.js'
|
||||||
import yMap from '../../y-map/src/y-map.js'
|
import yMap from '../../y-map/src/y-map.js'
|
||||||
import yXml from '../../y-xml/src/y-xml.js'
|
import yXml from '../../y-xml/src/y-xml.js'
|
||||||
import yTest from './test-connector.js'
|
import yTest from './test-connector.js'
|
||||||
@@ -48,11 +48,17 @@ export async function garbageCollectUsers (t, users) {
|
|||||||
await Promise.all(users.map(u => u.db.emptyGarbageCollector()))
|
await Promise.all(users.map(u => u.db.emptyGarbageCollector()))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attrsToObject (attrs) {
|
export function attrsObject (dom) {
|
||||||
|
let keys = []
|
||||||
|
let yxml = dom.__yxml
|
||||||
|
for (let i = 0; i < dom.attributes.length; i++) {
|
||||||
|
keys.push(dom.attributes[i].name)
|
||||||
|
}
|
||||||
|
keys = yxml._domFilter(dom, keys)
|
||||||
let obj = {}
|
let obj = {}
|
||||||
for (var i = 0; i < attrs.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
let attr = attrs[i]
|
let key = keys[i]
|
||||||
obj[attr.name] = attr.value
|
obj[key] = dom.getAttribute(key)
|
||||||
}
|
}
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@@ -61,8 +67,10 @@ export function domToJson (dom) {
|
|||||||
if (dom.nodeType === document.TEXT_NODE) {
|
if (dom.nodeType === document.TEXT_NODE) {
|
||||||
return dom.textContent
|
return dom.textContent
|
||||||
} else if (dom.nodeType === document.ELEMENT_NODE) {
|
} else if (dom.nodeType === document.ELEMENT_NODE) {
|
||||||
let attributes = attrsToObject(dom.attributes)
|
let attributes = attrsObject(dom, dom.__yxml)
|
||||||
let children = Array.from(dom.childNodes.values()).map(domToJson)
|
let children = Array.from(dom.childNodes.values())
|
||||||
|
.filter(d => d.__yxml !== false)
|
||||||
|
.map(domToJson)
|
||||||
return {
|
return {
|
||||||
name: dom.nodeName,
|
name: dom.nodeName,
|
||||||
children: children,
|
children: children,
|
||||||
@@ -198,6 +206,13 @@ export async function initArrays (t, opts) {
|
|||||||
for (let name in share) {
|
for (let name in share) {
|
||||||
result[name + i] = y.share[name]
|
result[name + i] = y.share[name]
|
||||||
}
|
}
|
||||||
|
y.share.xml.setDomFilter(function (d, attrs) {
|
||||||
|
if (d.nodeName === 'HIDDEN') {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
return attrs.filter(a => a !== 'hidden')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
result.array0.delete(0, result.array0.length)
|
result.array0.delete(0, result.array0.length)
|
||||||
if (result.users[0].connector.testRoom != null) {
|
if (result.users[0].connector.testRoom != null) {
|
||||||
|
|||||||
83
y.node.js
83
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-17
|
* @version v13.0.0-20
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -292,6 +292,10 @@ class BinaryEncoder {
|
|||||||
this.data = [];
|
this.data = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get length () {
|
||||||
|
return this.data.length
|
||||||
|
}
|
||||||
|
|
||||||
get pos () {
|
get pos () {
|
||||||
return this.data.length
|
return this.data.length
|
||||||
}
|
}
|
||||||
@@ -666,6 +670,11 @@ function extendConnector (Y/* :any */) {
|
|||||||
if (opts.generateUserId !== false) {
|
if (opts.generateUserId !== false) {
|
||||||
this.setUserId(Y.utils.generateUserId());
|
this.setUserId(Y.utils.generateUserId());
|
||||||
}
|
}
|
||||||
|
if (opts.maxBufferLength == null) {
|
||||||
|
this.maxBufferLength = -1;
|
||||||
|
} else {
|
||||||
|
this.maxBufferLength = opts.maxBufferLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnect () {
|
reconnect () {
|
||||||
@@ -821,14 +830,19 @@ function extendConnector (Y/* :any */) {
|
|||||||
encoder.writeVarString(self.opts.room);
|
encoder.writeVarString(self.opts.room);
|
||||||
encoder.writeVarString('update');
|
encoder.writeVarString('update');
|
||||||
let ops = self.broadcastOpBuffer;
|
let ops = self.broadcastOpBuffer;
|
||||||
self.broadcastOpBuffer = [];
|
|
||||||
let length = ops.length;
|
let length = ops.length;
|
||||||
encoder.writeUint32(length);
|
let encoderPosLen = encoder.pos;
|
||||||
for (var i = 0; i < length; i++) {
|
encoder.writeUint32(0);
|
||||||
|
for (var i = 0; i < length && (self.maxBufferLength < 0 || encoder.length < self.maxBufferLength); i++) {
|
||||||
let op = ops[i];
|
let op = ops[i];
|
||||||
Y.Struct[op.struct].binaryEncode(encoder, op);
|
Y.Struct[op.struct].binaryEncode(encoder, op);
|
||||||
}
|
}
|
||||||
|
encoder.setUint32(encoderPosLen, i);
|
||||||
|
self.broadcastOpBuffer = ops.slice(i);
|
||||||
self.broadcast(encoder.createBuffer());
|
self.broadcast(encoder.createBuffer());
|
||||||
|
if (i !== length) {
|
||||||
|
setTimeout(broadcastOperations, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.broadcastOpBuffer.length === 0) {
|
if (this.broadcastOpBuffer.length === 0) {
|
||||||
@@ -3434,6 +3448,51 @@ function Utils (Y) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Y.utils.getRelativePosition = function (type, offset) {
|
||||||
|
if (type == null) {
|
||||||
|
return null
|
||||||
|
} else {
|
||||||
|
if (type._content.length <= offset) {
|
||||||
|
return ['endof', type._model[0], type._model[1]]
|
||||||
|
} else {
|
||||||
|
return type._content[offset].id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Y.utils.fromRelativePosition = function (y, id) {
|
||||||
|
var offset = 0;
|
||||||
|
var op;
|
||||||
|
if (id[0] === 'endof') {
|
||||||
|
id = y.db.os.find(id.slice(1)).end;
|
||||||
|
op = y.db.os.findNodeWithUpperBound(id).val;
|
||||||
|
if (!op.deleted) {
|
||||||
|
offset = op.content != null ? op.content.length : 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
op = y.db.os.findNodeWithUpperBound(id).val;
|
||||||
|
if (!op.deleted) {
|
||||||
|
offset = id[1] - op.id[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = y.db.getType(op.parent);
|
||||||
|
if (type == null || y.db.os.find(op.parent).deleted) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
while (op.left != null) {
|
||||||
|
op = y.db.os.findNodeWithUpperBound(op.left).val;
|
||||||
|
if (!op.deleted) {
|
||||||
|
offset += op.content != null ? op.content.length : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
offset: offset
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class NamedEventHandler {
|
class NamedEventHandler {
|
||||||
constructor () {
|
constructor () {
|
||||||
this._eventListener = {};
|
this._eventListener = {};
|
||||||
@@ -3452,7 +3511,11 @@ function Utils (Y) {
|
|||||||
this._eventListener[name] = listener.filter(e => e !== f);
|
this._eventListener[name] = listener.filter(e => e !== f);
|
||||||
}
|
}
|
||||||
emit (name, value) {
|
emit (name, value) {
|
||||||
(this._eventListener[name] || []).forEach(l => l(value));
|
let listener = this._eventListener[name] || [];
|
||||||
|
if (name === 'error' && listener.length === 0) {
|
||||||
|
console.error(value);
|
||||||
|
}
|
||||||
|
listener.forEach(l => l(value));
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
this._eventListener = null;
|
this._eventListener = null;
|
||||||
@@ -4793,9 +4856,13 @@ function extend (Y) {
|
|||||||
}
|
}
|
||||||
transact (makeGen) {
|
transact (makeGen) {
|
||||||
const t = new Transaction(this);
|
const t = new Transaction(this);
|
||||||
while (makeGen != null) {
|
try {
|
||||||
makeGen.call(t);
|
while (makeGen != null) {
|
||||||
makeGen = this.getNextRequest();
|
makeGen.call(t);
|
||||||
|
makeGen = this.getNextRequest();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.y.emit('error', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
|
|||||||
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