Compare commits
1 Commits
v13.0.0-22
...
v13.0.0-17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fdf4b307b |
@@ -7,9 +7,9 @@ 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'
|
||||||
// maxBufferLength: 100
|
|
||||||
},
|
},
|
||||||
share: {
|
share: {
|
||||||
xml: 'XmlFragment()' // y.share.xml is of type Y.Xml with tagname "p"
|
xml: 'XmlFragment()' // y.share.xml is of type Y.Xml with tagname "p"
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="codeMirrorContainer"></div>
|
|
||||||
<script src="../bower_components/codemirror/lib/codemirror.js"></script>
|
|
||||||
<script src="../bower_components/codemirror/mode/javascript/javascript.js"></script>
|
|
||||||
<link rel="stylesheet" href="../bower_components/codemirror/lib/codemirror.css">
|
|
||||||
<style>
|
|
||||||
.CodeMirror {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="module" src="./index.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/* global Y, CodeMirror */
|
|
||||||
|
|
||||||
// initialize a shared object. This function call returns a promise!
|
|
||||||
Y({
|
|
||||||
db: {
|
|
||||||
name: 'memory'
|
|
||||||
},
|
|
||||||
connector: {
|
|
||||||
name: 'websockets-client',
|
|
||||||
room: 'codemirror-example'
|
|
||||||
},
|
|
||||||
sourceDir: '/bower_components',
|
|
||||||
share: {
|
|
||||||
codemirror: 'Text' // y.share.codemirror is of type Y.Text
|
|
||||||
}
|
|
||||||
}).then(function (y) {
|
|
||||||
window.yCodeMirror = y
|
|
||||||
|
|
||||||
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
|
|
||||||
mode: 'javascript',
|
|
||||||
lineNumbers: true
|
|
||||||
})
|
|
||||||
y.share.codemirror.bindCodeMirror(editor)
|
|
||||||
})
|
|
||||||
@@ -4,7 +4,8 @@
|
|||||||
<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/y-text.js"></script>
|
<script src="../../../y-text/dist/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,5 +1,8 @@
|
|||||||
/* 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: {
|
||||||
@@ -7,9 +10,10 @@ Y({
|
|||||||
},
|
},
|
||||||
connector: {
|
connector: {
|
||||||
name: 'websockets-client',
|
name: 'websockets-client',
|
||||||
room: 'Textarea-example2',
|
room: 'Textarea-example',
|
||||||
// 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'
|
||||||
@@ -20,4 +24,7 @@ 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..')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Y from '../src/y.js'
|
|||||||
import yArray from '../../y-array/src/y-array.js'
|
import yArray from '../../y-array/src/y-array.js'
|
||||||
import yIndexedDB from '../../y-indexeddb/src/y-indexeddb.js'
|
import yIndexedDB from '../../y-indexeddb/src/y-indexeddb.js'
|
||||||
import yMap from '../../y-map/src/y-map.js'
|
import yMap from '../../y-map/src/y-map.js'
|
||||||
import yText from '../../y-text/src/y-text.js'
|
import yText from '../../y-text/src/Text.js'
|
||||||
import yXml from '../../y-xml/src/y-xml.js'
|
import yXml from '../../y-xml/src/y-xml.js'
|
||||||
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
|
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
|
||||||
|
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-22",
|
"version": "13.0.0-17",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "yjs",
|
"name": "yjs",
|
||||||
"version": "13.0.0-22",
|
"version": "13.0.0-17",
|
||||||
"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,11 +42,6 @@ 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 () {
|
||||||
@@ -202,19 +197,14 @@ 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
|
||||||
let encoderPosLen = encoder.pos
|
encoder.writeUint32(length)
|
||||||
encoder.writeUint32(0)
|
for (var i = 0; i < length; i++) {
|
||||||
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) {
|
|
||||||
self.whenRemoteResponsive().then(broadcastOperations)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.broadcastOpBuffer.length === 0) {
|
if (this.broadcastOpBuffer.length === 0) {
|
||||||
@@ -225,20 +215,6 @@ export default function extendConnector (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Somehow check the responsiveness of the remote clients/server
|
|
||||||
* Default behavior:
|
|
||||||
* Wait 100ms before broadcasting the next batch of operations
|
|
||||||
*
|
|
||||||
* Only used when maxBufferLength is set
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
whenRemoteResponsive () {
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
setTimeout(resolve, 100)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
You received a raw message, and you know that it is intended for Yjs. Then call this function.
|
You received a raw message, and you know that it is intended for Yjs. Then call this function.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,10 +8,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
81
src/Utils.js
81
src/Utils.js
@@ -49,51 +49,6 @@ 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 = {}
|
||||||
@@ -112,11 +67,7 @@ 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) {
|
||||||
let listener = this._eventListener[name] || []
|
(this._eventListener[name] || []).forEach(l => l(value))
|
||||||
if (name === 'error' && listener.length === 0) {
|
|
||||||
console.error(value)
|
|
||||||
}
|
|
||||||
listener.forEach(l => l(value))
|
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
this._eventListener = null
|
this._eventListener = null
|
||||||
@@ -902,34 +853,4 @@ export default function Utils (Y) {
|
|||||||
}
|
}
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
Y.utils.writeObjectToYMap = function writeObjectToYMap (object, type) {
|
|
||||||
for (var key in object) {
|
|
||||||
var val = object[key]
|
|
||||||
if (Array.isArray(val)) {
|
|
||||||
type.set(key, Y.Array)
|
|
||||||
Y.utils.writeArrayToYArray(val, type.get(key))
|
|
||||||
} else if (typeof val === 'object') {
|
|
||||||
type.set(key, Y.Map)
|
|
||||||
Y.utils.writeObjectToYMap(val, type.get(key))
|
|
||||||
} else {
|
|
||||||
type.set(key, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Y.utils.writeArrayToYArray = function writeArrayToYArray (array, type) {
|
|
||||||
for (var i = array.length - 1; i >= 0; i--) {
|
|
||||||
var val = array[i]
|
|
||||||
if (Array.isArray(val)) {
|
|
||||||
type.insert(0, [Y.Array])
|
|
||||||
Y.utils.writeArrayToYArray(val, type.get(0))
|
|
||||||
} else if (typeof val === 'object') {
|
|
||||||
type.insert(0, [Y.Map])
|
|
||||||
Y.utils.writeObjectToYMap(val, type.get(0))
|
|
||||||
} else {
|
|
||||||
type.insert(0, [val])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import extendRBTree from './RedBlackTree'
|
import extendRBTree from './RedBlackTree'
|
||||||
|
|
||||||
export default function extend (Y) {
|
export default function extend (Y) {
|
||||||
@@ -47,13 +48,9 @@ export default function extend (Y) {
|
|||||||
}
|
}
|
||||||
transact (makeGen) {
|
transact (makeGen) {
|
||||||
const t = new Transaction(this)
|
const t = new Transaction(this)
|
||||||
try {
|
while (makeGen != null) {
|
||||||
while (makeGen != null) {
|
makeGen.call(t)
|
||||||
makeGen.call(t)
|
makeGen = this.getNextRequest()
|
||||||
makeGen = this.getNextRequest()
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.y.emit('error', e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
|
|||||||
@@ -224,65 +224,16 @@ 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
|
||||||
@@ -323,30 +274,30 @@ var xmlTransactions = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
test('y-xml: Random tests (10)', async function xmlRandom10 (t) {
|
test('y-xml: Random tests (10)', async function randomXml10 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 10)
|
await applyRandomTests(t, xmlTransactions, 10)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (42)', async function xmlRandom42 (t) {
|
test('y-xml: Random tests (42)', async function randomXml42 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 42)
|
await applyRandomTests(t, xmlTransactions, 42)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (43)', async function xmlRandom43 (t) {
|
test('y-xml: Random tests (43)', async function randomXml43 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 43)
|
await applyRandomTests(t, xmlTransactions, 43)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (44)', async function xmlRandom44 (t) {
|
test('y-xml: Random tests (44)', async function randomXml44 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 44)
|
await applyRandomTests(t, xmlTransactions, 44)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (45)', async function xmlRandom45 (t) {
|
test('y-xml: Random tests (45)', async function randomXml45 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 45)
|
await applyRandomTests(t, xmlTransactions, 45)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (46)', async function xmlRandom46 (t) {
|
test('y-xml: Random tests (46)', async function randomXml46 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 46)
|
await applyRandomTests(t, xmlTransactions, 46)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('y-xml: Random tests (47)', async function xmlRandom47 (t) {
|
test('y-xml: Random tests (47)', async function randomXml47 (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/y-text.js'
|
import yText from '../../y-text/src/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,17 +48,11 @@ 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 attrsObject (dom) {
|
export function attrsToObject (attrs) {
|
||||||
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 (let i = 0; i < keys.length; i++) {
|
for (var i = 0; i < attrs.length; i++) {
|
||||||
let key = keys[i]
|
let attr = attrs[i]
|
||||||
obj[key] = dom.getAttribute(key)
|
obj[attr.name] = attr.value
|
||||||
}
|
}
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@@ -67,10 +61,8 @@ 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 = attrsObject(dom, dom.__yxml)
|
let attributes = attrsToObject(dom.attributes)
|
||||||
let children = Array.from(dom.childNodes.values())
|
let children = Array.from(dom.childNodes.values()).map(domToJson)
|
||||||
.filter(d => d.__yxml !== false)
|
|
||||||
.map(domToJson)
|
|
||||||
return {
|
return {
|
||||||
name: dom.nodeName,
|
name: dom.nodeName,
|
||||||
children: children,
|
children: children,
|
||||||
@@ -206,13 +198,6 @@ 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) {
|
||||||
|
|||||||
127
y.node.js
127
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-22
|
* @version v13.0.0-17
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -292,10 +292,6 @@ class BinaryEncoder {
|
|||||||
this.data = [];
|
this.data = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get length () {
|
|
||||||
return this.data.length
|
|
||||||
}
|
|
||||||
|
|
||||||
get pos () {
|
get pos () {
|
||||||
return this.data.length
|
return this.data.length
|
||||||
}
|
}
|
||||||
@@ -670,11 +666,6 @@ 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 () {
|
||||||
@@ -830,19 +821,14 @@ 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;
|
||||||
let encoderPosLen = encoder.pos;
|
encoder.writeUint32(length);
|
||||||
encoder.writeUint32(0);
|
for (var i = 0; i < length; i++) {
|
||||||
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) {
|
|
||||||
self.whenRemoteResponsive().then(broadcastOperations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.broadcastOpBuffer.length === 0) {
|
if (this.broadcastOpBuffer.length === 0) {
|
||||||
@@ -853,20 +839,6 @@ function extendConnector (Y/* :any */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Somehow check the responsiveness of the remote clients/server
|
|
||||||
* Default behavior:
|
|
||||||
* Wait 100ms before broadcasting the next batch of operations
|
|
||||||
*
|
|
||||||
* Only used when maxBufferLength is set
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
whenRemoteResponsive () {
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
setTimeout(resolve, 100);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
You received a raw message, and you know that it is intended for Yjs. Then call this function.
|
You received a raw message, and you know that it is intended for Yjs. Then call this function.
|
||||||
*/
|
*/
|
||||||
@@ -3462,51 +3434,6 @@ 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 = {};
|
||||||
@@ -3525,11 +3452,7 @@ 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) {
|
||||||
let listener = this._eventListener[name] || [];
|
(this._eventListener[name] || []).forEach(l => l(value));
|
||||||
if (name === 'error' && listener.length === 0) {
|
|
||||||
console.error(value);
|
|
||||||
}
|
|
||||||
listener.forEach(l => l(value));
|
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
this._eventListener = null;
|
this._eventListener = null;
|
||||||
@@ -4315,36 +4238,6 @@ function Utils (Y) {
|
|||||||
}
|
}
|
||||||
return args
|
return args
|
||||||
};
|
};
|
||||||
|
|
||||||
Y.utils.writeObjectToYMap = function writeObjectToYMap (object, type) {
|
|
||||||
for (var key in object) {
|
|
||||||
var val = object[key];
|
|
||||||
if (Array.isArray(val)) {
|
|
||||||
type.set(key, Y.Array);
|
|
||||||
Y.utils.writeArrayToYArray(val, type.get(key));
|
|
||||||
} else if (typeof val === 'object') {
|
|
||||||
type.set(key, Y.Map);
|
|
||||||
Y.utils.writeObjectToYMap(val, type.get(key));
|
|
||||||
} else {
|
|
||||||
type.set(key, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Y.utils.writeArrayToYArray = function writeArrayToYArray (array, type) {
|
|
||||||
for (var i = array.length - 1; i >= 0; i--) {
|
|
||||||
var val = array[i];
|
|
||||||
if (Array.isArray(val)) {
|
|
||||||
type.insert(0, [Y.Array]);
|
|
||||||
Y.utils.writeArrayToYArray(val, type.get(0));
|
|
||||||
} else if (typeof val === 'object') {
|
|
||||||
type.insert(0, [Y.Map]);
|
|
||||||
Y.utils.writeObjectToYMap(val, type.get(0));
|
|
||||||
} else {
|
|
||||||
type.insert(0, [val]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function extendRBTree (Y) {
|
function extendRBTree (Y) {
|
||||||
@@ -4900,13 +4793,9 @@ function extend (Y) {
|
|||||||
}
|
}
|
||||||
transact (makeGen) {
|
transact (makeGen) {
|
||||||
const t = new Transaction(this);
|
const t = new Transaction(this);
|
||||||
try {
|
while (makeGen != null) {
|
||||||
while (makeGen != null) {
|
makeGen.call(t);
|
||||||
makeGen.call(t);
|
makeGen = this.getNextRequest();
|
||||||
makeGen = this.getNextRequest();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.y.emit('error', e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy () {
|
destroy () {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
267
y.test.js
267
y.test.js
@@ -5615,7 +5615,7 @@ function createCommonjsModule$1(fn, module) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var chance_1 = createCommonjsModule$1(function (module, exports) {
|
var chance_1 = createCommonjsModule$1(function (module, exports) {
|
||||||
// Chance.js 1.0.11
|
// Chance.js 1.0.10
|
||||||
// http://chancejs.com
|
// http://chancejs.com
|
||||||
// (c) 2013 Victor Quinn
|
// (c) 2013 Victor Quinn
|
||||||
// Chance may be freely distributed or modified under the MIT license.
|
// Chance may be freely distributed or modified under the MIT license.
|
||||||
@@ -5680,7 +5680,7 @@ var chance_1 = createCommonjsModule$1(function (module, exports) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chance.prototype.VERSION = "1.0.11";
|
Chance.prototype.VERSION = "1.0.10";
|
||||||
|
|
||||||
// Random helper functions
|
// Random helper functions
|
||||||
function initOptions(options, defaults) {
|
function initOptions(options, defaults) {
|
||||||
@@ -5899,16 +5899,6 @@ var chance_1 = createCommonjsModule$1(function (module, exports) {
|
|||||||
return integer.toString(16);
|
return integer.toString(16);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chance.prototype.letter = function(options) {
|
|
||||||
options = initOptions(options, {casing: 'lower'});
|
|
||||||
var pool = "abcdefghijklmnopqrstuvwxyz";
|
|
||||||
var letter = this.character({pool: pool});
|
|
||||||
if (options.casing === 'upper') {
|
|
||||||
letter = letter.toUpperCase();
|
|
||||||
}
|
|
||||||
return letter;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a random string
|
* Return a random string
|
||||||
*
|
*
|
||||||
@@ -14281,7 +14271,7 @@ function extendDatabase (Y /* :any */) {
|
|||||||
* Always:
|
* Always:
|
||||||
* * Call type
|
* * Call type
|
||||||
*/
|
*/
|
||||||
operationAdded (transaction, op) {
|
operationAdded (transaction, op) {
|
||||||
if (op.struct === 'Delete') {
|
if (op.struct === 'Delete') {
|
||||||
var type = this.initializedTypes[JSON.stringify(op.targetParent)];
|
var type = this.initializedTypes[JSON.stringify(op.targetParent)];
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
@@ -14340,7 +14330,6 @@ function extendDatabase (Y /* :any */) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
whenTransactionsFinished () {
|
whenTransactionsFinished () {
|
||||||
if (this.transactionInProgress) {
|
if (this.transactionInProgress) {
|
||||||
if (this.transactionsFinished == null) {
|
if (this.transactionsFinished == null) {
|
||||||
@@ -17603,7 +17592,7 @@ var y = d * 365.25;
|
|||||||
* @api public
|
* @api public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ms = function(val, options) {
|
var index$1$1 = function(val, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var type = typeof val;
|
var type = typeof val;
|
||||||
if (type === 'string' && val.length > 0) {
|
if (type === 'string' && val.length > 0) {
|
||||||
@@ -17745,7 +17734,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 = index$1$1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The currently active debug mode names, and names to skip.
|
* The currently active debug mode names, and names to skip.
|
||||||
@@ -17804,8 +17793,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;
|
||||||
@@ -19816,11 +19805,9 @@ function merge_tuples (diffs, start, length) {
|
|||||||
return diffs;
|
return diffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global Y, Element */
|
|
||||||
|
|
||||||
var monacoIdentifierTemplate = { major: 0, minor: 0 };
|
var monacoIdentifierTemplate = { major: 0, minor: 0 };
|
||||||
|
|
||||||
function extendYText (Y) {
|
function extend$2 (Y) {
|
||||||
Y.requestModules(['Array']).then(function () {
|
Y.requestModules(['Array']).then(function () {
|
||||||
class YText extends Y.Array.typeDefinition['class'] {
|
class YText extends Y.Array.typeDefinition['class'] {
|
||||||
constructor (os, _model, _content, args) {
|
constructor (os, _model, _content, args) {
|
||||||
@@ -20398,8 +20385,9 @@ function extendYText (Y) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var Text = extend$2;
|
||||||
if (typeof Y !== 'undefined') {
|
if (typeof Y !== 'undefined') {
|
||||||
extendYText(Y);
|
extend$2(Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* global Y */
|
/* global Y */
|
||||||
@@ -21300,7 +21288,7 @@ diff$3.INSERT = DIFF_INSERT$1;
|
|||||||
diff$3.DELETE = DIFF_DELETE$1;
|
diff$3.DELETE = DIFF_DELETE$1;
|
||||||
diff$3.EQUAL = DIFF_EQUAL$1;
|
diff$3.EQUAL = DIFF_EQUAL$1;
|
||||||
|
|
||||||
var diff_1$1 = diff$3;
|
var diff_1$2 = diff$3;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Modify a diff such that the cursor position points to the start of a change:
|
* Modify a diff such that the cursor position points to the start of a change:
|
||||||
@@ -21507,8 +21495,6 @@ function extendYXmlText (Y, _document, _MutationObserver) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDomFilter () {}
|
|
||||||
|
|
||||||
_setDom (dom) {
|
_setDom (dom) {
|
||||||
if (this.dom != null) {
|
if (this.dom != null) {
|
||||||
this._unbindFromDom();
|
this._unbindFromDom();
|
||||||
@@ -21523,7 +21509,7 @@ function extendYXmlText (Y, _document, _MutationObserver) {
|
|||||||
dom.__yxml = this;
|
dom.__yxml = this;
|
||||||
this._domObserverListener = () => {
|
this._domObserverListener = () => {
|
||||||
this._mutualExcluse(() => {
|
this._mutualExcluse(() => {
|
||||||
var diffs = diff_1$1(this.toString(), this.dom.nodeValue);
|
var diffs = diff_1$2(this.toString(), this.dom.nodeValue);
|
||||||
var pos = 0;
|
var pos = 0;
|
||||||
for (var i = 0; i < diffs.length; i++) {
|
for (var i = 0; i < diffs.length; i++) {
|
||||||
var d = diffs[i];
|
var d = diffs[i];
|
||||||
@@ -21626,10 +21612,6 @@ function extendYXmlText (Y, _document, _MutationObserver) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultDomFilter (node, attributes) {
|
|
||||||
return attributes
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1. Check if any of the nodes was deleted
|
* 1. Check if any of the nodes was deleted
|
||||||
* 2. Iterate over the children.
|
* 2. Iterate over the children.
|
||||||
@@ -21654,14 +21636,11 @@ function applyChangesFromDom (yxml) {
|
|||||||
// 2. iterate
|
// 2. iterate
|
||||||
let childNodes = yxml.dom.childNodes;
|
let childNodes = yxml.dom.childNodes;
|
||||||
let len = childNodes.length;
|
let len = childNodes.length;
|
||||||
for (let domCnt = 0, yCnt = 0; domCnt < len; domCnt++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let child = childNodes[domCnt];
|
let child = childNodes[i];
|
||||||
if (child.__yxml != null) {
|
if (child.__yxml != null) {
|
||||||
if (child.__yxml === false) {
|
if (i < yxml.length) {
|
||||||
continue
|
let expectedNode = yxml.get(i);
|
||||||
}
|
|
||||||
if (yCnt < yxml.length) {
|
|
||||||
let expectedNode = yxml.get(yCnt);
|
|
||||||
if (expectedNode !== child.__yxml) {
|
if (expectedNode !== child.__yxml) {
|
||||||
// 2.3 Not expected node
|
// 2.3 Not expected node
|
||||||
let index = yxml._content.findIndex(c => c.type[0] === child.__yxml._model[0] && c.type[1] === child.__yxml._model[1]);
|
let index = yxml._content.findIndex(c => c.type[0] === child.__yxml._model[0] && c.type[1] === child.__yxml._model[1]);
|
||||||
@@ -21671,18 +21650,16 @@ function applyChangesFromDom (yxml) {
|
|||||||
} else {
|
} else {
|
||||||
yxml.delete(index, 1);
|
yxml.delete(index, 1);
|
||||||
}
|
}
|
||||||
yCnt += yxml.insertDomElements(yCnt, [child]);
|
yxml.insertDomElements(i, [child]);
|
||||||
} else {
|
|
||||||
yCnt++;
|
|
||||||
}
|
}
|
||||||
// if this is the expected node id, just continue
|
// if this is the expected node id, just continue
|
||||||
} else {
|
} else {
|
||||||
// 2.2 fill _conten with child nodes
|
// 2.2 fill _conten with child nodes
|
||||||
yCnt += yxml.insertDomElements(yCnt, [child]);
|
yxml.insertDomElements(i, [child]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 2.1 A new node was found
|
// 2.1 A new node was found
|
||||||
yCnt += yxml.insertDomElements(yCnt, [child]);
|
yxml.insertDomElements(i, [child]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21695,7 +21672,6 @@ function extendYXmlFragment (Y, _document, _MutationObserver) {
|
|||||||
this.dom = null;
|
this.dom = null;
|
||||||
this._domObserver = null;
|
this._domObserver = null;
|
||||||
this._domObserverListener = null;
|
this._domObserverListener = null;
|
||||||
this._domFilter = defaultDomFilter;
|
|
||||||
var token = true;
|
var token = true;
|
||||||
this._mutualExcluse = f => {
|
this._mutualExcluse = f => {
|
||||||
// take and process current records
|
// take and process current records
|
||||||
@@ -21721,10 +21697,9 @@ function extendYXmlFragment (Y, _document, _MutationObserver) {
|
|||||||
if (this.dom != null) {
|
if (this.dom != null) {
|
||||||
this._mutualExcluse(() => {
|
this._mutualExcluse(() => {
|
||||||
if (event.type === 'insert') {
|
if (event.type === 'insert') {
|
||||||
for (let i = event.values.length - 1; i >= 0; i--) {
|
let nodes = event.values.map(v => v.getDom());
|
||||||
let val = event.values[i];
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||||
val.setDomFilter(this._domFilter);
|
let dom = nodes[i];
|
||||||
let dom = val.getDom();
|
|
||||||
let nextDom = null;
|
let nextDom = null;
|
||||||
if (this._content.length > event.index + i + 1) {
|
if (this._content.length > event.index + i + 1) {
|
||||||
nextDom = this.get(event.index + i + 1).getDom();
|
nextDom = this.get(event.index + i + 1).getDom();
|
||||||
@@ -21741,13 +21716,6 @@ function extendYXmlFragment (Y, _document, _MutationObserver) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDomFilter (f) {
|
|
||||||
this._domFilter = f;
|
|
||||||
this.toArray().forEach(function (c) {
|
|
||||||
c.setDomFilter(f);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
insertDomElements () {
|
insertDomElements () {
|
||||||
return Y.XmlElement.typeDefinition.class.prototype.insertDomElements.apply(this, arguments)
|
return Y.XmlElement.typeDefinition.class.prototype.insertDomElements.apply(this, arguments)
|
||||||
}
|
}
|
||||||
@@ -21846,6 +21814,16 @@ function extendYXmlFragment (Y, _document, _MutationObserver) {
|
|||||||
|
|
||||||
// import diff from 'fast-diff'
|
// import diff from 'fast-diff'
|
||||||
function extendXmlElement (Y, _document, _MutationObserver) {
|
function extendXmlElement (Y, _document, _MutationObserver) {
|
||||||
|
function domToType (dom) {
|
||||||
|
if (dom.nodeType === _document.TEXT_NODE) {
|
||||||
|
return Y.XmlText(dom)
|
||||||
|
} else if (dom.nodeType === _document.ELEMENT_NODE) {
|
||||||
|
return Y.XmlElement(dom)
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported node!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function yarrayEventHandler (op) {
|
function yarrayEventHandler (op) {
|
||||||
if (op.struct === 'Insert') {
|
if (op.struct === 'Insert') {
|
||||||
// when using indexeddb db adapter, the op could already exist (see y-js/y-indexeddb#2)
|
// when using indexeddb db adapter, the op could already exist (see y-js/y-indexeddb#2)
|
||||||
@@ -22023,7 +22001,7 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class YXmlElement extends Y.utils.CustomType {
|
class YXmlElement extends Y.utils.CustomType {
|
||||||
constructor (os, model, arrayContent, contents, opContents, dom, domFilter) {
|
constructor (os, model, arrayContent, contents, opContents, dom) {
|
||||||
super();
|
super();
|
||||||
this._os = os;
|
this._os = os;
|
||||||
this.os = os;
|
this.os = os;
|
||||||
@@ -22050,7 +22028,6 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
this._eventListenerHandler = eventHandler;
|
this._eventListenerHandler = eventHandler;
|
||||||
this._domObserver = null;
|
this._domObserver = null;
|
||||||
this.dom = null;
|
this.dom = null;
|
||||||
this._domFilter = domFilter;
|
|
||||||
if (dom != null) {
|
if (dom != null) {
|
||||||
this._setDom(dom);
|
this._setDom(dom);
|
||||||
}
|
}
|
||||||
@@ -22089,7 +22066,6 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
let nodes = event.nodes;
|
let nodes = event.nodes;
|
||||||
for (let i = nodes.length - 1; i >= 0; i--) {
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
||||||
let node = nodes[i];
|
let node = nodes[i];
|
||||||
node.setDomFilter(this._domFilter);
|
|
||||||
let dom = node.getDom();
|
let dom = node.getDom();
|
||||||
let nextDom = null;
|
let nextDom = null;
|
||||||
if (this._content.length > event.index + i + 1) {
|
if (this._content.length > event.index + i + 1) {
|
||||||
@@ -22107,14 +22083,6 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDomFilter (f) {
|
|
||||||
this._domFilter = f;
|
|
||||||
let len = this._content.length;
|
|
||||||
for (let i = 0; i < len; i++) {
|
|
||||||
this.get(i).setDomFilter(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get length () {
|
get length () {
|
||||||
return this._content.length
|
return this._content.length
|
||||||
}
|
}
|
||||||
@@ -22164,27 +22132,13 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
insertDomElements (pos, doms) {
|
insertDomElements (pos, doms) {
|
||||||
let types = [];
|
|
||||||
doms.forEach(d => {
|
doms.forEach(d => {
|
||||||
if (d.__yxml != null && d.__yxml !== false) {
|
if (d.__yxml != null) {
|
||||||
d.__yxml._unbindFromDom();
|
d.__yxml._unbindFromDom();
|
||||||
}
|
}
|
||||||
if (this._domFilter(d, []) !== null) {
|
|
||||||
let type;
|
|
||||||
if (d.nodeType === _document.TEXT_NODE) {
|
|
||||||
type = Y.XmlText(d, this._domFilter);
|
|
||||||
} else if (d.nodeType === _document.ELEMENT_NODE) {
|
|
||||||
type = Y.XmlElement(d, this._domFilter);
|
|
||||||
} else {
|
|
||||||
throw new Error('Unsupported node!')
|
|
||||||
}
|
|
||||||
types.push(type);
|
|
||||||
} else {
|
|
||||||
d.__yxml = false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
let types = doms.map(domToType);
|
||||||
this.insert(pos, types);
|
this.insert(pos, types);
|
||||||
return types.length
|
|
||||||
}
|
}
|
||||||
|
|
||||||
insert (pos, types) {
|
insert (pos, types) {
|
||||||
@@ -22241,16 +22195,13 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
let diffChildren = false;
|
let diffChildren = false;
|
||||||
mutations.forEach(mutation => {
|
mutations.forEach(mutation => {
|
||||||
if (mutation.type === 'attributes') {
|
if (mutation.type === 'attributes') {
|
||||||
let name = mutation.attributeName;
|
var name = mutation.attributeName;
|
||||||
// check if filter accepts attribute
|
var val = mutation.target.getAttribute(mutation.attributeName);
|
||||||
if (this._domFilter(this.dom, [name]).length > 0) {
|
if (this.getAttribute(name) !== val) {
|
||||||
var val = mutation.target.getAttribute(name);
|
if (val == null) {
|
||||||
if (this.getAttribute(name) !== val) {
|
this.removeAttribute(name);
|
||||||
if (val == null) {
|
} else {
|
||||||
this.removeAttribute(name);
|
this.setAttribute(name, val);
|
||||||
} else {
|
|
||||||
this.setAttribute(name, val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (mutation.type === 'childList') {
|
} else if (mutation.type === 'childList') {
|
||||||
@@ -22276,17 +22227,18 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
dom.__yxml = this;
|
dom.__yxml = this;
|
||||||
// tag is already set in constructor
|
// tag is already set in constructor
|
||||||
// set attributes
|
// set attributes
|
||||||
let attrNames = [];
|
for (var i = 0; i < dom.attributes.length; i++) {
|
||||||
for (let i = 0; i < dom.attributes.length; i++) {
|
var attr = dom.attributes[i];
|
||||||
attrNames.push(dom.attributes[i].name);
|
this.setAttribute(attr.name, attr.value);
|
||||||
}
|
}
|
||||||
attrNames = this._domFilter(dom, attrNames);
|
this.insert(0, Array.prototype.map.call(dom.childNodes, dom => {
|
||||||
for (let i = 0; i < attrNames.length; i++) {
|
if (dom.__yxml != null) {
|
||||||
let attrName = attrNames[i];
|
// it is ok to reset here. It was probably moved from another node, and will be removed by that node
|
||||||
let attrValue = dom.getAttribute(attrName);
|
dom.__yxml._domObserver.disconnect();
|
||||||
this.setAttribute(attrName, attrValue);
|
dom.__yxml = null;
|
||||||
}
|
}
|
||||||
this.insertDomElements(0, Array.prototype.slice.call(dom.childNodes));
|
return domToType(dom)
|
||||||
|
}));
|
||||||
if (_MutationObserver != null) {
|
if (_MutationObserver != null) {
|
||||||
this.dom = this._bindToDom(dom);
|
this.dom = this._bindToDom(dom);
|
||||||
}
|
}
|
||||||
@@ -22377,27 +22329,19 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
name: 'XmlElement',
|
name: 'XmlElement',
|
||||||
class: YXmlElement,
|
class: YXmlElement,
|
||||||
struct: 'Xml',
|
struct: 'Xml',
|
||||||
parseArguments: function (arg, arg2) {
|
parseArguments: function (arg) {
|
||||||
let domFilter;
|
|
||||||
if (typeof arg2 === 'function') {
|
|
||||||
domFilter = arg2;
|
|
||||||
} else {
|
|
||||||
domFilter = defaultDomFilter;
|
|
||||||
}
|
|
||||||
if (typeof arg === 'string') {
|
if (typeof arg === 'string') {
|
||||||
return [this, {
|
return [this, {
|
||||||
nodeName: arg.toUpperCase(),
|
nodeName: arg.toUpperCase(),
|
||||||
dom: null,
|
dom: null
|
||||||
domFilter
|
|
||||||
}]
|
}]
|
||||||
} else if (arg.nodeType === _document.ELEMENT_NODE) {
|
} else if (arg.nodeType === _document.ELEMENT_NODE) {
|
||||||
return [this, {
|
return [this, {
|
||||||
nodeName: arg.nodeName,
|
nodeName: arg.nodeName,
|
||||||
dom: arg,
|
dom: arg
|
||||||
domFilter
|
|
||||||
}]
|
}]
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Y.XmlElement requires an argument which is a string!')
|
throw new Error('Y.Xml requires an argument which is a string!')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initType: function YXmlElementInitializer (os, model, init) {
|
initType: function YXmlElementInitializer (os, model, init) {
|
||||||
@@ -22438,10 +22382,10 @@ function extendXmlElement (Y, _document, _MutationObserver) {
|
|||||||
contents[name] = op.content[0];
|
contents[name] = op.content[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new YXmlElement(os, model, _content, contents, opContents, init != null ? init.dom : null, init != null ? init.domFilter : defaultDomFilter)
|
return new YXmlElement(os, model, _content, contents, opContents, init != null ? init.dom : null)
|
||||||
},
|
},
|
||||||
createType: function YXmlElementCreator (os, model, args) {
|
createType: function YXmlElementCreator (os, model, args) {
|
||||||
return new YXmlElement(os, model, [], {}, {}, args.dom, args.domFilter)
|
return new YXmlElement(os, model, [], {}, {}, args.dom)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -22455,6 +22399,7 @@ function extendXml (Y, _document, _MutationObserver) {
|
|||||||
if (typeof MutationObserver !== 'undefined') {
|
if (typeof MutationObserver !== 'undefined') {
|
||||||
_MutationObserver = MutationObserver;
|
_MutationObserver = MutationObserver;
|
||||||
} else {
|
} else {
|
||||||
|
console.warn('MutationObserver is not available. y-xml won\'t listen to changes on the DOM');
|
||||||
_MutationObserver = null;
|
_MutationObserver = null;
|
||||||
}
|
}
|
||||||
extendXmlElement(Y, _document, _MutationObserver);
|
extendXmlElement(Y, _document, _MutationObserver);
|
||||||
@@ -22632,7 +22577,7 @@ if (typeof Y !== 'undefined') {
|
|||||||
|
|
||||||
let Y$2 = Y$1;
|
let Y$2 = Y$1;
|
||||||
|
|
||||||
Y$2.extend(extend$1, extendYText, extendYMap, extendTestConnector, extendXml);
|
Y$2.extend(extend$1, Text, extendYMap, extendTestConnector, extendXml);
|
||||||
|
|
||||||
var database = { name: 'memory' };
|
var database = { name: 'memory' };
|
||||||
var connector = { name: 'test', url: 'http://localhost:1234' };
|
var connector = { name: 'test', url: 'http://localhost:1234' };
|
||||||
@@ -22669,17 +22614,11 @@ async function garbageCollectUsers (t, users) {
|
|||||||
await Promise.all(users.map(u => u.db.emptyGarbageCollector()));
|
await Promise.all(users.map(u => u.db.emptyGarbageCollector()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function attrsObject (dom) {
|
function attrsToObject (attrs) {
|
||||||
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 (let i = 0; i < keys.length; i++) {
|
for (var i = 0; i < attrs.length; i++) {
|
||||||
let key = keys[i];
|
let attr = attrs[i];
|
||||||
obj[key] = dom.getAttribute(key);
|
obj[attr.name] = attr.value;
|
||||||
}
|
}
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@@ -22688,10 +22627,8 @@ 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 = attrsObject(dom, dom.__yxml);
|
let attributes = attrsToObject(dom.attributes);
|
||||||
let children = Array.from(dom.childNodes.values())
|
let children = Array.from(dom.childNodes.values()).map(domToJson);
|
||||||
.filter(d => d.__yxml !== false)
|
|
||||||
.map(domToJson);
|
|
||||||
return {
|
return {
|
||||||
name: dom.nodeName,
|
name: dom.nodeName,
|
||||||
children: children,
|
children: children,
|
||||||
@@ -22827,13 +22764,6 @@ 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) {
|
||||||
@@ -23908,65 +23838,16 @@ 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;
|
||||||
@@ -24007,31 +23888,31 @@ var xmlTransactions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
test('y-xml: Random tests (10)', async function xmlRandom10 (t) {
|
test('y-xml: Random tests (10)', async function randomXml10 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 10);
|
await applyRandomTests(t, xmlTransactions, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('y-xml: Random tests (42)', async function xmlRandom42 (t) {
|
test('y-xml: Random tests (42)', async function randomXml42 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 42);
|
await applyRandomTests(t, xmlTransactions, 42);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('y-xml: Random tests (43)', async function xmlRandom43 (t) {
|
test('y-xml: Random tests (43)', async function randomXml43 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 43);
|
await applyRandomTests(t, xmlTransactions, 43);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('y-xml: Random tests (44)', async function xmlRandom44 (t) {
|
test('y-xml: Random tests (44)', async function randomXml44 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 44);
|
await applyRandomTests(t, xmlTransactions, 44);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('y-xml: Random tests (45)', async function xmlRandom45 (t) {
|
test('y-xml: Random tests (45)', async function randomXml45 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 45);
|
await applyRandomTests(t, xmlTransactions, 45);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('y-xml: Random tests (46)', async function xmlRandom46 (t) {
|
test('y-xml: Random tests (46)', async function randomXml46 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 46);
|
await applyRandomTests(t, xmlTransactions, 46);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('y-xml: Random tests (47)', async function xmlRandom47 (t) {
|
test('y-xml: Random tests (47)', async function randomXml47 (t) {
|
||||||
await applyRandomTests(t, xmlTransactions, 47);
|
await applyRandomTests(t, xmlTransactions, 47);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user