Compare commits

..

4 Commits

Author SHA1 Message Date
Kevin Jahns
83a6aa0a70 v13.0.0-47 -- distribution files 2018-01-18 18:45:10 +01:00
Kevin Jahns
1d4f283955 13.0.0-47 2018-01-18 18:44:56 +01:00
Kevin Jahns
fc3a4c376c implement when-handler 2018-01-18 18:44:20 +01:00
Kevin Jahns
0b510b64a3 persistence updates + make Persistence.init async 2018-01-16 16:13:47 +01:00
14 changed files with 5909 additions and 5849 deletions

View File

@@ -4,14 +4,14 @@ window.onload = function () {
window.yXmlType.bindToDom(document.body) window.yXmlType.bindToDom(document.body)
} }
let persistence = null // new Y.IndexedDBPersistence() const persistence = new Y.IndexedDB()
// initialize a shared object. This function call returns a promise! // initialize a shared object. This function call returns a promise!
let y = new Y({ let y = new Y('htmleditor', {
connector: { connector: {
name: 'websockets-client', name: 'websockets-client',
url: 'http://127.0.0.1:1234', url: 'http://127.0.0.1:1234',
room: 'x' room: 'html-editor'
// maxBufferLength: 100 // maxBufferLength: 100
} }
}, persistence) }, persistence)

View File

@@ -1,24 +1,18 @@
/* global Y, CodeMirror */ /* global Y, CodeMirror */
// initialize a shared object. This function call returns a promise! const persistence = new Y.IndexedDB()
Y({ const connector = {
db: {
name: 'memory'
},
connector: { connector: {
name: 'websockets-client', name: 'websockets-client',
room: 'codemirror-example' room: 'codemirror-example'
},
sourceDir: '/bower_components',
share: {
codemirror: 'Text' // y.share.codemirror is of type Y.Text
} }
}).then(function (y) { }
window.yCodeMirror = y // initialize a shared object. This function call returns a promise!
const y = Y('codemirror-example', connector, persistence)
window.yCodeMirror = y
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), { var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
mode: 'javascript', mode: 'javascript',
lineNumbers: true lineNumbers: true
})
y.share.codemirror.bindCodeMirror(editor)
}) })
y.share.codemirror.bindCodeMirror(editor)

View File

@@ -1,9 +1,9 @@
import Y from '../src/Y.js' import Y from '../src/Y.js'
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js' import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
import IndexedDBPersistence from '../../y-indexeddb/src/y-indexeddb.js' import extendYIndexedDBPersistence from '../../y-indexeddb/src/y-indexeddb.js'
Y.extend(yWebsocketsClient) Y.extend(yWebsocketsClient)
Y.IndexedDBPersistence = IndexedDBPersistence extendYIndexedDBPersistence(Y)
export default Y export default Y

2
package-lock.json generated
View File

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

View File

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

