From 4c01a34d0921fd2d6a3b4d392ccc08274aaad0bf Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Sat, 13 Oct 2018 14:38:29 +0200 Subject: [PATCH] integrate ydb client and adapt some demos --- {ydb => YdbClient}/README.md | 0 YdbClient/TODO.md | 56 ++++++++++++ ydb/ydb-client.js => YdbClient/YdbClient.js | 38 +++++++- .../YdbClient.test.js | 2 +- {ydb => YdbClient}/broadcastchannel.js | 0 {ydb => YdbClient}/decoding.js | 0 {ydb => YdbClient}/encoding.js | 0 {ydb => YdbClient}/encoding.test.js | 0 {ydb => YdbClient}/globals.js | 0 {ydb => YdbClient}/idb.js | 0 {ydb => YdbClient}/idb.test.js | 0 {ydb => YdbClient}/idbactions.js | 35 +++++--- {ydb => YdbClient}/idbactions.test.js | 0 {ydb => YdbClient}/index.js | 2 +- {ydb => YdbClient}/logging.js | 0 {ydb => YdbClient}/message.js | 4 +- {ydb => YdbClient}/test.html | 0 {ydb => YdbClient}/test.js | 0 examples/notes/index.html | 13 ++- examples/notes/index.js | 88 +++++++++++++++++++ examples/notes/index.mjs | 48 ---------- examples/notes/style.css | 57 ++++++++++++ examples/textarea/index.js | 2 +- src/Bindings/DomBinding/DomBinding.js | 6 +- src/MessageHandler/integrateRemoteStructs.js | 32 +++++++ src/Transaction.js | 9 +- src/Y.js | 13 --- 27 files changed, 314 insertions(+), 91 deletions(-) rename {ydb => YdbClient}/README.md (100%) create mode 100644 YdbClient/TODO.md rename ydb/ydb-client.js => YdbClient/YdbClient.js (75%) rename ydb/ydb-client.test.js => YdbClient/YdbClient.test.js (98%) rename {ydb => YdbClient}/broadcastchannel.js (100%) rename {ydb => YdbClient}/decoding.js (100%) rename {ydb => YdbClient}/encoding.js (100%) rename {ydb => YdbClient}/encoding.test.js (100%) rename {ydb => YdbClient}/globals.js (100%) rename {ydb => YdbClient}/idb.js (100%) rename {ydb => YdbClient}/idb.test.js (100%) rename {ydb => YdbClient}/idbactions.js (91%) rename {ydb => YdbClient}/idbactions.test.js (100%) rename {ydb => YdbClient}/index.js (74%) rename {ydb => YdbClient}/logging.js (100%) rename {ydb => YdbClient}/message.js (96%) rename {ydb => YdbClient}/test.html (100%) rename {ydb => YdbClient}/test.js (100%) create mode 100644 examples/notes/index.js delete mode 100644 examples/notes/index.mjs create mode 100644 examples/notes/style.css diff --git a/ydb/README.md b/YdbClient/README.md similarity index 100% rename from ydb/README.md rename to YdbClient/README.md diff --git a/YdbClient/TODO.md b/YdbClient/TODO.md new file mode 100644 index 00000000..4f71aaba --- /dev/null +++ b/YdbClient/TODO.md @@ -0,0 +1,56 @@ +Implement default dom filter.. + +But requires more explicit filtering of src attributes + +e.g. src="java\nscript:alert(0)" + +function domFilter (nodeName, attributes) { + // Filter all attributes that start with on*. E.g. onclick does execute code + // If key is 'href' or 'src', filter everything but 'http*', 'blob*', or 'data:image*' urls + attributes.forEach(function (value, key) { + key = key.toLowerCase(); + value = value.toLowerCase(); + if (key != null && ( + // filter all attributes starting with 'on' + key.substr(0, 2) === 'on' || + // if key is 'href' or 'src', filter everything but http, blob, or data:image + ( + (key === 'href' || key === 'src') && + value.substr(0, 4) !== 'http' && + value.substr(0, 4) !== 'blob' && + value.substr(0, 10) !== 'data:image' + ) + )) { + attributes.delete(key); + } + }); + switch (nodeName) { + case 'SCRIPT': + return null; + case 'EN-ADORNMENTS': + // TODO: Remove EN-ADORNMENTS check when merged into master branch! + return null; + case 'EN-TABLE': + attributes.delete('class'); + return attributes; + case 'EN-COMMENT': + attributes.delete('style'); + attributes.delete('class'); + return attributes; + case 'SPAN': + return (attributes.get('id') || '').substr(0, 5) === 'goog_' ? null : attributes; + case 'TD': + attributes.delete('class'); + return attributes; + case 'EMBED': + attributes.delete('src'); + attributes.delete('style'); + attributes.delete('data-reference'); + return attributes; + case 'FORM': + attributes.delete('action'); + return attributes; + default: + return (nodeName || '').substr(0, 3) === 'UI-' ? null : attributes; + } + } diff --git a/ydb/ydb-client.js b/YdbClient/YdbClient.js similarity index 75% rename from ydb/ydb-client.js rename to YdbClient/YdbClient.js index 9d40ea87..2a63f7fa 100644 --- a/ydb/ydb-client.js +++ b/YdbClient/YdbClient.js @@ -7,6 +7,9 @@ import * as encoding from './encoding.js' import * as logging from './logging.js' import * as idb from './idb.js' import Y from '../src/Y.js' +import BinaryDecoder from '../src/Util/Binary/Decoder.js' +import { integrateRemoteStruct } from '../src/MessageHandler/integrateRemoteStructs.js' +import { createMutualExclude } from '../src/Util/mutualExclude.js' export class YdbClient { constructor (url, db) { @@ -24,9 +27,20 @@ export class YdbClient { */ getY (roomname) { const y = new Y(roomname) - y.on('afterTransaction', function () { - debugger - }) + const mutex = createMutualExclude() + y.on('afterTransaction', (y, transaction) => mutex(() => { + if (transaction.encodedStructsLen > 0) { + update(this, roomname, transaction.encodedStructs.createBuffer()) + } + })) + subscribe(this, roomname, update => mutex(() => { + y.transact(() => { + const decoder = new BinaryDecoder(update) + while (decoder.hasContent()) { + integrateRemoteStruct(y, decoder) + } + }, true) + })) return y } } @@ -111,7 +125,7 @@ export const update = (ydb, room, update) => { const t = idbactions.createTransaction(ydb.db) logging.log(`Write Unconfirmed Update. room "${room}", ${JSON.stringify(update)}`) return idbactions.writeClientUnconfirmed(t, room, update).then(clientConf => { - logging.log(`Send Unconfirmed Update. connected ${ydb.connected} room "${room}", clientConf ${clientConf}, ${logging.arrayBufferToString(update)}`) + logging.log(`Send Unconfirmed Update. connected ${ydb.connected} room "${room}", clientConf ${clientConf}`) send(ydb, message.createUpdate(room, update, clientConf)) }) } @@ -133,3 +147,19 @@ export const subscribe = (ydb, room, f) => { } }) } + +export const subscribeRooms = (ydb, rooms) => { + const t = idbactions.createTransaction(ydb.db) + const subs = [] + return globals.pall(rooms.map(room => idbactions.getRoomMeta(t, room).then(meta => { + if (meta === undefined) { + subs.push(room) + return idbactions.writeUnconfirmedSubscription(t, room) + } + }))).then(() => { + // write all sub messages when all unconfirmed subs are writted to idb + if (subs.length > 0) { + send(ydb, message.createSub(rooms.map(room => ({room, offset: 0})))) + } + }) +} diff --git a/ydb/ydb-client.test.js b/YdbClient/YdbClient.test.js similarity index 98% rename from ydb/ydb-client.test.js rename to YdbClient/YdbClient.test.js index 828c1ee6..fd981fff 100644 --- a/ydb/ydb-client.test.js +++ b/YdbClient/YdbClient.test.js @@ -1,7 +1,7 @@ /* eslint-env browser */ import * as test from './test.js' -import * as ydbClient from './ydb-client.js' +import * as ydbClient from './YdbClient.js' import * as globals from './globals.js' import * as idbactions from './idbactions.js' import * as logging from './logging.js' diff --git a/ydb/broadcastchannel.js b/YdbClient/broadcastchannel.js similarity index 100% rename from ydb/broadcastchannel.js rename to YdbClient/broadcastchannel.js diff --git a/ydb/decoding.js b/YdbClient/decoding.js similarity index 100% rename from ydb/decoding.js rename to YdbClient/decoding.js diff --git a/ydb/encoding.js b/YdbClient/encoding.js similarity index 100% rename from ydb/encoding.js rename to YdbClient/encoding.js diff --git a/ydb/encoding.test.js b/YdbClient/encoding.test.js similarity index 100% rename from ydb/encoding.test.js rename to YdbClient/encoding.test.js diff --git a/ydb/globals.js b/YdbClient/globals.js similarity index 100% rename from ydb/globals.js rename to YdbClient/globals.js diff --git a/ydb/idb.js b/YdbClient/idb.js similarity index 100% rename from ydb/idb.js rename to YdbClient/idb.js diff --git a/ydb/idb.test.js b/YdbClient/idb.test.js similarity index 100% rename from ydb/idb.test.js rename to YdbClient/idb.test.js diff --git a/ydb/idbactions.js b/YdbClient/idbactions.js similarity index 91% rename from ydb/idbactions.js rename to YdbClient/idbactions.js index a7fd0e8b..9f960677 100644 --- a/ydb/idbactions.js +++ b/YdbClient/idbactions.js @@ -186,7 +186,7 @@ export const writeHostUnconfirmedByClient = (t, clientConf, offset) => idb.get(g * @param {ArrayBuffer} update * @return {Promise} */ -export const writeHostUnconfirmed = (t, room, offset, update) => idb.add(getStoreHU(t), update, encodeHUKey(room, offset)) +export const writeHostUnconfirmed = (t, room, offset, update) => idb.put(getStoreHU(t), update, encodeHUKey(room, offset)) /** * The host confirms that it persisted updates up until (including) offset. updates may be moved from HU to Co. @@ -199,9 +199,11 @@ export const writeConfirmedByHost = (t, room, offset) => { const co = getStoreCo(t) return globals.pall([idb.get(co, getCoDataKey(room)), idb.get(co, getCoMetaKey(room))]).then(async arr => { const data = arr[0] - const meta = arr[1] - const metaSessionId = decodeMetaValue(meta).roomsid + const meta = decodeMetaValue(arr[1]) const dataEncoder = encoding.createEncoder() + if (meta.offset >= offset) { + return // nothing to do + } encoding.writeArrayBuffer(dataEncoder, data) const hu = getStoreHU(t) const huKeyRange = idb.createIDBKeyRangeBound(encodeHUKey(room, 0), encodeHUKey(room, offset), false, false) @@ -210,9 +212,9 @@ export const writeConfirmedByHost = (t, room, offset) => { if (key.room === room && key.offset <= offset) { encoding.writeArrayBuffer(dataEncoder, value) } - }).then(() => - globals.pall([idb.put(co, encodeMetaValue(metaSessionId, offset), getCoMetaKey(room)), idb.put(co, encoding.toBuffer(dataEncoder), getCoDataKey(room)), idb.del(hu, huKeyRange)]) - ) + }).then(() => { + globals.pall([idb.put(co, encodeMetaValue(meta.roomsid, offset), getCoMetaKey(room)), idb.put(co, encoding.toBuffer(dataEncoder), getCoDataKey(room)), idb.del(hu, huKeyRange)]) + }) }) } @@ -290,10 +292,23 @@ const encodeMetaValue = (roomsid, offset) => { * @param {number} offset * @return {Promise} */ -export const confirmSubscription = (t, room, roomsessionid, offset) => globals.pall([ - idb.put(getStoreCo(t), encodeMetaValue(roomsessionid, offset), getCoMetaKey(room)), - idb.put(getStoreCo(t), globals.createArrayBufferFromArray([]), getCoDataKey(room)) -]).then(() => idb.del(getStoreUS(t), room)) +export const confirmSubscription = (t, room, roomsessionid, offset) => idb.get(getStoreCo(t), getCoMetaKey(room)).then(metaval => { + if (metaval === undefined) { + return globals.pall([ + idb.put(getStoreCo(t), encodeMetaValue(roomsessionid, offset), getCoMetaKey(room)), + idb.put(getStoreCo(t), globals.createArrayBufferFromArray([]), getCoDataKey(room)) + ]).then(() => idb.del(getStoreUS(t), room)) + } + const meta = decodeMetaValue(metaval) + if (meta.roomsid !== roomsessionid) { + // TODO: upload all unconfirmed updates + // or do a Yjs sync with server + } else if (meta.roomsid < offset) { + return writeConfirmedByHost(t, room, offset) + } else { + // nothing needs to happen + } +}) export const writeUnconfirmedSubscription = (t, room) => idb.put(getStoreUS(t), true, room) diff --git a/ydb/idbactions.test.js b/YdbClient/idbactions.test.js similarity index 100% rename from ydb/idbactions.test.js rename to YdbClient/idbactions.test.js diff --git a/ydb/index.js b/YdbClient/index.js similarity index 74% rename from ydb/index.js rename to YdbClient/index.js index 578f545b..a7b99102 100644 --- a/ydb/index.js +++ b/YdbClient/index.js @@ -1,4 +1,4 @@ -import * as ydbclient from './ydb-client.js' +import * as ydbclient from './YdbClient.js' /** * @param {string} url diff --git a/ydb/logging.js b/YdbClient/logging.js similarity index 100% rename from ydb/logging.js rename to YdbClient/logging.js diff --git a/ydb/message.js b/YdbClient/message.js similarity index 96% rename from ydb/message.js rename to YdbClient/message.js index 4affde14..5a205c83 100644 --- a/ydb/message.js +++ b/YdbClient/message.js @@ -25,7 +25,7 @@ export const readMessage = (ydb, message) => { const offset = decoding.readVarUint(decoder) const room = decoding.readVarString(decoder) const update = decoding.readPayload(decoder) - logging.log(`Received Update. room "${room}", offset ${offset}, ${logging.arrayBufferToString(update)}`) + logging.log(`Received Update. room "${room}", offset ${offset}`) idbactions.writeHostUnconfirmed(t, room, offset, update) bc.publish(room, update) break @@ -36,7 +36,7 @@ export const readMessage = (ydb, message) => { const room = decoding.readVarString(decoder) const offset = decoding.readVarUint(decoder) const roomsid = decoding.readVarUint(decoder) // TODO: SID - logging.log(`Received Sub Conf. room "${room}", offset ${offset}, roomsid ${roomsid}`) + // logging.log(`Received Sub Conf. room "${room}", offset ${offset}, roomsid ${roomsid}`) idbactions.confirmSubscription(t, room, roomsid, offset) } break diff --git a/ydb/test.html b/YdbClient/test.html similarity index 100% rename from ydb/test.html rename to YdbClient/test.html diff --git a/ydb/test.js b/YdbClient/test.js similarity index 100% rename from ydb/test.js rename to YdbClient/test.js diff --git a/examples/notes/index.html b/examples/notes/index.html index d2fdf891..d7f3379a 100644 --- a/examples/notes/index.html +++ b/examples/notes/index.html @@ -2,7 +2,16 @@ + - + + +
+

+
+
- + \ No newline at end of file diff --git a/examples/notes/index.js b/examples/notes/index.js new file mode 100644 index 00000000..021a7d93 --- /dev/null +++ b/examples/notes/index.js @@ -0,0 +1,88 @@ +/* eslint-env browser */ + +import { createYdbClient } from '../../YdbClient/index.js' +import Y from '../../src/Y.dist.js' +import * as ydb from '../../YdbClient/YdbClient.js' +import DomBinding from '../../src/Bindings/DomBinding/DomBinding.js' + +const uuidv4 = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = Math.random() * 16 | 0 + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16) +}) + +createYdbClient('ws://localhost:8899/ws').then(ydbclient => { + const y = ydbclient.getY('notelist') + let ynotelist = y.define('notelist', Y.Array) + const domNoteList = document.querySelector('.notelist') + + // utils + const addEventListener = (element, eventname, f) => element.addEventListener(eventname, f) + + // create note button + const createNoteButton = event => { + ynotelist.insert(0, [{ + guid: uuidv4(), + title: 'Note #' + ynotelist.length + }]) + } + addEventListener(document.querySelector('#createNoteButton'), 'click', createNoteButton) + window.createNote = createNoteButton + window.createNotes = n => { + y.transact(() => { + for (let i = 0; i < n; i++) { + createNoteButton() + } + }) + } + + // clear note list function + window.clearNotes = () => ynotelist.delete(0, ynotelist.length) + + // update editor and editor title + let domBinding = null + const updateEditor = () => { + domNoteList.querySelectorAll('a').forEach(a => a.classList.remove('selected')) + const domNote = document.querySelector('.notelist').querySelector(`[href="${location.hash}"]`) + if (domNote !== null) { + domNote.classList.add('selected') + const note = ynotelist.toArray().find(note => note.guid === location.hash.slice(1)) + if (note !== undefined) { + const ydoc = ydbclient.getY(note.guid) + const ycontent = ydoc.define('content', Y.XmlFragment) + if (domBinding !== null) { + domBinding.destroy() + } + domBinding = new DomBinding(ycontent, document.querySelector('#editor')) + document.querySelector('#headline').innerText = note.title + document.querySelector('#editor').focus() + } + } + } + + // listen to url-hash changes + addEventListener(window, 'hashchange', updateEditor) + updateEditor() + + // render note list + const renderNoteList = addedElements => { + const fragment = document.createDocumentFragment() + addedElements.forEach(note => { + const a = document.createElement('a') + a.setAttribute('href', '#' + note.guid) + a.innerText = note.title + fragment.insertBefore(a, null) + }) + domNoteList.insertBefore(fragment, domNoteList.firstChild) + } + renderNoteList(ynotelist.toArray()) + ydb.subscribeRooms(ydbclient, ynotelist.map(note => note.guid)) + ynotelist.observe(event => { + const addedNotes = [] + event.addedElements.forEach(itemJson => itemJson._content.forEach(json => addedNotes.push(json))) + // const arr = ynotelist.toArray().filter(note => event.addedElements.has(note)) + renderNoteList(addedNotes.reverse()) + if (domBinding === null) { + updateEditor() + } + }) +}) diff --git a/examples/notes/index.mjs b/examples/notes/index.mjs deleted file mode 100644 index d3dc9080..00000000 --- a/examples/notes/index.mjs +++ /dev/null @@ -1,48 +0,0 @@ - -import IndexedDBPersistence from '../../src/Persistences/IndexeddbPersistence.js' -import YWebsocketsConnector from '../../src/Connectors/WebsocketsConnector/WebsocketsConnector.js' -import Y from '../../src/Y.js' -import YXmlFragment from '../../src/Types/YXml/YXmlFragment.js' - -const yCollection = new YCollection(new YWebsocketsConnector(), new IndexedDBPersistence()) - -const y = yCollection.getDocument('my-notes') - - - - - -persistence.addConnector(persistence) - -const y = new Y() -await persistence.persistY(y) - - -connector.connectY('html-editor', y) -persistence.connectY('html-editor', y) - - - - -window.connector = connector - -window.onload = function () { - window.domBinding = new DomBinding(window.yXmlType, document.body, { scrollingElement: document.scrollingElement }) -} - -window.y = y -window.yXmlType = y.define('xml', YXmlFragment) -window.undoManager = new UndoManager(window.yXmlType, { - captureTimeout: 500 -}) - -document.onkeydown = function interceptUndoRedo (e) { - if (e.keyCode === 90 && (e.metaKey || e.ctrlKey)) { - if (!e.shiftKey) { - window.undoManager.undo() - } else { - window.undoManager.redo() - } - e.preventDefault() - } -} diff --git a/examples/notes/style.css b/examples/notes/style.css new file mode 100644 index 00000000..b58eb39f --- /dev/null +++ b/examples/notes/style.css @@ -0,0 +1,57 @@ +.sidebar { + height: 100%; /* Full-height: remove this if you want "auto" height */ + width: 180px; /* Set the width of the sidebar */ + position: fixed; /* Fixed Sidebar (stay in place on scroll) */ + z-index: 1; /* Stay on top */ + top: 0; /* Stay at the top */ + left: 0; + background-color: #111; /* Black */ + overflow-x: hidden; /* Disable horizontal scroll */ + padding-top: 20px; + color: #50abff; +} + +#createNoteButton { + padding-left: .5em; + padding-top: .5em; + padding-bottom: .7em; + margin: 0; + cursor: pointer; +} + +.sidebar a { + padding: 6px 8px 6px 16px; + text-decoration: none; + font-size: 13px; + color: #818181; + display: block; +} + +.sidebar a.selected { + border-style: outset; +} + +/* When you mouse over the navigation links, change their color */ +.sidebar a:hover { + color: #f1f1f1; +} + +/* Style page content */ +.main { + margin-left: 180px; /* Same as the width of the sidebar */ + padding: 0px 10px; +} + +/* On smaller screens, where height is less than 450px, change the style of the sidebar (less padding and a smaller font size) */ +@media screen and (max-height: 450px) { + .sidebar {padding-top: 15px;} + .sidebar a {font-size: 18px;} +} + +#editor { + min-height: 400px; +} + +[contenteditable]:focus { + outline: 0px solid transparent; +} \ No newline at end of file diff --git a/examples/textarea/index.js b/examples/textarea/index.js index 15ecb028..db3eedea 100644 --- a/examples/textarea/index.js +++ b/examples/textarea/index.js @@ -1,4 +1,4 @@ -import { createYdbClient } from '../../ydb/index.js' +import { createYdbClient } from '../../YdbClient/index.js' import Y from '../../src/Y.dist.js' createYdbClient('ws://localhost:8899/ws').then(ydbclient => { diff --git a/src/Bindings/DomBinding/DomBinding.js b/src/Bindings/DomBinding/DomBinding.js index beabb910..b2454609 100644 --- a/src/Bindings/DomBinding/DomBinding.js +++ b/src/Bindings/DomBinding/DomBinding.js @@ -69,9 +69,10 @@ export default class DomBinding extends Binding { subtree: true }) this._currentSel = null - document.addEventListener('selectionchange', () => { + this._selectionchange = () => { this._currentSel = getCurrentRelativeSelection(this) - }) + } + document.addEventListener('selectionchange', this._selectionchange) const y = type._y this.y = y // Force flush dom changes before Type changes are applied (they might @@ -193,6 +194,7 @@ export default class DomBinding extends Binding { y.off('beforeTransaction', this._beforeTransactionHandler) y.off('beforeObserverCalls', this._beforeObserverCallsHandler) y.off('afterTransaction', this._afterTransactionHandler) + document.removeEventListener('selectionchange', this._selectionchange) super.destroy() } } diff --git a/src/MessageHandler/integrateRemoteStructs.js b/src/MessageHandler/integrateRemoteStructs.js index 802c3af6..e4038675 100644 --- a/src/MessageHandler/integrateRemoteStructs.js +++ b/src/MessageHandler/integrateRemoteStructs.js @@ -107,3 +107,35 @@ export function integrateRemoteStructs (y, decoder) { } } } + +// TODO: use this above / refactor +export function integrateRemoteStruct (y, decoder) { + let reference = decoder.readVarUint() + let Constr = getStruct(reference) + let struct = new Constr() + let decoderPos = decoder.pos + let missing = struct._fromBinary(y, decoder) + if (missing.length === 0) { + while (struct != null) { + _integrateRemoteStructHelper(y, struct) + struct = y._readyToIntegrate.shift() + } + } else { + let _decoder = new BinaryDecoder(decoder.uint8arr) + _decoder.pos = decoderPos + let missingEntry = new MissingEntry(_decoder, missing, struct) + let missingStructs = y._missingStructs + for (let i = missing.length - 1; i >= 0; i--) { + let m = missing[i] + if (!missingStructs.has(m.user)) { + missingStructs.set(m.user, new Map()) + } + let msu = missingStructs.get(m.user) + if (!msu.has(m.clock)) { + msu.set(m.clock, []) + } + let mArray = msu = msu.get(m.clock) + mArray.push(missingEntry) + } + } +} diff --git a/src/Transaction.js b/src/Transaction.js index ed8dfdc5..a01a7b37 100644 --- a/src/Transaction.js +++ b/src/Transaction.js @@ -60,18 +60,13 @@ export default class Transaction { */ this.changedParentTypes = new Map() this.encodedStructsLen = 0 - this._encodedStructs = new BinaryEncoder() - this._encodedStructs.writeUint32(0) - } - get encodedStructs () { - this._encodedStructs.setUint32(0, this.encodedStructsLen) - return this._encodedStructs + this.encodedStructs = new BinaryEncoder() } } export function writeStructToTransaction (transaction, struct) { transaction.encodedStructsLen++ - struct._toBinary(transaction._encodedStructs) + struct._toBinary(transaction.encodedStructs) } /** diff --git a/src/Y.js b/src/Y.js index 9eb3aced..be03faf1 100644 --- a/src/Y.js +++ b/src/Y.js @@ -36,21 +36,8 @@ export default class Y extends NamedEventHandler { * @type {String} */ this.room = room -<<<<<<< HEAD:src/Y.js - if (opts != null && opts.connector != null) { - opts.connector.room = room - } - this._contentReady = false - this._opts = opts - if (opts == null || typeof opts.userID !== 'number') { - this.userID = generateRandomUint32() - } else { - this.userID = opts.userID - } -======= this._contentReady = false this.userID = generateRandomUint32() ->>>>>>> experimental-connectors:src/Y.mjs // TODO: This should be a Map so we can use encodables as keys this.share = {} this.ds = new DeleteStore(this)