switched to *standard* coding style

This commit is contained in:
Kevin Jahns
2015-07-21 17:14:03 +02:00
parent ee116b8ca4
commit ee983ceff6
26 changed files with 2067 additions and 2204 deletions

View File

@@ -1,86 +1,85 @@
/* global EventHandler, Y, CustomType, Struct */
(function(){
;(function () {
class YArray {
constructor (os, _model, idArray, valArray) {
this.os = os;
this._model = _model;
this.os = os
this._model = _model
// Array of all the operation id's
this.idArray = idArray;
this.idArray = idArray
// Array of all the values
this.valArray = valArray;
this.eventHandler = new EventHandler( ops =>{
var userEvents = [];
this.valArray = valArray
this.eventHandler = new EventHandler(ops => {
var userEvents = []
for (var i in ops) {
var op = ops[i];
if (op.struct === "Insert") {
let pos;
var op = ops[i]
if (op.struct === 'Insert') {
let pos
// we check op.left only!,
// because op.right might not be defined when this is called
if (op.left === null) {
pos = 0;
pos = 0
} else {
var sid = JSON.stringify(op.left);
pos = this.idArray.indexOf(sid) + 1;
var sid = JSON.stringify(op.left)
pos = this.idArray.indexOf(sid) + 1
if (pos <= 0) {
throw new Error("Unexpected operation!");
throw new Error('Unexpected operation!')
}
}
this.idArray.splice(pos, 0, JSON.stringify(op.id));
this.valArray.splice(pos, 0, op.content);
this.idArray.splice(pos, 0, JSON.stringify(op.id))
this.valArray.splice(pos, 0, op.content)
userEvents.push({
type: "insert",
type: 'insert',
object: this,
index: pos,
length: 1
});
} else if (op.struct === "Delete") {
let pos = this.idArray.indexOf(JSON.stringify(op.target));
this.idArray.splice(pos, 1);
this.valArray.splice(pos, 1);
})
} else if (op.struct === 'Delete') {
let pos = this.idArray.indexOf(JSON.stringify(op.target))
this.idArray.splice(pos, 1)
this.valArray.splice(pos, 1)
userEvents.push({
type: "delete",
type: 'delete',
object: this,
index: pos,
length: 1
});
})
} else {
throw new Error("Unexpected struct!");
throw new Error('Unexpected struct!')
}
}
this.eventHandler.callUserEventListeners(userEvents);
});
this.eventHandler.callUserEventListeners(userEvents)
})
}
get length () {
return this.idArray.length;
return this.idArray.length
}
get (pos) {
if (pos == null || typeof pos !== "number") {
throw new Error("pos must be a number!");
if (pos == null || typeof pos !== 'number') {
throw new Error('pos must be a number!')
}
return this.valArray[pos];
return this.valArray[pos]
}
toArray() {
return this.valArray.slice();
toArray () {
return this.valArray.slice()
}
insert (pos, contents) {
if (typeof pos !== "number") {
throw new Error("pos must be a number!");
if (typeof pos !== 'number') {
throw new Error('pos must be a number!')
}
if (!(contents instanceof Array)) {
throw new Error("contents must be an Array of objects!");
throw new Error('contents must be an Array of objects!')
}
if (contents.length === 0) {
return;
return
}
if (pos > this.idArray.length || pos < 0) {
throw new Error("This position exceeds the range of the array!");
throw new Error('This position exceeds the range of the array!')
}
var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1]);
var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1])
var ops = [];
var prevId = mostLeft;
var ops = []
var prevId = mostLeft
for (var i = 0; i < contents.length; i++) {
var op = {
left: prevId,
@@ -90,97 +89,97 @@
// at the time of creating this operation, and is therefore not defined in idArray
parent: this._model,
content: contents[i],
struct: "Insert",
struct: 'Insert',
id: this.os.getNextOpId()
};
ops.push(op);
prevId = op.id;
}
ops.push(op)
prevId = op.id
}
var eventHandler = this.eventHandler;
eventHandler.awaitAndPrematurelyCall(ops);
this.os.requestTransaction(function*(){
var eventHandler = this.eventHandler
eventHandler.awaitAndPrematurelyCall(ops)
this.os.requestTransaction(function *() {
// now we can set the right reference.
var mostRight;
var mostRight
if (mostLeft != null) {
mostRight = (yield* this.getOperation(mostLeft)).right;
mostRight = (yield* this.getOperation(mostLeft)).right
} else {
mostRight = (yield* this.getOperation(ops[0].parent)).start;
mostRight = (yield* this.getOperation(ops[0].parent)).start
}
for (var j in ops) {
ops[j].right = mostRight;
ops[j].right = mostRight
}
yield* this.applyCreatedOperations(ops);
eventHandler.awaitedLastInserts(ops.length);
});
yield* this.applyCreatedOperations(ops)
eventHandler.awaitedLastInserts(ops.length)
})
}
delete (pos, length = 1) {
if (typeof length !== "number") {
throw new Error("pos must be a number!");
if (typeof length !== 'number') {
throw new Error('pos must be a number!')
}
if (typeof pos !== "number") {
throw new Error("pos must be a number!");
if (typeof pos !== 'number') {
throw new Error('pos must be a number!')
}
if (pos + length > this.idArray.length || pos < 0 || length < 0) {
throw new Error("The deletion range exceeds the range of the array!");
throw new Error('The deletion range exceeds the range of the array!')
}
if (length === 0) {
return;
return
}
var eventHandler = this.eventHandler;
var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null;
var dels = [];
var eventHandler = this.eventHandler
var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null
var dels = []
for (var i = 0; i < length; i++) {
dels.push({
target: JSON.parse(this.idArray[pos + i]),
struct: "Delete"
});
struct: 'Delete'
})
}
eventHandler.awaitAndPrematurelyCall(dels);
this.os.requestTransaction(function*(){
yield* this.applyCreatedOperations(dels);
eventHandler.awaitedLastDeletes(dels.length, newLeft);
});
eventHandler.awaitAndPrematurelyCall(dels)
this.os.requestTransaction(function *() {
yield* this.applyCreatedOperations(dels)
eventHandler.awaitedLastDeletes(dels.length, newLeft)
})
}
observe (f) {
this.eventHandler.addUserEventListener(f);
this.eventHandler.addUserEventListener(f)
}
*_changed (transaction, op) {
if (op.struct === "Insert") {
var l = op.left;
var left;
* _changed (transaction, op) {
if (op.struct === 'Insert') {
var l = op.left
var left
while (l != null) {
left = yield* transaction.getOperation(l);
left = yield* transaction.getOperation(l)
if (!left.deleted) {
break;
break
}
l = left.left;
l = left.left
}
op.left = l;
op.left = l
}
this.eventHandler.receivedOp(op);
this.eventHandler.receivedOp(op)
}
}
Y.Array = new CustomType({
class: YArray,
createType: function* YArrayCreator () {
createType: function * YArrayCreator () {
var model = {
start: null,
end: null,
struct: "List",
type: "Array",
struct: 'List',
type: 'Array',
id: this.store.getNextOpId()
};
yield* this.applyCreatedOperations([model]);
return yield* this.createType(model);
}
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);
initType: function * YArrayInitializer (os, model) {
var valArray = []
var idArray = yield* 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)
}
});
})();
})
})()