@@ -25,32 +25,55 @@ export default class AbstractPersistence {
if (cnf === undefined) { if (cnf === undefined) {
cnf = getFreshCnf() cnf = getFreshCnf()
this.ys.set(y, cnf) this.ys.set(y, cnf)
this.init(y) return this.init(y).then(() => {
y.on('afterTransaction', (y, transaction) => { y.on('afterTransaction', (y, transaction) => {
let cnf = this.ys.get(y) let cnf = this.ys.get(y)
if (cnf.len > 0) { if (cnf.len > 0) {
cnf.buffer.setUint32(0, cnf.len) cnf.buffer.setUint32(0, cnf.len)
this.saveUpdate(y, cnf.buffer.createBuffer(), transaction) this.saveUpdate(y, cnf.buffer.createBuffer(), transaction)
let _cnf = getFreshCnf() let _cnf = getFreshCnf()
for (let key in _cnf) { for (let key in _cnf) {
cnf[key] = _cnf[key] cnf[key] = _cnf[key]
}
} }
} })
return this.retrieve(y)
}).then(function () {
return Promise.resolve(cnf)
}) })
} } else {
return this.retrieve(y).then(function () {
return Promise.resolve(cnf) return Promise.resolve(cnf)
}) }
} }
deinit (y) { deinit (y) {
this.ys.delete(y) this.ys.delete(y)
y.persistence = null
} }
destroy () { destroy () {
this.ys = null this.ys = null
} }
/**
* Remove all persisted data that belongs to a room.
* Automatically destroys all Yjs all Yjs instances that persist to
* the room. If `destroyYjsInstances = false` the persistence functionality
* will be removed from the Yjs instances.
*
* ** Must be overwritten! **
*/
removePersistedData (room, destroyYjsInstances = true) {
this.ys.forEach((cnf, y) => {
if (y.room === room) {
if (destroyYjsInstances) {
y.destroy()
} else {
this.deinit(y)
}
}
})
}
/* overwrite */ /* overwrite */
saveUpdate (buffer) { saveUpdate (buffer) {
} }
@@ -75,17 +98,17 @@ export default class AbstractPersistence {
y.transact(function () { y.transact(function () {
if (model != null) { if (model != null) {
fromBinary(y, new BinaryDecoder(new Uint8Array(model))) fromBinary(y, new BinaryDecoder(new Uint8Array(model)))
y._setContentReady()
} }
if (updates != null) { if (updates != null) {
for (let i = 0; i < updates.length; i++) { for (let i = 0; i < updates.length; i++) {
integrateRemoteStructs(y, new BinaryDecoder(new Uint8Array(updates[i]))) integrateRemoteStructs(y, new BinaryDecoder(new Uint8Array(updates[i])))
y._setContentReady()
} }
} }
}) })
y.emit('persistenceReady')
}) })
} }
/* overwrite */ /* overwrite */
persist (y) { persist (y) {
return toBinary(y).createBuffer() return toBinary(y).createBuffer()

View File

@@ -1,6 +1,7 @@
export default class NamedEventHandler { export default class NamedEventHandler {
constructor () { constructor () {
this._eventListener = new Map() this._eventListener = new Map()
this._stateListener = new Map()
} }
_getListener (name) { _getListener (name) {
let listeners = this._eventListener.get(name) let listeners = this._eventListener.get(name)
@@ -21,6 +22,20 @@ export default class NamedEventHandler {
let listeners = this._getListener(name) let listeners = this._getListener(name)
listeners.on.add(f) listeners.on.add(f)
} }
_initStateListener (name) {
let state = this._stateListener.get(name)
if (state === undefined) {
state = {}
state.promise = new Promise(function (resolve) {
state.resolve = resolve
})
this._stateListener.set(name, state)
}
return state
}
when (name) {
return this._initStateListener(name).promise
}
off (name, f) { off (name, f) {
if (name == null || f == null) { if (name == null || f == null) {
throw new Error('You must specify event name and function!') throw new Error('You must specify event name and function!')
@@ -32,6 +47,7 @@ export default class NamedEventHandler {
} }
} }
emit (name, ...args) { emit (name, ...args) {
this._initStateListener(name).resolve()
const listener = this._eventListener.get(name) const listener = this._eventListener.get(name)
if (listener !== undefined) { if (listener !== undefined) {
listener.on.forEach(f => f.apply(null, args)) listener.on.forEach(f => f.apply(null, args))

View File

@@ -5,6 +5,7 @@ import { generateUserID } from './Util/generateUserID.js'
import RootID from './Util/RootID.js' import RootID from './Util/RootID.js'
import NamedEventHandler from './Util/NamedEventHandler.js' import NamedEventHandler from './Util/NamedEventHandler.js'
import UndoManager from './Util/UndoManager.js' import UndoManager from './Util/UndoManager.js'
import { integrateRemoteStructs } from './MessageHandler/integrateRemoteStructs.js'
import { messageToString, messageToRoomname } from './MessageHandler/messageToString.js' import { messageToString, messageToRoomname } from './MessageHandler/messageToString.js'
@@ -61,6 +62,15 @@ export default class Y extends NamedEventHandler {
this.emit('content') this.emit('content')
} }
} }
whenContentReady () {
if (this._contentReady) {
return Promise.resolve()
} else {
return new Promise(resolve => {
this.once('content', resolve)
})
}
}
_beforeChange () {} _beforeChange () {}
transact (f, remote = false) { transact (f, remote = false) {
let initialCall = this._transaction === null let initialCall = this._transaction === null
@@ -192,7 +202,8 @@ Y.utils = {
UndoManager, UndoManager,
getRelativePosition, getRelativePosition,
fromRelativePosition, fromRelativePosition,
addType addType,
integrateRemoteStructs
} }
Y.debug = debug Y.debug = debug

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-46 * @version v13.0.0-47
* @license MIT * @license MIT
*/ */
@@ -3591,6 +3591,7 @@ function generateUserID () {
class NamedEventHandler { class NamedEventHandler {
constructor () { constructor () {
this._eventListener = new Map(); this._eventListener = new Map();
this._stateListener = new Map();
} }
_getListener (name) { _getListener (name) {
let listeners = this._eventListener.get(name); let listeners = this._eventListener.get(name);
@@ -3611,6 +3612,20 @@ class NamedEventHandler {
let listeners = this._getListener(name); let listeners = this._getListener(name);
listeners.on.add(f); listeners.on.add(f);
} }
_initStateListener (name) {
let state = this._stateListener.get(name);
if (state === undefined) {
state = {};
state.promise = new Promise(function (resolve) {
state.resolve = resolve;
});
this._stateListener.set(name, state);
}
return state
}
when (name) {
return this._initStateListener(name).promise
}
off (name, f) { off (name, f) {
if (name == null || f == null) { if (name == null || f == null) {
throw new Error('You must specify event name and function!') throw new Error('You must specify event name and function!')
@@ -3622,6 +3637,7 @@ class NamedEventHandler {
} }
} }
emit (name, ...args) { emit (name, ...args) {
this._initStateListener(name).resolve();
const listener = this._eventListener.get(name); const listener = this._eventListener.get(name);
if (listener !== undefined) { if (listener !== undefined) {
listener.on.forEach(f => f.apply(null, args)); listener.on.forEach(f => f.apply(null, args));
@@ -4642,32 +4658,55 @@ class AbstractPersistence {
if (cnf === undefined) { if (cnf === undefined) {
cnf = getFreshCnf(); cnf = getFreshCnf();
this.ys.set(y, cnf); this.ys.set(y, cnf);
this.init(y); return this.init(y).then(() => {
y.on('afterTransaction', (y, transaction) => { y.on('afterTransaction', (y, transaction) => {
let cnf = this.ys.get(y); let cnf = this.ys.get(y);
if (cnf.len > 0) { if (cnf.len > 0) {
cnf.buffer.setUint32(0, cnf.len); cnf.buffer.setUint32(0, cnf.len);
this.saveUpdate(y, cnf.buffer.createBuffer(), transaction); this.saveUpdate(y, cnf.buffer.createBuffer(), transaction);
let _cnf = getFreshCnf(); let _cnf = getFreshCnf();
for (let key in _cnf) { for (let key in _cnf) {
cnf[key] = _cnf[key]; cnf[key] = _cnf[key];
}
} }
} });
}); return this.retrieve(y)
} }).then(function () {
return this.retrieve(y).then(function () { return Promise.resolve(cnf)
})
} else {
return Promise.resolve(cnf) return Promise.resolve(cnf)
}) }
} }
deinit (y) { deinit (y) {
this.ys.delete(y); this.ys.delete(y);
y.persistence = null;
} }
destroy () { destroy () {
this.ys = null; this.ys = null;
} }
/**
* Remove all persisted data that belongs to a room.
* Automatically destroys all Yjs all Yjs instances that persist to
* the room. If `destroyYjsInstances = false` the persistence functionality
* will be removed from the Yjs instances.
*
* ** Must be overwritten! **
*/
removePersistedData (room, destroyYjsInstances = true) {
this.ys.forEach((cnf, y) => {
if (y.room === room) {
if (destroyYjsInstances) {
y.destroy();
} else {
this.deinit(y);
}
}
});
}
/* overwrite */ /* overwrite */
saveUpdate (buffer) { saveUpdate (buffer) {
} }
@@ -4692,17 +4731,17 @@ class AbstractPersistence {
y.transact(function () { y.transact(function () {
if (model != null) { if (model != null) {
fromBinary(y, new BinaryDecoder(new Uint8Array(model))); fromBinary(y, new BinaryDecoder(new Uint8Array(model)));
y._setContentReady();
} }
if (updates != null) { if (updates != null) {
for (let i = 0; i < updates.length; i++) { for (let i = 0; i < updates.length; i++) {
integrateRemoteStructs(y, new BinaryDecoder(new Uint8Array(updates[i]))); integrateRemoteStructs(y, new BinaryDecoder(new Uint8Array(updates[i])));
y._setContentReady();
} }
} }
}); });
y.emit('persistenceReady');
}); });
} }
/* overwrite */ /* overwrite */
persist (y) { persist (y) {
return toBinary(y).createBuffer() return toBinary(y).createBuffer()
@@ -4749,6 +4788,15 @@ class Y$1 extends NamedEventHandler {
this.emit('content'); this.emit('content');
} }
} }
whenContentReady () {
if (this._contentReady) {
return Promise.resolve()
} else {
return new Promise(resolve => {
this.once('content', resolve);
})
}
}
_beforeChange () {} _beforeChange () {}
transact (f, remote = false) { transact (f, remote = false) {
let initialCall = this._transaction === null; let initialCall = this._transaction === null;
@@ -4880,7 +4928,8 @@ Y$1.utils = {
UndoManager, UndoManager,
getRelativePosition, getRelativePosition,
fromRelativePosition, fromRelativePosition,
addType: addStruct addType: addStruct,
integrateRemoteStructs
}; };
Y$1.debug = browser; Y$1.debug = browser;

File diff suppressed because one or more lines are too long

11533
y.test.js

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long