Compare commits

..

1 Commits

Author SHA1 Message Date
Kevin Jahns
0fdf4b307b v13.0.0-17 -- distribution files 2017-09-11 17:40:04 +02:00
16 changed files with 1053 additions and 924 deletions

View File

@@ -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"

View File

@@ -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>

View File

@@ -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..')
}) })

View File

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

View File

@@ -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.
*/ */

View File

@@ -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
} }

View File

@@ -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

View File

@@ -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 () {

View File

@@ -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)
}) })

View File

@@ -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) {

8
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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-21 * @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;
@@ -4870,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

1660
y.test.js

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long