View File

@@ -1,143 +1,145 @@
/* @flow */
/*eslint-env browser,jasmine */
/* global createUsers, wait, Y, compareAllUsers, getRandomNumber, applyRandomTransactions */
/* eslint-env browser,jasmine */
var numberOfYArrayTests = 80;
var numberOfYArrayTests = 80
describe("Array Type", function(){
var y1, y2, y3, flushAll;
describe('Array Type', function () {
var y1, y2, y3, flushAll
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000;
beforeEach(async function(done){
await createUsers(this, 5);
y1 = this.users[0].root;
y2 = this.users[1].root;
y3 = this.users[2].root;
flushAll = this.users[0].connector.flushAll;
done();
});
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000
beforeEach(async function (done) {
await createUsers(this, 5)
y1 = this.users[0].root
y2 = this.users[1].root
y3 = this.users[2].root
flushAll = this.users[0].connector.flushAll
done()
})
afterEach(async function(done) {
await compareAllUsers(this.users);
done();
});
await compareAllUsers(this.users)
done()
})
describe("Basic tests", function(){
it("insert three elements, try re-get property", async function(done){
var array = await y1.set("Array", Y.Array);
array.insert(0, [1, 2, 3]);
array = await y1.get("Array"); // re-get property
expect(array.toArray()).toEqual([1, 2, 3]);
done();
});
it("Basic insert in array (handle three conflicts)", async function(done){
var l1, l2, l3;
await y1.set("Array", Y.Array);
await flushAll();
(l1 = await y1.get("Array")).insert(0, [0]);
(l2 = await y2.get("Array")).insert(0, [1]);
(l3 = await y3.get("Array")).insert(0, [2]);
await flushAll();
expect(l1.toArray()).toEqual(l2.toArray());
expect(l2.toArray()).toEqual(l3.toArray());
done();
});
it("Basic insert&delete in array (handle three conflicts)", async function(done){
var l1, l2, l3;
l1 = await y1.set("Array", Y.Array);
l1.insert(0, ["x", "y", "z"]);
await flushAll();
l1.insert(1, [0]);
l2 = await y2.get("Array");
l2.delete(0);
l2.delete(1);
l3 = await y3.get("Array");
l3.insert(1, [2]);
await flushAll();
expect(l1.toArray()).toEqual(l2.toArray());
expect(l2.toArray()).toEqual(l3.toArray());
expect(l2.toArray()).toEqual([0, 2, "y"]);
done();
});
it("Basic insert. Then delete the whole array", async function(done){
var l1, l2, l3;
l1 = await y1.set("Array", Y.Array);
l1.insert(0, ["x", "y", "z"]);
await flushAll();
l1.delete(0, 3);
l2 = await y2.get("Array");
l3 = await y3.get("Array");
await flushAll();
expect(l1.toArray()).toEqual(l2.toArray());
expect(l2.toArray()).toEqual(l3.toArray());
expect(l2.toArray()).toEqual([]);
done();
});
it("throw insert & delete events", async function(done){
var array = await this.users[0].root.set("array", Y.Array);
var event;
array.observe(function(e){
event = e;
});
array.insert(0, [0]);
describe('Basic tests', function () {
it('insert three elements, try re-get property', async function (done) {
var array = await y1.set('Array', Y.Array)
array.insert(0, [1, 2, 3])
array = await y1.get('Array') // re-get property
expect(array.toArray()).toEqual([1, 2, 3])
done()
})
it('Basic insert in array (handle three conflicts)', async function (done) {
await y1.set('Array', Y.Array)
await flushAll()
var l1 = await y1.get('Array')
l1.insert(0, [0])
var l2 = await y2.get('Array')
l2.insert(0, [1])
var l3 = await y3.get('Array')
l3.insert(0, [2])
await flushAll()
expect(l1.toArray()).toEqual(l2.toArray())
expect(l2.toArray()).toEqual(l3.toArray())
done()
})
it('Basic insert&delete in array (handle three conflicts)', async function (done) {
var l1, l2, l3
l1 = await y1.set('Array', Y.Array)
l1.insert(0, ['x', 'y', 'z'])
await flushAll()
l1.insert(1, [0])
l2 = await y2.get('Array')
l2.delete(0)
l2.delete(1)
l3 = await y3.get('Array')
l3.insert(1, [2])
await flushAll()
expect(l1.toArray()).toEqual(l2.toArray())
expect(l2.toArray()).toEqual(l3.toArray())
expect(l2.toArray()).toEqual([0, 2, 'y'])
done()
})
it('Basic insert. Then delete the whole array', async function (done) {
var l1, l2, l3
l1 = await y1.set('Array', Y.Array)
l1.insert(0, ['x', 'y', 'z'])
await flushAll()
l1.delete(0, 3)
l2 = await y2.get('Array')
l3 = await y3.get('Array')
await flushAll()
expect(l1.toArray()).toEqual(l2.toArray())
expect(l2.toArray()).toEqual(l3.toArray())
expect(l2.toArray()).toEqual([])
done()
})
it('throw insert & delete events', async function (done) {
var array = await this.users[0].root.set('array', Y.Array)
var event
array.observe(function (e) {
event = e
})
array.insert(0, [0])
expect(event).toEqual([{
type: "insert",
type: 'insert',
object: array,
index: 0,
length: 1
}]);
array.delete(0);
}])
array.delete(0)
expect(event).toEqual([{
type: "delete",
type: 'delete',
object: array,
index: 0,
length: 1
}]);
await wait(50);
done();
});
});
describe(`${numberOfYArrayTests} Random tests`, function(){
}])
await wait(50)
done()
})
})
describe(`${numberOfYArrayTests} Random tests`, function () {
var randomArrayTransactions = [
function insert (array) {
array.insert(getRandomNumber(array.toArray().length), [getRandomNumber()]);
array.insert(getRandomNumber(array.toArray().length), [getRandomNumber()])
},
function _delete (array) {
var length = array.toArray().length;
var length = array.toArray().length
if (length > 0) {
array.delete(getRandomNumber(length - 1));
array.delete(getRandomNumber(length - 1))
}
}
];
function compareArrayValues(arrays){
var firstArray;
]
function compareArrayValues (arrays) {
var firstArray
for (var l of arrays) {
var val = l.toArray();
var val = l.toArray()
if (firstArray == null) {
firstArray = val;
firstArray = val
} else {
expect(val).toEqual(firstArray);
expect(val).toEqual(firstArray)
}
}
}
beforeEach(async function(done){
await this.users[0].root.set("Array", Y.Array);
await flushAll();
beforeEach(async function (done) {
await this.users[0].root.set('Array', Y.Array)
await flushAll()
var promises = [];
var promises = []
for (var u = 0; u < this.users.length; u++) {
promises.push(this.users[u].root.get("Array"));
promises.push(this.users[u].root.get('Array'))
}
this.arrays = await Promise.all(promises);
done();
});
it("arrays.length equals users.length", async function(done){
expect(this.arrays.length).toEqual(this.users.length);
done();
});
it(`succeed after ${numberOfYArrayTests} actions`, async function(done){
await applyRandomTransactions(this.users, this.arrays, randomArrayTransactions, numberOfYArrayTests);
await flushAll();
await compareArrayValues(this.arrays);
done();
});
});
});
this.arrays = await Promise.all(promises)
done()
})
it('arrays.length equals users.length', async function (done) { // eslint-disable-line
expect(this.arrays.length).toEqual(this.users.length)
done()
})
it(`succeed after ${numberOfYArrayTests} actions`, async function (done) {
await applyRandomTransactions(this.users, this.arrays, randomArrayTransactions, numberOfYArrayTests)
await flushAll()
await compareArrayValues(this.arrays)
done()
})
})
})

