diff --git a/.eslintrc b/.eslintrc index 38807764..35eecedd 100644 --- a/.eslintrc +++ b/.eslintrc @@ -33,6 +33,7 @@ "compareAllUsers": true, "createUsers": true, "getRandomNumber": true, - "applyRandomTransactions": true + "applyRandomTransactions": true, + "CustomType": true } } diff --git a/src/OperationStore.js b/src/OperationStore.js index 501759b3..60daa893 100644 --- a/src/OperationStore.js +++ b/src/OperationStore.js @@ -9,7 +9,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars if (t == null) { var op = yield* this.getOperation(id); if (op != null) { - t = yield* Y[op.type].create.call(this, this.store, op); + t = yield* Y[op.type].initType.call(this, this.store, op); this.store.initializedTypes[sid] = t; } } @@ -17,7 +17,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars } *createType (model) { var sid = JSON.stringify(model.id); - var t = yield* Y[model.type].create(this.store, model); + var t = yield* Y[model.type].initType.call(this, this.store, model); this.store.initializedTypes[sid] = t; return t; } diff --git a/src/Types/Array.js b/src/Types/Array.js index 4e35dcce..e4ab55b7 100644 --- a/src/Types/Array.js +++ b/src/Types/Array.js @@ -155,23 +155,26 @@ } } - Y.Array = function* _YArray(){ - var model = { - start: null, - end: null, - struct: "List", - type: "Array", - id: this.store.getNextOpId() - }; - yield* this.applyCreatedOperations([model]); - return yield* this.createType(model); - }; - Y.Array.create = function* YArrayCreate(os, model){ - var valArray = []; - var idArray = yield* Y.Struct.List.map.call(this, model, function(c){ - valArray.push(c.content); - return JSON.stringify(c.id); - }); - return new YArray(os, model.id, idArray, valArray); - }; + Y.Array = new CustomType({ + class: YArray, + createType: function* YArrayCreator () { + var model = { + start: null, + end: null, + struct: "List", + type: "Array", + id: this.store.getNextOpId() + }; + yield* this.applyCreatedOperations([model]); + return yield* this.createType(model); + }, + initType: function* YArrayInitializer(os, model){ + var valArray = []; + var idArray = yield* Y.Struct.List.map.call(this, model, function(c){ + valArray.push(c.content); + return JSON.stringify(c.id); + }); + return new YArray(os, model.id, idArray, valArray); + } + }); })(); diff --git a/src/Types/Map.js b/src/Types/Map.js index fc3b553f..b1337c5e 100644 --- a/src/Types/Map.js +++ b/src/Types/Map.js @@ -1,92 +1,5 @@ - -var GeneratorFunction = (function*(){}).constructor; - -class EventHandler { - constructor (onevent) { - this.waiting = []; - this.awaiting = 0; - this.onevent = onevent; - this.userEventListeners = []; - } - receivedOp (op) { - if (this.awaiting <= 0) { - this.onevent([op]); - } else { - this.waiting.push(copyObject(op)); - } - } - awaitAndPrematurelyCall (ops) { - this.awaiting++; - this.onevent(ops); - } - addUserEventListener (f) { - this.userEventListeners.push(f); - } - removeUserEventListener (f) { - this.userEventListeners = this.userEventListeners.filter(function(g){ - return f !== g; - }); - } - removeAllUserEventListeners () { - this.userEventListeners = []; - } - callUserEventListeners (event) { - for (var i in this.userEventListeners) { - try { - this.userEventListeners[i](event); - } catch (e) { - console.log("User events must not throw Errors!");//eslint-disable-line - } - } - } - awaitedLastInserts (n) { - var ops = this.waiting.splice(this.waiting.length - n); - for (var oid = 0; oid < ops.length; oid++) { - var op = ops[oid]; - for (var i = this.waiting.length - 1; i >= 0; i--) { - let w = this.waiting[i]; - if (compareIds(op.left, w.id)) { - // include the effect of op in w - w.right = op.id; - // exclude the effect of w in op - op.left = w.left; - } else if (compareIds(op.right, w.id)) { - // similar.. - w.left = op.id; - op.right = w.right; - } - } - } - this.tryCallEvents(); - } - awaitedLastDeletes (n, newLeft) { - var ops = this.waiting.splice(this.waiting.length - n); - for (var j in ops) { - var del = ops[j]; - if (newLeft != null) { - for (var i in this.waiting) { - let w = this.waiting[i]; - // We will just care about w.left - if (compareIds(del.target, w.left)) { - del.left = newLeft; - } - } - } - } - this.tryCallEvents(); - } - tryCallEvents () { - this.awaiting--; - if (this.awaiting <= 0 && this.waiting.length > 0) { - var events = this.waiting; - this.waiting = []; - this.onevent(events); - } - } - -} (function(){ - class Map { + class YMap { constructor (os, model) { this._model = model.id; this.os = os; @@ -210,10 +123,10 @@ class EventHandler { struct: "Insert" }; var def = Promise.defer(); - if ( value != null && value.constructor === GeneratorFunction) { + if ( value instanceof CustomType) { // construct a new type this.os.requestTransaction(function*(){ - var type = yield* value.call(this); + var type = yield* value.createType.call(this); insert.opContent = type._model; insert.id = this.store.getNextOpId(); yield* this.applyCreatedOperations([insert]); @@ -243,18 +156,20 @@ class EventHandler { this.eventHandler.receivedOp(op); } } - - Y.Map = function* YMap(){ - var model = { - map: {}, - struct: "Map", - type: "Map", - id: this.store.getNextOpId() - }; - yield* this.applyCreatedOperations([model]); - return yield* this.createType(model); - }; - Y.Map.create = function* YMapCreate(os, model){ - return new Map(os, model); - }; + Y.Map = new CustomType({ + class: YMap, + createType: function* YMapCreator(){ + var model = { + map: {}, + struct: "Map", + type: "Map", + id: this.store.getNextOpId() + }; + yield* this.applyCreatedOperations([model]); + return yield* this.createType(model); + }, + initType: function* YMapInitializer(os, model){ + return new YMap(os, model); + } + }); })(); diff --git a/src/Types/TextBind.js b/src/Types/TextBind.js new file mode 100644 index 00000000..e69de29b diff --git a/src/Utils.js b/src/Utils.js new file mode 100644 index 00000000..c24c59fc --- /dev/null +++ b/src/Utils.js @@ -0,0 +1,100 @@ + +var GeneratorFunction = (function*(){}).constructor;//eslint-disable-line + +class EventHandler { //eslint-disable-line + constructor (onevent) { + this.waiting = []; + this.awaiting = 0; + this.onevent = onevent; + this.userEventListeners = []; + } + receivedOp (op) { + if (this.awaiting <= 0) { + this.onevent([op]); + } else { + this.waiting.push(copyObject(op)); + } + } + awaitAndPrematurelyCall (ops) { + this.awaiting++; + this.onevent(ops); + } + addUserEventListener (f) { + this.userEventListeners.push(f); + } + removeUserEventListener (f) { + this.userEventListeners = this.userEventListeners.filter(function(g){ + return f !== g; + }); + } + removeAllUserEventListeners () { + this.userEventListeners = []; + } + callUserEventListeners (event) { + for (var i in this.userEventListeners) { + try { + this.userEventListeners[i](event); + } catch (e) { + console.log("User events must not throw Errors!");//eslint-disable-line + } + } + } + awaitedLastInserts (n) { + var ops = this.waiting.splice(this.waiting.length - n); + for (var oid = 0; oid < ops.length; oid++) { + var op = ops[oid]; + for (var i = this.waiting.length - 1; i >= 0; i--) { + let w = this.waiting[i]; + if (compareIds(op.left, w.id)) { + // include the effect of op in w + w.right = op.id; + // exclude the effect of w in op + op.left = w.left; + } else if (compareIds(op.right, w.id)) { + // similar.. + w.left = op.id; + op.right = w.right; + } + } + } + this.tryCallEvents(); + } + awaitedLastDeletes (n, newLeft) { + var ops = this.waiting.splice(this.waiting.length - n); + for (var j in ops) { + var del = ops[j]; + if (newLeft != null) { + for (var i in this.waiting) { + let w = this.waiting[i]; + // We will just care about w.left + if (compareIds(del.target, w.left)) { + del.left = newLeft; + } + } + } + } + this.tryCallEvents(); + } + tryCallEvents () { + this.awaiting--; + if (this.awaiting <= 0 && this.waiting.length > 0) { + var events = this.waiting; + this.waiting = []; + this.onevent(events); + } + } +} + +class CustomType { //eslint-disable-line + constructor (def) { + if (def.createType == null + || def.initType == null + || def.class == null + ) { + throw new Error("Custom type was not initialized correctly!"); + } + this.createType = def.createType; + this.initType = def.initType; + this.class = def.class; + } +}