array & type are observeable

This commit is contained in:
Kevin Jahns 2015-07-15 21:24:05 +02:00
parent 9b3fe2f197
commit 60b75d1862
5 changed files with 157 additions and 19 deletions

View File

@ -1,6 +1,6 @@
language: node_js
before_install:
- "npm install -g bower coffee-script"
- "npm install -g bower"
- "bower install"
node_js:
- "0.12"
@ -8,4 +8,5 @@ node_js:
- "0.10"
branches:
only:
- master
- master
- 0.6

View File

@ -11,6 +11,7 @@
// Array of all the values
this.valArray = valArray;
this.eventHandler = new EventHandler( ops =>{
var userEvents = [];
for (var i in ops) {
var op = ops[i];
if (op.struct === "Insert") {
@ -28,14 +29,27 @@
}
this.idArray.splice(pos, 0, JSON.stringify(op.id));
this.valArray.splice(pos, 0, op.content);
userEvents.push({
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);
userEvents.push({
type: "delete",
object: this,
index: pos,
length: 1
});
} else {
throw new Error("Unexpected struct!");
}
}
this.eventHandler.callUserEventListeners(userEvents);
});
}
get (pos) {
@ -121,6 +135,9 @@
eventHandler.awaitedLastDeletes(dels.length, newLeft);
});
}
observe (f) {
this.eventHandler.addUserEventListener(f);
}
*_changed (transaction, op) {
if (op.struct === "Insert") {
var l = op.left;

View File

@ -89,6 +89,29 @@ describe("Array Type", function(){
done();
});
});
it("throw insert & delete events", function(done){
this.users[0].root.set("array", Y.Array).then(function(array){
var event;
array.observe(function(e){
event = e;
});
array.insert(0, [0]);
expect(event).toEqual([{
type: "insert",
object: array,
index: 0,
length: 1
}]);
array.delete(0);
expect(event).toEqual([{
type: "delete",
object: array,
index: 0,
length: 1
}]);
done();
});
});
});
describe(`${numberOfYArrayTests} Random tests`, function(){
var randomArrayTransactions = [

View File

@ -6,6 +6,7 @@ class EventHandler {
this.waiting = [];
this.awaiting = 0;
this.onevent = onevent;
this.userEventListeners = [];
}
receivedOp (op) {
if (this.awaiting <= 0) {
@ -18,6 +19,26 @@ class EventHandler {
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++) {
@ -56,7 +77,7 @@ class EventHandler {
}
tryCallEvents () {
this.awaiting--;
if (this.awaiting <= 0) {
if (this.awaiting <= 0 && this.waiting.length > 0) {
var events = this.waiting;
this.waiting = [];
this.onevent(events);
@ -73,30 +94,69 @@ class EventHandler {
this.contents = {};
this.opContents = {};
this.eventHandler = new EventHandler( ops =>{
var userEvents = [];
for (var i in ops) {
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;
// 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;
};
} else {
oldValue = this.contents[key];
}
// compute op event
if (op.struct === "Insert"){
if (op.left === null) {
if (op.opContent != null) {
this.opContents[op.parentSub] = op.opContent;
} else {
this.contents[op.parentSub] = op.content;
}
this.map[op.parentSub] = op.id;
}
} else if (op.struct === "Delete") {
var key = op.key;
if (compareIds(this.map[key], op.target)) {
if (this.contents[key] != null) {
delete this.contents[key];
this.opContents[key] = op.opContent;
} else {
delete this.opContents[key];
this.contents[key] = op.content;
}
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);
}
} else if (op.struct === "Delete") {
if (compareIds(this.map[key], op.target)) {
if (this.opContents[key] != null) {
delete this.opContents[key];
} else {
delete this.contents[key];
}
var deleteEvent = {
name: key,
object: this,
oldValue: oldValue,
type: "delete"
};
userEvents.push(deleteEvent);
}
} else {
throw new Error("Unexpected Operation!");
}
}
this.eventHandler.callUserEventListeners(userEvents);
});
}
get (key) {
@ -173,12 +233,9 @@ class EventHandler {
}
return def.promise;
}
/*
*delete (key) {
var t = yield "transaction";
var model = yield* t.getOperation(this._model);
yield* Y.Struct.Map.delete.call(t, model, key);
}*/
observe (f) {
this.eventHandler.addUserEventListener(f);
}
*_changed (transaction, op) {
if (op.struct === "Delete") {
op.key = (yield* transaction.getOperation(op.target)).parentSub;

View File

@ -136,6 +136,46 @@ describe("Map Type", function(){
done();
}, 50);
});
it("throws add & update & delete events (with type and primitive content)", function(done){
var y = this.users[0].root;
var event;
y.observe(function(e){
event = e; // just put it on event, should be thrown synchronously anyway
});
y.set("stuff", 4);
expect(event).toEqual([{
type: "add",
object: y,
name: "stuff"
}]);
// update, oldValue is in contents
y.set("stuff", Y.Array);
expect(event).toEqual([{
type: "update",
object: y,
name: "stuff",
oldValue: 4
}]);
y.get("stuff").then(function(replacedArray){
// update, oldValue is in opContents
y.set("stuff", 5);
var getYArray = event[0].oldValue;
expect(typeof getYArray.constructor === "function").toBeTruthy();
getYArray().then(function(array){
expect(array).toEqual(replacedArray);
// delete
y.delete("stuff");
expect(event).toEqual([{
type: "delete",
name: "stuff",
object: y,
oldValue: 5
}]);
done();
});
});
});
});
describe(`${numberOfYMapTests} Random tests`, function(){
var randomMapTransactions = [