View File

@@ -1,76 +1,78 @@
(function(){
/* global EventHandler, Y, CustomType, copyObject, compareIds */
;(function () {
class YMap {
constructor (os, model) {
this._model = model.id;
this.os = os;
this.map = copyObject(model.map);
this.contents = {};
this.opContents = {};
this.eventHandler = new EventHandler( ops =>{
var userEvents = [];
this._model = model.id
this.os = os
this.map = copyObject(model.map)
this.contents = {}
this.opContents = {}
this.eventHandler = new EventHandler(ops => {
var userEvents = []
for (var i in ops) {
var op = ops[i];
var oldValue;
var op = ops[i]
var oldValue
// key is the name to use to access (op)content
var key = op.struct === "Delete" ? op.key : op.parentSub;
var key = op.struct === 'Delete' ? op.key : op.parentSub
// compute oldValue
if (this.opContents[key] != null) {
let prevType = this.opContents[key];
oldValue = () => { //eslint-disable-line
let def = Promise.defer();
this.os.requestTransaction(function*(){//eslint-disable-line
def.resolve(yield* this.getType(prevType));
});
return def.promise;
};
let prevType = this.opContents[key]
oldValue = () => {// eslint-disable-line
let def = Promise.defer()
this.os.requestTransaction(function *() {// eslint-disable-line
def.resolve(yield* this.getType(prevType))
})
return def.promise
}
} else {
oldValue = this.contents[key];
oldValue = this.contents[key]
}
// compute op event
if (op.struct === "Insert"){
if (op.struct === 'Insert') {
if (op.left === null) {
if (op.opContent != null) {
delete this.contents[key];
this.opContents[key] = op.opContent;
delete this.contents[key]
this.opContents[key] = op.opContent
} else {
delete this.opContents[key];
this.contents[key] = op.content;
delete this.opContents[key]
this.contents[key] = op.content
}
this.map[key] = op.id;
this.map[key] = op.id
var insertEvent = {
name: key,
object: this
};
if (oldValue === undefined) {
insertEvent.type = "add";
} else {
insertEvent.type = "update";
insertEvent.oldValue = oldValue;
}
userEvents.push(insertEvent);
if (oldValue === undefined) {
insertEvent.type = 'add'
} else {
insertEvent.type = 'update'
insertEvent.oldValue = oldValue
}
userEvents.push(insertEvent)
}
} else if (op.struct === "Delete") {
} else if (op.struct === 'Delete') {
if (compareIds(this.map[key], op.target)) {
if (this.opContents[key] != null) {
delete this.opContents[key];
delete this.opContents[key]
} else {
delete this.contents[key];
delete this.contents[key]
}
var deleteEvent = {
name: key,
object: this,
oldValue: oldValue,
type: "delete"
};
userEvents.push(deleteEvent);
type: 'delete'
}
userEvents.push(deleteEvent)
}
} else {
throw new Error("Unexpected Operation!");
throw new Error('Unexpected Operation!')
}
}
this.eventHandler.callUserEventListeners(userEvents);
});
this.eventHandler.callUserEventListeners(userEvents)
})
}
get (key) {
// return property.
@@ -78,34 +80,34 @@
// if property is a type, return a promise
if (this.opContents[key] == null) {
if (key == null) {
return copyObject(this.contents);
return copyObject(this.contents)
} else {
return this.contents[key];
return this.contents[key]
}
} else {
let def = Promise.defer();
var oid = this.opContents[key];
this.os.requestTransaction(function*(){
def.resolve(yield* this.getType(oid));
});
return def.promise;
let def = Promise.defer()
var oid = this.opContents[key]
this.os.requestTransaction(function *() {
def.resolve(yield* this.getType(oid))
})
return def.promise
}
}
delete (key) {
var right = this.map[key];
var right = this.map[key]
if (right != null) {
var del = {
target: right,
struct: "Delete"
};
var eventHandler = this.eventHandler;
var modDel = copyObject(del);
modDel.key = key;
eventHandler.awaitAndPrematurelyCall([modDel]);
this.os.requestTransaction(function*(){
yield* this.applyCreatedOperations([del]);
eventHandler.awaitedLastDeletes(1);
});
struct: 'Delete'
}
var eventHandler = this.eventHandler
var modDel = copyObject(del)
modDel.key = key
eventHandler.awaitAndPrematurelyCall([modDel])
this.os.requestTransaction(function *() {
yield* this.applyCreatedOperations([del])
eventHandler.awaitedLastDeletes(1)
})
}
}
set (key, value) {
@@ -113,108 +115,108 @@
// if property is a type, return a promise
// if not, apply immediately on this type an call event
var right = this.map[key] || null;
var right = this.map[key] || null
var insert = {
left: null,
right: right,
origin: null,
parent: this._model,
parentSub: key,
struct: "Insert"
};
var def = Promise.defer();
if ( value instanceof CustomType) {
// construct a new type
this.os.requestTransaction(function*(){
var type = yield* value.createType.call(this);
insert.opContent = type._model;
insert.id = this.store.getNextOpId();
yield* this.applyCreatedOperations([insert]);
def.resolve(type);
});
} else {
insert.content = value;
insert.id = this.os.getNextOpId();
var eventHandler = this.eventHandler;
eventHandler.awaitAndPrematurelyCall([insert]);
this.os.requestTransaction(function*(){
yield* this.applyCreatedOperations([insert]);
eventHandler.awaitedLastInserts(1);
});
def.resolve(value);
struct: 'Insert'
}
return def.promise;
var def = Promise.defer()
if (value instanceof CustomType) {
// construct a new type
this.os.requestTransaction(function *() {
var type = yield* value.createType.call(this)
insert.opContent = type._model
insert.id = this.store.getNextOpId()
yield* this.applyCreatedOperations([insert])
def.resolve(type)
})
} else {
insert.content = value
insert.id = this.os.getNextOpId()
var eventHandler = this.eventHandler
eventHandler.awaitAndPrematurelyCall([insert])
this.os.requestTransaction(function *() {
yield* this.applyCreatedOperations([insert])
eventHandler.awaitedLastInserts(1)
})
def.resolve(value)
}
return def.promise
}
observe (f) {
this.eventHandler.addUserEventListener(f);
this.eventHandler.addUserEventListener(f)
}
unobserve (f) {
this.eventHandler.removeUserEventListener(f);
this.eventHandler.removeUserEventListener(f)
}
observePath (path, f) {
var self = this;
var self = this
if (path.length === 0) {
this.observe(f);
return Promise.resolve(function(){
self.unobserve(f);
});
this.observe(f)
return Promise.resolve(function () {
self.unobserve(f)
})
} else {
var deleteChildObservers;
var resetObserverPath = function(){
var promise = self.get(path[0]);
var deleteChildObservers
var resetObserverPath = function () {
var promise = self.get(path[0])
if (!promise instanceof Promise) {
// its either not defined or a premitive value
promise = self.set(path[0], Y.Map);
promise = self.set(path[0], Y.Map)
}
return promise.then(function(map){
return map.observePath(path.slice(1), f);
}).then(function(_deleteChildObservers){
deleteChildObservers = _deleteChildObservers;
return Promise.resolve();
});
};
var observer = function(events){
return promise.then(function (map) {
return map.observePath(path.slice(1), f)
}).then(function (_deleteChildObservers) {
deleteChildObservers = _deleteChildObservers
return Promise.resolve()
})
}
var observer = function (events) {
for (var e in events) {
var event = events[e];
var event = events[e]
if (event.name === path[0]) {
deleteChildObservers();
if (event.type === "add" || event.type === "update") {
resetObserverPath();
deleteChildObservers()
if (event.type === 'add' || event.type === 'update') {
resetObserverPath()
}
}
}
};
self.observe(observer);
}
self.observe(observer)
return resetObserverPath().then(
Promise.resolve(function(){
deleteChildObservers();
self.unobserve(observer);
Promise.resolve(function () {
deleteChildObservers()
self.unobserve(observer)
})
);
)
}
}
*_changed (transaction, op) {
if (op.struct === "Delete") {
op.key = (yield* transaction.getOperation(op.target)).parentSub;
* _changed (transaction, op) {
if (op.struct === 'Delete') {
op.key = (yield* transaction.getOperation(op.target)).parentSub
}
this.eventHandler.receivedOp(op);
this.eventHandler.receivedOp(op)
}
}
Y.Map = new CustomType({
class: YMap,
createType: function* YMapCreator(){
createType: function * YMapCreator () {
var model = {
map: {},
struct: "Map",
type: "Map",
struct: 'Map',
type: 'Map',
id: this.store.getNextOpId()
};
yield* this.applyCreatedOperations([model]);
return yield* this.createType(model);
}
yield* this.applyCreatedOperations([model])
return yield* this.createType(model)
},
initType: function* YMapInitializer(os, model){
return new YMap(os, model);
initType: function * YMapInitializer (os, model) { // eslint-disable-line
return new YMap(os, model)
}
});
})();
})
})()

View File

@@ -1,207 +1,207 @@
/* @flow */
/*eslint-env browser,jasmine */
/* global createUsers, Y, compareAllUsers, getRandomNumber, applyRandomTransactions */
/* eslint-env browser,jasmine */
var numberOfYMapTests = 100;
var numberOfYMapTests = 100
describe("Map Type", function(){
var y1, y2, y3, y4, flushAll;
describe('Map Type', function () {
var y1, y2, y3, y4, flushAll
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000;
beforeEach(async function(done){
await createUsers(this, 5);
y1 = this.users[0].root;
y2 = this.users[1].root;
y3 = this.users[2].root;
y4 = this.users[3].root;
flushAll = this.users[0].connector.flushAll;
done();
});
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000
beforeEach(async function (done) {
await createUsers(this, 5)
y1 = this.users[0].root
y2 = this.users[1].root
y3 = this.users[2].root
y4 = this.users[3].root
flushAll = this.users[0].connector.flushAll
done()
})
afterEach(async function(done) {
await compareAllUsers(this.users);
done();
}, 5000);
await compareAllUsers(this.users)
done()
}, 5000)
describe("Basic tests", function(){
it("Basic get&set of Map property (converge via sync)", async function(done){
y1.set("stuff", "stuffy");
expect(y1.get("stuff")).toEqual("stuffy");
await flushAll();
describe('Basic tests', function () {
it('Basic get&set of Map property (converge via sync)', async function (done) {
y1.set('stuff', 'stuffy')
expect(y1.get('stuff')).toEqual('stuffy')
await flushAll()
for (var key in this.users) {
var u = this.users[key].root;
expect(u.get("stuff")).toEqual("stuffy");
var u = this.users[key].root
expect(u.get('stuff')).toEqual('stuffy')
}
await compareAllUsers(this.users);
done();
});
it("Map can set custom types (Map)", async function(done){
var map = await y1.set("Map", Y.Map);
map.set("one", 1);
map = await y1.get("Map");
expect(map.get("one")).toEqual(1);
await compareAllUsers(this.users);
done();
});
it("Map can set custom types (Array)", async function(done){
var array = await y1.set("Array", Y.Array);
array.insert(0, [1, 2, 3]);
array = await y1.get("Array");
expect(array.toArray()).toEqual([1, 2, 3]);
await compareAllUsers(this.users);
done();
});
it("Basic get&set of Map property (converge via update)", async function(done){
await flushAll();
y1.set("stuff", "stuffy");
expect(y1.get("stuff")).toEqual("stuffy");
await compareAllUsers(this.users)
done()
})
it('Map can set custom types (Map)', async function (done) {
var map = await y1.set('Map', Y.Map)
map.set('one', 1)
map = await y1.get('Map')
expect(map.get('one')).toEqual(1)
await compareAllUsers(this.users)
done()
})
it('Map can set custom types (Array)', async function (done) {
var array = await y1.set('Array', Y.Array)
array.insert(0, [1, 2, 3])
array = await y1.get('Array')
expect(array.toArray()).toEqual([1, 2, 3])
await compareAllUsers(this.users)
done()
})
it('Basic get&set of Map property (converge via update)', async function (done) {
await flushAll()
y1.set('stuff', 'stuffy')
expect(y1.get('stuff')).toEqual('stuffy')
await flushAll();
await flushAll()
for (var key in this.users) {
var r = this.users[key].root;
expect(r.get("stuff")).toEqual("stuffy");
var r = this.users[key].root
expect(r.get('stuff')).toEqual('stuffy')
}
done();
});
it("Basic get&set of Map property (handle conflict)", async function(done){
await flushAll();
y1.set("stuff", "c0");
done()
})
it('Basic get&set of Map property (handle conflict)', async function (done) {
await flushAll()
y1.set('stuff', 'c0')
y2.set("stuff", "c1");
y2.set('stuff', 'c1')
await flushAll();
await flushAll()
for (var key in this.users) {
var u = this.users[key];
expect(u.root.get("stuff")).toEqual("c0");
var u = this.users[key]
expect(u.root.get('stuff')).toEqual('c0')
}
await compareAllUsers(this.users);
done();
});
it("Basic get&set&delete of Map property (handle conflict)", async function(done){
await flushAll();
y1.set("stuff", "c0");
y1.delete("stuff");
y2.set("stuff", "c1");
await flushAll();
await compareAllUsers(this.users)
done()
})
it('Basic get&set&delete of Map property (handle conflict)', async function (done) {
await flushAll()
y1.set('stuff', 'c0')
y1.delete('stuff')
y2.set('stuff', 'c1')
await flushAll()
for (var key in this.users) {
var u = this.users[key];
expect(u.root.get("stuff")).toBeUndefined();
var u = this.users[key]
expect(u.root.get('stuff')).toBeUndefined()
}
await compareAllUsers(this.users);
done();
});
it("Basic get&set of Map property (handle three conflicts)", async function(done){
await flushAll();
y1.set("stuff", "c0");
y2.set("stuff", "c1");
y2.set("stuff", "c2");
y3.set("stuff", "c3");
await flushAll();
await compareAllUsers(this.users)
done()
})
it('Basic get&set of Map property (handle three conflicts)', async function (done) {
await flushAll()
y1.set('stuff', 'c0')
y2.set('stuff', 'c1')
y2.set('stuff', 'c2')
y3.set('stuff', 'c3')
await flushAll()
for (var key in this.users) {
var u = this.users[key];
expect(u.root.get("stuff")).toEqual("c0");
var u = this.users[key]
expect(u.root.get('stuff')).toEqual('c0')
}
await compareAllUsers(this.users);
done();
});
it("Basic get&set&delete of Map property (handle three conflicts)", async function(done){
await flushAll();
y1.set("stuff", "c0");
y2.set("stuff", "c1");
y2.set("stuff", "c2");
y3.set("stuff", "c3");
await flushAll();
y1.set("stuff", "deleteme");
y1.delete("stuff");
y2.set("stuff", "c1");
y3.set("stuff", "c2");
y4.set("stuff", "c3");
await flushAll();
await compareAllUsers(this.users)
done()
})
it('Basic get&set&delete of Map property (handle three conflicts)', async function (done) {
await flushAll()
y1.set('stuff', 'c0')
y2.set('stuff', 'c1')
y2.set('stuff', 'c2')
y3.set('stuff', 'c3')
await flushAll()
y1.set('stuff', 'deleteme')
y1.delete('stuff')
y2.set('stuff', 'c1')
y3.set('stuff', 'c2')
y4.set('stuff', 'c3')
await flushAll()
for (var key in this.users) {
var u = this.users[key];
expect(u.root.get("stuff")).toBeUndefined();
var u = this.users[key]
expect(u.root.get('stuff')).toBeUndefined()
}
await compareAllUsers(this.users);
done();
});
it("throws add & update & delete events (with type and primitive content)", async function(done){
var event;
await flushAll();
y1.observe(function(e){
event = e; // just put it on event, should be thrown synchronously anyway
});
y1.set("stuff", 4);
await compareAllUsers(this.users)
done()
})
it('throws add & update & delete events (with type and primitive content)', async function (done) {
var event
await flushAll()
y1.observe(function (e) {
event = e // just put it on event, should be thrown synchronously anyway
})
y1.set('stuff', 4)
expect(event).toEqual([{
type: "add",
type: 'add',
object: y1,
name: "stuff"
}]);
name: 'stuff'
}])
// update, oldValue is in contents
await y1.set("stuff", Y.Array);
await y1.set('stuff', Y.Array)
expect(event).toEqual([{
type: "update",
type: 'update',
object: y1,
name: "stuff",
name: 'stuff',
oldValue: 4
}]);
y1.get("stuff").then(function(replacedArray){
}])
y1.get('stuff').then(function (replacedArray) {
// update, oldValue is in opContents
y1.set("stuff", 5);
var getYArray = event[0].oldValue;
expect(typeof getYArray.constructor === "function").toBeTruthy();
getYArray().then(function(array){
expect(array).toEqual(replacedArray);
y1.set('stuff', 5)
var getYArray = event[0].oldValue
expect(typeof getYArray.constructor === 'function').toBeTruthy()
getYArray().then(function (array) {
expect(array).toEqual(replacedArray)
// delete
y1.delete("stuff");
y1.delete('stuff')
expect(event).toEqual([{
type: "delete",
name: "stuff",
type: 'delete',
name: 'stuff',
object: y1,
oldValue: 5
}]);
done();
});
});
});
});
describe(`${numberOfYMapTests} Random tests`, function(){
}])
done()
})
})
})
})
describe(`${numberOfYMapTests} Random tests`, function () {
var randomMapTransactions = [
function set (map) {
map.set("somekey", getRandomNumber());
map.set('somekey', getRandomNumber())
},
function delete_ (map) {
map.delete("somekey");
map.delete('somekey')
}
];
function compareMapValues(maps){
var firstMap;
]
function compareMapValues (maps) {
var firstMap
for (var map of maps) {
var val = map.get();
var val = map.get()
if (firstMap == null) {
firstMap = val;
firstMap = val
} else {
expect(val).toEqual(firstMap);
expect(val).toEqual(firstMap)
}
}
}
beforeEach(async function(done){
await y1.set("Map", Y.Map);
await flushAll();
beforeEach(async function (done) {
await y1.set('Map', Y.Map)
await flushAll()
var promises = [];
var promises = []
for (var u = 0; u < this.users.length; u++) {
promises.push(this.users[u].root.get("Map"));
promises.push(this.users[u].root.get('Map'))
}
this.maps = await Promise.all(promises);
done();
});
it(`succeed after ${numberOfYMapTests} actions`, async function(done){
await applyRandomTransactions(this.users, this.maps, randomMapTransactions, numberOfYMapTests);
await flushAll();
await compareMapValues(this.maps);
done();
});
});
});
this.maps = await Promise.all(promises)
done()
})
it(`succeed after ${numberOfYMapTests} actions`, async function (done) {
await applyRandomTransactions(this.users, this.maps, randomMapTransactions, numberOfYMapTests)
await flushAll()
await compareMapValues(this.maps)
done()
})
})
})

View File

@@ -1,287 +1,288 @@
/* global Y, CustomType */
(function(){
class YTextBind extends Y.Array.class {
;(function () {
class YTextBind extends Y . Array . class {
constructor (os, _model, idArray, valArray) {
super(os, _model, idArray, valArray);
this.textfields = [];
super(os, _model, idArray, valArray)
this.textfields = []
}
toString () {
return this.valArray.join("");
return this.valArray.join('')
}
insert (pos, content) {
super(pos, content.split(""));
super(pos, content.split(''))
}
bind (textfield, domRoot) {
domRoot = domRoot || window; //eslint-disable-line
if (domRoot.getSelection == null) {
domRoot = window;//eslint-disable-line
}
domRoot = domRoot || window; // eslint-disable-line
if (domRoot.getSelection == null) {
domRoot = window;// eslint-disable-line
}
// don't duplicate!
for (var t in this.textfields) {
if (this.textfields[t] === textfield) {
return;
// don't duplicate!
for (var t in this.textfields) {
if (this.textfields[t] === textfield) {
return
}
}
var creatorToken = false
var word = this
textfield.value = this.toString()
this.textfields.push(textfield)
var createRange, writeRange, writeContent
if (textfield.selectionStart != null && textfield.setSelectionRange != null) {
createRange = function (fix) {
var left = textfield.selectionStart
var right = textfield.selectionEnd
if (fix != null) {
left = fix(left)
right = fix(right)
}
return {
left: left,
right: right
}
}
var creatorToken = false;
writeRange = function (range) {
writeContent(word.toString())
textfield.setSelectionRange(range.left, range.right)
}
writeContent = function (content) {
textfield.value = content
}
} else {
createRange = function (fix) {
var range = {}
var s = domRoot.getSelection()
var clength = textfield.textContent.length
range.left = Math.min(s.anchorOffset, clength)
range.right = Math.min(s.focusOffset, clength)
if (fix != null) {
range.left = fix(range.left)
range.right = fix(range.right)
}
var editedElement = s.focusNode
if (editedElement === textfield || editedElement === textfield.childNodes[0]) {
range.isReal = true
} else {
range.isReal = false
}
return range
}
var word = this;
textfield.value = this.toString();
this.textfields.push(textfield);
var createRange, writeRange, writeContent;
if(textfield.selectionStart != null && textfield.setSelectionRange != null) {
createRange = function (fix) {
var left = textfield.selectionStart;
var right = textfield.selectionEnd;
if (fix != null) {
left = fix(left);
right = fix(right);
writeRange = function (range) {
writeContent(word.toString())
var textnode = textfield.childNodes[0]
if (range.isReal && textnode != null) {
if (range.left < 0) {
range.left = 0
}
return {
left: left,
right: right
};
};
writeRange = function (range) {
writeContent(word.toString());
textfield.setSelectionRange(range.left, range.right);
};
writeContent = function (content){
textfield.value = content;
};
range.right = Math.max(range.left, range.right)
if (range.right > textnode.length) {
range.right = textnode.length
}
range.left = Math.min(range.left, range.right)
var r = document.createRange(); // eslint-disable-line
r.setStart(textnode, range.left)
r.setEnd(textnode, range.right)
var s = window.getSelection(); // eslint-disable-line
s.removeAllRanges()
s.addRange(r)
}
}
writeContent = function (content) {
var contentArray = content.replace(new RegExp('\n', 'g'), ' ').split(' ');// eslint-disable-line
textfield.innerText = ''
for (var i in contentArray) {
var c = contentArray[i]
textfield.innerText += c
if (i !== contentArray.length - 1) {
textfield.innerHTML += '&nbsp;'
}
}
}
}
writeContent(this.toString())
this.observe(function (events) {
for (var e in events) {
var event = events[e]
if (!creatorToken) {
var oPos, fix
if (event.type === 'insert') {
oPos = event.index
fix = function (cursor) {// eslint-disable-line
if (cursor <= oPos) {
return cursor
} else {
cursor += 1
return cursor
}
}
var r = createRange(fix)
writeRange(r)
} else if (event.type === 'delete') {
oPos = event.index
fix = function (cursor) {// eslint-disable-line
if (cursor < oPos) {
return cursor
} else {
cursor -= 1
return cursor
}
}
r = createRange(fix)
writeRange(r)
}
}
}
})
// consume all text-insert changes.
textfield.onkeypress = function (event) {
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.onkeypress = null
return true
}
creatorToken = true
var char
if (event.keyCode === 13) {
char = '\n'
} else if (event.key != null) {
if (event.charCode === 32) {
char = ' '
} else {
char = event.key
}
} else {
createRange = function (fix) {
var range = {};
var s = domRoot.getSelection();
var clength = textfield.textContent.length;
range.left = Math.min(s.anchorOffset, clength);
range.right = Math.min(s.focusOffset, clength);
if(fix != null){
range.left = fix(range.left);
range.right = fix(range.right);
}
var editedElement = s.focusNode;
if(editedElement === textfield || editedElement === textfield.childNodes[0]){
range.isReal = true;
} else {
range.isReal = false;
}
return range;
};
writeRange = function (range) {
writeContent(word.toString());
var textnode = textfield.childNodes[0];
if(range.isReal && textnode != null) {
if(range.left < 0){
range.left = 0;
}
range.right = Math.max(range.left, range.right);
if (range.right > textnode.length) {
range.right = textnode.length;
}
range.left = Math.min(range.left, range.right);
var r = document.createRange(); //eslint-disable-line
r.setStart(textnode, range.left);
r.setEnd(textnode, range.right);
var s = window.getSelection(); //eslint-disable-line
s.removeAllRanges();
s.addRange(r);
}
};
writeContent = function (content) {
var contentArray = content.replace(new RegExp("\n", 'g')," ").split(" ");//eslint-disable-line
textfield.innerText = "";
for(var i in contentArray){
var c = contentArray[i];
textfield.innerText += c;
if(i !== contentArray.length - 1){
textfield.innerHTML += "&nbsp;";
}
}
};
char = window.String.fromCharCode(event.keyCode); // eslint-disable-line
}
writeContent(this.toString());
this.observe(function (events) {
for(var e in events) {
var event = events[e];
if (!creatorToken) {
var oPos, fix;
if( event.type === "insert") {
oPos = event.index;
fix = function (cursor) {//eslint-disable-line
if (cursor <= oPos) {
return cursor;
} else {
cursor += 1;
return cursor;
}
};
var r = createRange(fix);
writeRange(r);
} else if (event.type === "delete") {
oPos = event.index;
fix = function (cursor){//eslint-disable-line
if (cursor < oPos) {
return cursor;
} else {
cursor -= 1;
return cursor;
}
};
r = createRange(fix);
writeRange(r);
if (char.length > 1) {
return true
} else if (char.length > 0) {
var r = createRange()
var pos = Math.min(r.left, r.right, word.length)
var diff = Math.abs(r.right - r.left)
word.delete(pos, diff)
word.insert(pos, char)
r.left = pos + char.length
r.right = r.left
writeRange(r)
}
event.preventDefault()
creatorToken = false
return false
}
textfield.onpaste = function (event) {
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.onpaste = null
return true
}
event.preventDefault()
}
textfield.oncut = function (event) {
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.oncut = null
return true
}
event.preventDefault()
}
//
// consume deletes. Note that
// chrome: won't consume deletions on keypress event.
// keyCode is deprecated. BUT: I don't see another way.
// since event.key is not implemented in the current version of chrome.
// Every browser supports keyCode. Let's stick with it for now..
//
textfield.onkeydown = function (event) {
creatorToken = true
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.onkeydown = null
return true
}
var r = createRange()
var pos = Math.min(r.left, r.right, word.toString().length)
var diff = Math.abs(r.left - r.right)
if (event.keyCode != null && event.keyCode === 8) { // Backspace
if (diff > 0) {
word.delete(pos, diff)
r.left = pos
r.right = pos
writeRange(r)
} else {
if (event.ctrlKey != null && event.ctrlKey) {
var val = word.toString()
var newPos = pos
var delLength = 0
if (pos > 0) {
newPos--
delLength++
}
while (newPos > 0 && val[newPos] !== ' ' && val[newPos] !== '\n') {
newPos--
delLength++
}
word.delete(newPos, pos - newPos)
r.left = newPos
r.right = newPos
writeRange(r)
} else {
if (pos > 0) {
word.delete(pos - 1, 1)
r.left = pos - 1
r.right = pos - 1
writeRange(r)
}
}
}
});
// consume all text-insert changes.
textfield.onkeypress = function (event) {
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.onkeypress = null;
return true;
}
creatorToken = true;
var char;
if (event.keyCode === 13) {
char = "\n";
} else if (event.key != null) {
if (event.charCode === 32) {
char = " ";
} else {
char = event.key;
}
event.preventDefault()
creatorToken = false
return false
} else if (event.keyCode != null && event.keyCode === 46) { // Delete
if (diff > 0) {
word.delete(pos, diff)
r.left = pos
r.right = pos
writeRange(r)
} else {
char = window.String.fromCharCode(event.keyCode); //eslint-disable-line
word.delete(pos, 1)
r.left = pos
r.right = pos
writeRange(r)
}
if (char.length > 1) {
return true;
} else if (char.length > 0) {
var r = createRange();
var pos = Math.min(r.left, r.right, word.length);
var diff = Math.abs(r.right - r.left);
word.delete(pos, diff);
word.insert(pos, char);
r.left = pos + char.length;
r.right = r.left;
writeRange(r);
}
event.preventDefault();
creatorToken = false;
return false;
};
textfield.onpaste = function (event) {
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.onpaste = null;
return true;
}
event.preventDefault();
};
textfield.oncut = function (event) {
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.oncut = null;
return true;
}
event.preventDefault();
};
//
// consume deletes. Note that
// chrome: won't consume deletions on keypress event.
// keyCode is deprecated. BUT: I don't see another way.
// since event.key is not implemented in the current version of chrome.
// Every browser supports keyCode. Let's stick with it for now..
//
textfield.onkeydown = function (event) {
creatorToken = true;
if (word.is_deleted) {
// if word is deleted, do not do anything ever again
textfield.onkeydown = null;
return true;
}
var r = createRange();
var pos = Math.min(r.left, r.right, word.toString().length);
var diff = Math.abs(r.left - r.right);
if (event.keyCode != null && event.keyCode === 8) { // Backspace
if (diff > 0) {
word.delete(pos, diff);
r.left = pos;
r.right = pos;
writeRange(r);
} else {
if (event.ctrlKey != null && event.ctrlKey) {
var val = word.toString();
var newPos = pos;
var delLength = 0;
if (pos > 0) {
newPos--;
delLength++;
}
while (newPos > 0 && val[newPos] !== " " && val[newPos] !== "\n") {
newPos--;
delLength++;
}
word.delete(newPos, pos - newPos);
r.left = newPos;
r.right = newPos;
writeRange(r);
} else {
if (pos > 0) {
word.delete(pos - 1, 1);
r.left = pos - 1;
r.right = pos - 1;
writeRange(r);
}
}
}
event.preventDefault();
creatorToken = false;
return false;
} else if (event.keyCode != null && event.keyCode === 46) { // Delete
if (diff > 0) {
word.delete(pos, diff);
r.left = pos;
r.right = pos;
writeRange(r);
} else {
word.delete(pos, 1);
r.left = pos;
r.right = pos;
writeRange(r);
}
event.preventDefault();
creatorToken = false;
return false;
} else {
creatorToken = false;
return true;
}
};
event.preventDefault()
creatorToken = false
return false
} else {
creatorToken = false
return true
}
}
}
}
Y.TextBind = new CustomType({
class: YTextBind,
createType: function* YTextBindCreator () {
createType: function * YTextBindCreator () {
var model = {
start: null,
end: null,
struct: "List",
type: "TextBind",
struct: 'List',
type: 'TextBind',
id: this.store.getNextOpId()
};
yield* this.applyCreatedOperations([model]);
return yield* this.createType(model);
}
yield* this.applyCreatedOperations([model])
return yield* this.createType(model)
},
initType: function* YTextBindInitializer(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 YTextBind(os, model.id, idArray, valArray);
initType: function * YTextBindInitializer (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 YTextBind(os, model.id, idArray, valArray)
}
});
})();
})
})()