testing observers, refactoring some Basic Types

This commit is contained in:
DadaMonad 2014-12-22 17:05:15 +00:00
parent 21f7350c4d
commit cacfb54d5e
48 changed files with 3300 additions and 2368 deletions

2
.gitignore vendored
View File

@ -4,3 +4,5 @@
.directory .directory
.c9 .c9
myftppass myftppass
.codio
.settings

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,209 @@
(function() {
var HistoryBuffer,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
HistoryBuffer = (function() {
function HistoryBuffer(user_id) {
this.user_id = user_id;
this.emptyGarbage = __bind(this.emptyGarbage, this);
this.operation_counter = {};
this.buffer = {};
this.change_listeners = [];
this.garbage = [];
this.trash = [];
this.performGarbageCollection = true;
this.garbageCollectTimeout = 1000;
this.reserved_identifier_counter = 0;
setTimeout(this.emptyGarbage, this.garbageCollectTimeout);
}
HistoryBuffer.prototype.emptyGarbage = function() {
var o, _i, _len, _ref;
_ref = this.garbage;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
o = _ref[_i];
if (typeof o.cleanup === "function") {
o.cleanup();
}
}
this.garbage = this.trash;
this.trash = [];
if (this.garbageCollectTimeout !== -1) {
this.garbageCollectTimeoutId = setTimeout(this.emptyGarbage, this.garbageCollectTimeout);
}
return void 0;
};
HistoryBuffer.prototype.getUserId = function() {
return this.user_id;
};
HistoryBuffer.prototype.addToGarbageCollector = function() {
var o, _i, _len, _results;
if (this.performGarbageCollection) {
_results = [];
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
o = arguments[_i];
if (o != null) {
_results.push(this.garbage.push(o));
} else {
_results.push(void 0);
}
}
return _results;
}
};
HistoryBuffer.prototype.stopGarbageCollection = function() {
this.performGarbageCollection = false;
this.setManualGarbageCollect();
this.garbage = [];
return this.trash = [];
};
HistoryBuffer.prototype.setManualGarbageCollect = function() {
this.garbageCollectTimeout = -1;
clearTimeout(this.garbageCollectTimeoutId);
return this.garbageCollectTimeoutId = void 0;
};
HistoryBuffer.prototype.setGarbageCollectTimeout = function(garbageCollectTimeout) {
this.garbageCollectTimeout = garbageCollectTimeout;
};
HistoryBuffer.prototype.getReservedUniqueIdentifier = function() {
return {
creator: '_',
op_number: "_" + (this.reserved_identifier_counter++),
doSync: false
};
};
HistoryBuffer.prototype.getOperationCounter = function(user_id) {
var ctn, res, user, _ref;
if (user_id == null) {
res = {};
_ref = this.operation_counter;
for (user in _ref) {
ctn = _ref[user];
res[user] = ctn;
}
return res;
} else {
return this.operation_counter[user_id];
}
};
HistoryBuffer.prototype._encode = function(state_vector) {
var json, o, o_json, o_next, o_number, o_prev, u_name, unknown, user, _ref;
if (state_vector == null) {
state_vector = {};
}
json = [];
unknown = function(user, o_number) {
if ((user == null) || (o_number == null)) {
throw new Error("dah!");
}
return (state_vector[user] == null) || state_vector[user] <= o_number;
};
_ref = this.buffer;
for (u_name in _ref) {
user = _ref[u_name];
for (o_number in user) {
o = user[o_number];
if (o.uid.doSync && unknown(u_name, o_number)) {
o_json = o._encode();
if (o.next_cl != null) {
o_next = o.next_cl;
while ((o_next.next_cl != null) && unknown(o_next.uid.creator, o_next.uid.op_number)) {
o_next = o_next.next_cl;
}
o_json.next = o_next.getUid();
} else if (o.prev_cl != null) {
o_prev = o.prev_cl;
while ((o_prev.prev_cl != null) && unknown(o_prev.uid.creator, o_prev.uid.op_number)) {
o_prev = o_prev.prev_cl;
}
o_json.prev = o_prev.getUid();
}
json.push(o_json);
}
}
}
return json;
};
HistoryBuffer.prototype.getNextOperationIdentifier = function(user_id) {
var uid;
if (user_id == null) {
user_id = this.user_id;
}
if (this.operation_counter[user_id] == null) {
this.operation_counter[user_id] = 0;
}
uid = {
'creator': user_id,
'op_number': this.operation_counter[user_id],
'doSync': true
};
this.operation_counter[user_id]++;
return uid;
};
HistoryBuffer.prototype.getOperation = function(uid) {
var _ref;
if (uid.uid != null) {
uid = uid.uid;
}
return (_ref = this.buffer[uid.creator]) != null ? _ref[uid.op_number] : void 0;
};
HistoryBuffer.prototype.addOperation = function(o) {
if (this.buffer[o.uid.creator] == null) {
this.buffer[o.uid.creator] = {};
}
if (this.buffer[o.uid.creator][o.uid.op_number] != null) {
throw new Error("You must not overwrite operations!");
}
this.buffer[o.uid.creator][o.uid.op_number] = o;
if (this.number_of_operations_added_to_HB == null) {
this.number_of_operations_added_to_HB = 0;
}
this.number_of_operations_added_to_HB++;
return o;
};
HistoryBuffer.prototype.removeOperation = function(o) {
var _ref;
return (_ref = this.buffer[o.uid.creator]) != null ? delete _ref[o.uid.op_number] : void 0;
};
HistoryBuffer.prototype.addToCounter = function(o) {
var _results;
if (this.operation_counter[o.uid.creator] == null) {
this.operation_counter[o.uid.creator] = 0;
}
if (typeof o.uid.op_number === 'number' && o.uid.creator !== this.getUserId()) {
if (o.uid.op_number === this.operation_counter[o.uid.creator]) {
this.operation_counter[o.uid.creator]++;
_results = [];
while (this.getOperation({
creator: o.uid.creator,
op_number: this.operation_counter[o.uid.creator]
}) != null) {
_results.push(this.operation_counter[o.uid.creator]++);
}
return _results;
}
}
};
return HistoryBuffer;
})();
module.exports = HistoryBuffer;
}).call(this);
//# sourceMappingURL=HistoryBuffer.js.map

View File

@ -0,0 +1,458 @@
(function() {
var __slice = [].slice,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
module.exports = function(HB) {
var Delete, Delimiter, ImmutableObject, Insert, Operation, execution_listener, parser;
parser = {};
execution_listener = [];
Operation = (function() {
function Operation(uid) {
this.is_deleted = false;
this.garbage_collected = false;
this.event_listeners = [];
if (uid != null) {
this.uid = uid;
}
}
Operation.prototype.type = "Insert";
Operation.prototype.observe = function(f) {
return this.event_listeners.push(f);
};
Operation.prototype.unobserve = function(f) {
return this.event_listeners.filter(function(g) {
return f !== g;
});
};
Operation.prototype.deleteAllObservers = function() {
return this.event_listeners = [];
};
Operation.prototype.callEvent = function() {
return this.forwardEvent.apply(this, [this].concat(__slice.call(arguments)));
};
Operation.prototype.forwardEvent = function() {
var args, f, op, _i, _len, _ref, _results;
op = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
_ref = this.event_listeners;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
f = _ref[_i];
_results.push(f.call.apply(f, [op].concat(__slice.call(args))));
}
return _results;
};
Operation.prototype.isDeleted = function() {
return this.is_deleted;
};
Operation.prototype.applyDelete = function(garbagecollect) {
if (garbagecollect == null) {
garbagecollect = true;
}
if (!this.garbage_collected) {
this.is_deleted = true;
if (garbagecollect) {
this.garbage_collected = true;
return HB.addToGarbageCollector(this);
}
}
};
Operation.prototype.cleanup = function() {
HB.removeOperation(this);
return this.deleteAllObservers();
};
Operation.prototype.setParent = function(parent) {
this.parent = parent;
};
Operation.prototype.getParent = function() {
return this.parent;
};
Operation.prototype.getUid = function() {
return this.uid;
};
Operation.prototype.dontSync = function() {
return this.uid.doSync = false;
};
Operation.prototype.execute = function() {
var l, _i, _len;
this.is_executed = true;
if (this.uid == null) {
this.uid = HB.getNextOperationIdentifier();
}
HB.addOperation(this);
for (_i = 0, _len = execution_listener.length; _i < _len; _i++) {
l = execution_listener[_i];
l(this._encode());
}
return this;
};
Operation.prototype.saveOperation = function(name, op) {
if ((op != null ? op.execute : void 0) != null) {
return this[name] = op;
} else if (op != null) {
if (this.unchecked == null) {
this.unchecked = {};
}
return this.unchecked[name] = op;
}
};
Operation.prototype.validateSavedOperations = function() {
var name, op, op_uid, success, uninstantiated, _ref;
uninstantiated = {};
success = this;
_ref = this.unchecked;
for (name in _ref) {
op_uid = _ref[name];
op = HB.getOperation(op_uid);
if (op) {
this[name] = op;
} else {
uninstantiated[name] = op_uid;
success = false;
}
}
delete this.unchecked;
if (!success) {
this.unchecked = uninstantiated;
}
return success;
};
return Operation;
})();
Delete = (function(_super) {
__extends(Delete, _super);
function Delete(uid, deletes) {
this.saveOperation('deletes', deletes);
Delete.__super__.constructor.call(this, uid);
}
Delete.prototype.type = "Delete";
Delete.prototype._encode = function() {
return {
'type': "Delete",
'uid': this.getUid(),
'deletes': this.deletes.getUid()
};
};
Delete.prototype.execute = function() {
if (this.validateSavedOperations()) {
this.deletes.applyDelete(this);
return Delete.__super__.execute.apply(this, arguments);
} else {
return false;
}
};
return Delete;
})(Operation);
parser['Delete'] = function(o) {
var deletes_uid, uid;
uid = o['uid'], deletes_uid = o['deletes'];
return new Delete(uid, deletes_uid);
};
Insert = (function(_super) {
__extends(Insert, _super);
function Insert(uid, prev_cl, next_cl, origin) {
this.saveOperation('prev_cl', prev_cl);
this.saveOperation('next_cl', next_cl);
if (origin != null) {
this.saveOperation('origin', origin);
} else {
this.saveOperation('origin', prev_cl);
}
Insert.__super__.constructor.call(this, uid);
}
Insert.prototype.type = "Insert";
Insert.prototype.applyDelete = function(o) {
var callLater, garbagecollect, _ref;
if (this.deleted_by == null) {
this.deleted_by = [];
}
callLater = false;
if ((this.parent != null) && !this.isDeleted() && (o != null)) {
callLater = true;
}
if (o != null) {
this.deleted_by.push(o);
}
garbagecollect = false;
if (!((this.prev_cl != null) && (this.next_cl != null)) || this.prev_cl.isDeleted()) {
garbagecollect = true;
}
Insert.__super__.applyDelete.call(this, garbagecollect);
if (callLater) {
this.parent.callEvent([
{
type: "insert",
position: this.getPosition(),
object: this.parent,
changed_by: o.uid.creator
}
]);
}
if ((_ref = this.next_cl) != null ? _ref.isDeleted() : void 0) {
return this.next_cl.applyDelete();
}
};
Insert.prototype.cleanup = function() {
var d, o, _i, _len, _ref, _ref1;
if ((_ref = this.prev_cl) != null ? _ref.isDeleted() : void 0) {
_ref1 = this.deleted_by;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
d = _ref1[_i];
d.cleanup();
}
o = this.next_cl;
while (o.type !== "Delimiter") {
if (o.origin === this) {
o.origin = this.prev_cl;
}
o = o.next_cl;
}
this.prev_cl.next_cl = this.next_cl;
this.next_cl.prev_cl = this.prev_cl;
return Insert.__super__.cleanup.apply(this, arguments);
}
};
Insert.prototype.getDistanceToOrigin = function() {
var d, o;
d = 0;
o = this.prev_cl;
while (true) {
if (this.origin === o) {
break;
}
d++;
o = o.prev_cl;
}
return d;
};
Insert.prototype.execute = function() {
var distance_to_origin, i, o;
if (!this.validateSavedOperations()) {
return false;
} else {
if (this.prev_cl != null) {
distance_to_origin = this.getDistanceToOrigin();
o = this.prev_cl.next_cl;
i = distance_to_origin;
while (true) {
if (o !== this.next_cl) {
if (o.getDistanceToOrigin() === i) {
if (o.uid.creator < this.uid.creator) {
this.prev_cl = o;
distance_to_origin = i + 1;
} else {
}
} else if (o.getDistanceToOrigin() < i) {
if (i - distance_to_origin <= o.getDistanceToOrigin()) {
this.prev_cl = o;
distance_to_origin = i + 1;
} else {
}
} else {
break;
}
i++;
o = o.next_cl;
} else {
break;
}
}
this.next_cl = this.prev_cl.next_cl;
this.prev_cl.next_cl = this;
this.next_cl.prev_cl = this;
}
this.setParent(this.prev_cl.getParent());
Insert.__super__.execute.apply(this, arguments);
this.callOperationSpecificEvents();
return this;
}
};
Insert.prototype.callOperationSpecificEvents = function() {
var _ref;
return (_ref = this.parent) != null ? _ref.callEvent([
{
type: "insert",
position: this.getPosition(),
object: this.parent,
changed_by: this.uid.creator
}
]) : void 0;
};
Insert.prototype.getPosition = function() {
var position, prev;
position = 0;
prev = this.prev_cl;
while (true) {
if (prev instanceof Delimiter) {
break;
}
if (!prev.isDeleted()) {
position++;
}
prev = prev.prev_cl;
}
return position;
};
return Insert;
})(Operation);
ImmutableObject = (function(_super) {
__extends(ImmutableObject, _super);
function ImmutableObject(uid, content, prev, next, origin) {
this.content = content;
ImmutableObject.__super__.constructor.call(this, uid, prev, next, origin);
}
ImmutableObject.prototype.type = "ImmutableObject";
ImmutableObject.prototype.val = function() {
return this.content;
};
ImmutableObject.prototype._encode = function() {
var json;
json = {
'type': "ImmutableObject",
'uid': this.getUid(),
'content': this.content
};
if (this.prev_cl != null) {
json['prev'] = this.prev_cl.getUid();
}
if (this.next_cl != null) {
json['next'] = this.next_cl.getUid();
}
if (this.origin != null) {
json["origin"] = this.origin().getUid();
}
return json;
};
return ImmutableObject;
})(Operation);
parser['ImmutableObject'] = function(json) {
var content, next, origin, prev, uid;
uid = json['uid'], content = json['content'], prev = json['prev'], next = json['next'], origin = json['origin'];
return new ImmutableObject(uid, content, prev, next, origin);
};
Delimiter = (function(_super) {
__extends(Delimiter, _super);
function Delimiter(uid, prev_cl, next_cl, origin) {
this.saveOperation('prev_cl', prev_cl);
this.saveOperation('next_cl', next_cl);
this.saveOperation('origin', prev_cl);
Delimiter.__super__.constructor.call(this, uid);
}
Delimiter.prototype.type = "Delimiter";
Delimiter.prototype.applyDelete = function() {
var o;
Delimiter.__super__.applyDelete.call(this);
o = this.next_cl;
while (o != null) {
o.applyDelete();
o = o.next_cl;
}
return void 0;
};
Delimiter.prototype.cleanup = function() {
return Delimiter.__super__.cleanup.call(this);
};
Delimiter.prototype.execute = function() {
var _ref, _ref1;
if (((_ref = this.unchecked) != null ? _ref['next_cl'] : void 0) != null) {
return Delimiter.__super__.execute.apply(this, arguments);
} else if ((_ref1 = this.unchecked) != null ? _ref1['prev_cl'] : void 0) {
if (this.validateSavedOperations()) {
if (this.prev_cl.next_cl != null) {
throw new Error("Probably duplicated operations");
}
this.prev_cl.next_cl = this;
return Delimiter.__super__.execute.apply(this, arguments);
} else {
return false;
}
} else if ((this.prev_cl != null) && (this.prev_cl.next_cl == null)) {
delete this.prev_cl.unchecked.next_cl;
this.prev_cl.next_cl = this;
return Delimiter.__super__.execute.apply(this, arguments);
} else if ((this.prev_cl != null) || (this.next_cl != null) || true) {
return Delimiter.__super__.execute.apply(this, arguments);
}
};
Delimiter.prototype._encode = function() {
var _ref, _ref1;
return {
'type': "Delimiter",
'uid': this.getUid(),
'prev': (_ref = this.prev_cl) != null ? _ref.getUid() : void 0,
'next': (_ref1 = this.next_cl) != null ? _ref1.getUid() : void 0
};
};
return Delimiter;
})(Operation);
parser['Delimiter'] = function(json) {
var next, prev, uid;
uid = json['uid'], prev = json['prev'], next = json['next'];
return new Delimiter(uid, prev, next);
};
return {
'types': {
'Delete': Delete,
'Insert': Insert,
'Delimiter': Delimiter,
'Operation': Operation,
'ImmutableObject': ImmutableObject
},
'parser': parser,
'execution_listener': execution_listener
};
};
}).call(this);
//# sourceMappingURL=../Types/BasicTypes.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,246 @@
(function() {
var text_types_uninitialized,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
text_types_uninitialized = require("./TextTypes");
module.exports = function(HB) {
var JsonType, createJsonTypeWrapper, parser, text_types, types;
text_types = text_types_uninitialized(HB);
types = text_types.types;
parser = text_types.parser;
createJsonTypeWrapper = function(_jsonType) {
var JsonTypeWrapper;
JsonTypeWrapper = (function() {
function JsonTypeWrapper(jsonType) {
var name, obj, _fn, _ref;
_ref = jsonType.map;
_fn = function(name, obj) {
return Object.defineProperty(JsonTypeWrapper.prototype, name, {
get: function() {
var x;
x = obj.val();
if (x instanceof JsonType) {
return createJsonTypeWrapper(x);
} else if (x instanceof types.ImmutableObject) {
return x.val();
} else {
return x;
}
},
set: function(o) {
var o_name, o_obj, overwrite, _results;
overwrite = jsonType.val(name);
if (o.constructor === {}.constructor && overwrite instanceof types.Operation) {
_results = [];
for (o_name in o) {
o_obj = o[o_name];
_results.push(overwrite.val(o_name, o_obj, 'immutable'));
}
return _results;
} else {
return jsonType.val(name, o, 'immutable');
}
},
enumerable: true,
configurable: false
});
};
for (name in _ref) {
obj = _ref[name];
_fn(name, obj);
}
}
return JsonTypeWrapper;
})();
return new JsonTypeWrapper(_jsonType);
};
JsonType = (function(_super) {
__extends(JsonType, _super);
function JsonType() {
return JsonType.__super__.constructor.apply(this, arguments);
}
JsonType.prototype.type = "JsonType";
JsonType.prototype.applyDelete = function() {
return JsonType.__super__.applyDelete.call(this);
};
JsonType.prototype.cleanup = function() {
return JsonType.__super__.cleanup.call(this);
};
JsonType.prototype.toJson = function() {
var json, name, o, that, val;
if ((this.bound_json == null) || (Object.observe == null) || true) {
val = this.val();
json = {};
for (name in val) {
o = val[name];
if (o == null) {
json[name] = o;
} else if (o.constructor === {}.constructor) {
json[name] = this.val(name).toJson();
} else if (o instanceof types.Operation) {
while (o instanceof types.Operation) {
o = o.val();
}
json[name] = o;
} else {
json[name] = o;
}
}
this.bound_json = json;
if (Object.observe != null) {
that = this;
Object.observe(this.bound_json, function(events) {
var event, _i, _len, _results;
_results = [];
for (_i = 0, _len = events.length; _i < _len; _i++) {
event = events[_i];
if ((event.changed_by == null) && (event.type === "add" || (event.type = "update"))) {
_results.push(that.val(event.name, event.object[event.name]));
} else {
_results.push(void 0);
}
}
return _results;
});
this.observe(function(events) {
var event, notifier, oldVal, _i, _len, _results;
_results = [];
for (_i = 0, _len = events.length; _i < _len; _i++) {
event = events[_i];
if (event.created_ !== HB.getUserId()) {
notifier = Object.getNotifier(that.bound_json);
oldVal = that.bound_json[event.name];
if (oldVal != null) {
notifier.performChange('update', function() {
return that.bound_json[event.name] = that.val(event.name);
}, that.bound_json);
_results.push(notifier.notify({
object: that.bound_json,
type: 'update',
name: event.name,
oldValue: oldVal,
changed_by: event.changed_by
}));
} else {
notifier.performChange('add', function() {
return that.bound_json[event.name] = that.val(event.name);
}, that.bound_json);
_results.push(notifier.notify({
object: that.bound_json,
type: 'add',
name: event.name,
oldValue: oldVal,
changed_by: event.changed_by
}));
}
} else {
_results.push(void 0);
}
}
return _results;
});
}
}
return this.bound_json;
};
JsonType.prototype.mutable_default = true;
JsonType.prototype.setMutableDefault = function(mutable) {
if (mutable === true || mutable === 'mutable') {
JsonType.prototype.mutable_default = true;
} else if (mutable === false || mutable === 'immutable') {
JsonType.prototype.mutable_default = false;
} else {
throw new Error('Set mutable either "mutable" or "immutable"!');
}
return 'OK';
};
JsonType.prototype.val = function(name, content, mutable) {
var json, n, o, word;
if ((name != null) && arguments.length > 1) {
if (mutable != null) {
if (mutable === true || mutable === 'mutable') {
mutable = true;
} else {
mutable = false;
}
} else {
mutable = this.mutable_default;
}
if (typeof content === 'function') {
return this;
} else if ((content == null) || (((!mutable) || typeof content === 'number') && content.constructor !== Object)) {
return JsonType.__super__.val.call(this, name, (new types.ImmutableObject(void 0, content)).execute());
} else {
if (typeof content === 'string') {
word = (new types.WordType(void 0)).execute();
word.insertText(0, content);
return JsonType.__super__.val.call(this, name, word);
} else if (content.constructor === Object) {
json = new JsonType().execute();
for (n in content) {
o = content[n];
json.val(n, o, mutable);
}
return JsonType.__super__.val.call(this, name, json);
} else {
throw new Error("You must not set " + (typeof content) + "-types in collaborative Json-objects!");
}
}
} else {
return JsonType.__super__.val.call(this, name, content);
}
};
Object.defineProperty(JsonType.prototype, 'value', {
get: function() {
return createJsonTypeWrapper(this);
},
set: function(o) {
var o_name, o_obj, _results;
if (o.constructor === {}.constructor) {
_results = [];
for (o_name in o) {
o_obj = o[o_name];
_results.push(this.val(o_name, o_obj, 'immutable'));
}
return _results;
} else {
throw new Error("You must only set Object values!");
}
}
});
JsonType.prototype._encode = function() {
return {
'type': "JsonType",
'uid': this.getUid()
};
};
return JsonType;
})(types.MapManager);
parser['JsonType'] = function(json) {
var uid;
uid = json['uid'];
return new JsonType(uid);
};
types['JsonType'] = JsonType;
return text_types;
};
}).call(this);
//# sourceMappingURL=../Types/JsonTypes.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,401 @@
(function() {
var basic_types_uninitialized,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
basic_types_uninitialized = require("./BasicTypes");
module.exports = function(HB) {
var AddName, ListManager, MapManager, ReplaceManager, Replaceable, basic_types, parser, types;
basic_types = basic_types_uninitialized(HB);
types = basic_types.types;
parser = basic_types.parser;
MapManager = (function(_super) {
__extends(MapManager, _super);
function MapManager(uid) {
this.map = {};
MapManager.__super__.constructor.call(this, uid);
}
MapManager.prototype.type = "MapManager";
MapManager.prototype.applyDelete = function() {
var name, p, _ref;
_ref = this.map;
for (name in _ref) {
p = _ref[name];
p.applyDelete();
}
return MapManager.__super__.applyDelete.call(this);
};
MapManager.prototype.cleanup = function() {
return MapManager.__super__.cleanup.call(this);
};
MapManager.prototype.val = function(name, content) {
var o, obj, qqq, result, x, _ref, _ref1;
if (content != null) {
if (this.map[name] == null) {
(new AddName(void 0, this, name)).execute();
}
if (this.map[name] === null) {
qqq = this;
x = new AddName(void 0, this, name);
x.execute();
}
this.map[name].replace(content);
return this;
} else if (name != null) {
obj = (_ref = this.map[name]) != null ? _ref.val() : void 0;
if (obj instanceof types.ImmutableObject) {
return obj.val();
} else {
return obj;
}
} else {
result = {};
_ref1 = this.map;
for (name in _ref1) {
o = _ref1[name];
obj = o.val();
if (obj instanceof types.ImmutableObject || obj instanceof MapManager) {
obj = obj.val();
}
result[name] = obj;
}
return result;
}
};
return MapManager;
})(types.Operation);
AddName = (function(_super) {
__extends(AddName, _super);
function AddName(uid, map_manager, name) {
this.name = name;
this.saveOperation('map_manager', map_manager);
AddName.__super__.constructor.call(this, uid);
}
AddName.prototype.type = "AddName";
AddName.prototype.applyDelete = function() {
return AddName.__super__.applyDelete.call(this);
};
AddName.prototype.cleanup = function() {
return AddName.__super__.cleanup.call(this);
};
AddName.prototype.execute = function() {
var beg, clone, end, event_properties, event_this, uid_beg, uid_end, uid_r, _base;
if (!this.validateSavedOperations()) {
return false;
} else {
clone = function(o) {
var name, p, value;
p = {};
for (name in o) {
value = o[name];
p[name] = value;
}
return p;
};
uid_r = clone(this.map_manager.getUid());
uid_r.doSync = false;
uid_r.op_number = "_" + uid_r.op_number + "_RM_" + this.name;
if (HB.getOperation(uid_r) == null) {
uid_beg = clone(uid_r);
uid_beg.op_number = "" + uid_r.op_number + "_beginning";
uid_end = clone(uid_r);
uid_end.op_number = "" + uid_r.op_number + "_end";
beg = (new types.Delimiter(uid_beg, void 0, uid_end)).execute();
end = (new types.Delimiter(uid_end, beg, void 0)).execute();
event_properties = {
name: this.name
};
event_this = this.map_manager;
this.map_manager.map[this.name] = new ReplaceManager(event_properties, event_this, uid_r, beg, end);
this.map_manager.map[this.name].setParent(this.map_manager, this.name);
((_base = this.map_manager.map[this.name]).add_name_ops != null ? _base.add_name_ops : _base.add_name_ops = []).push(this);
this.map_manager.map[this.name].execute();
}
return AddName.__super__.execute.apply(this, arguments);
}
};
AddName.prototype._encode = function() {
return {
'type': "AddName",
'uid': this.getUid(),
'map_manager': this.map_manager.getUid(),
'name': this.name
};
};
return AddName;
})(types.Operation);
parser['AddName'] = function(json) {
var map_manager, name, uid;
map_manager = json['map_manager'], uid = json['uid'], name = json['name'];
return new AddName(uid, map_manager, name);
};
ListManager = (function(_super) {
__extends(ListManager, _super);
function ListManager(uid, beginning, end, prev, next, origin) {
if ((beginning != null) && (end != null)) {
this.saveOperation('beginning', beginning);
this.saveOperation('end', end);
} else {
this.beginning = new types.Delimiter(void 0, void 0, void 0);
this.end = new types.Delimiter(void 0, this.beginning, void 0);
this.beginning.next_cl = this.end;
this.beginning.execute();
this.end.execute();
}
ListManager.__super__.constructor.call(this, uid, prev, next, origin);
}
ListManager.prototype.type = "ListManager";
ListManager.prototype.execute = function() {
if (this.validateSavedOperations()) {
this.beginning.setParent(this);
this.end.setParent(this);
return ListManager.__super__.execute.apply(this, arguments);
} else {
return false;
}
};
ListManager.prototype.getLastOperation = function() {
return this.end.prev_cl;
};
ListManager.prototype.getFirstOperation = function() {
return this.beginning.next_cl;
};
ListManager.prototype.toArray = function() {
var o, result;
o = this.beginning.next_cl;
result = [];
while (o !== this.end) {
result.push(o);
o = o.next_cl;
}
return result;
};
ListManager.prototype.getOperationByPosition = function(position) {
var o;
o = this.beginning.next_cl;
if ((position > 0 || o.isDeleted()) && !(o instanceof types.Delimiter)) {
while (o.isDeleted() && !(o instanceof types.Delimiter)) {
o = o.next_cl;
}
while (true) {
if (o instanceof types.Delimiter) {
break;
}
if (position <= 0 && !o.isDeleted()) {
break;
}
o = o.next_cl;
if (!o.isDeleted()) {
position -= 1;
}
}
}
return o;
};
return ListManager;
})(types.Operation);
ReplaceManager = (function(_super) {
__extends(ReplaceManager, _super);
function ReplaceManager(event_porperties, event_this, uid, beginning, end, prev, next, origin) {
this.event_porperties = event_porperties;
this.event_this = event_this;
ReplaceManager.__super__.constructor.call(this, uid, beginning, end, prev, next, origin);
}
ReplaceManager.prototype.type = "ReplaceManager";
ReplaceManager.prototype.applyDelete = function() {
var o, _i, _len, _ref;
o = this.beginning;
while (o != null) {
o.applyDelete();
o = o.next_cl;
}
if (this.add_name_ops != null) {
_ref = this.add_name_ops;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
o = _ref[_i];
o.applyDelete();
}
}
return ReplaceManager.__super__.applyDelete.call(this);
};
ReplaceManager.prototype.cleanup = function() {
return ReplaceManager.__super__.cleanup.call(this);
};
ReplaceManager.prototype.callEventDecorator = function(events) {
var event, name, prop, _i, _len, _ref;
if (!this.isDeleted()) {
_ref = this.event_porperties;
for (name in _ref) {
prop = _ref[name];
for (_i = 0, _len = events.length; _i < _len; _i++) {
event = events[_i];
event[name] = prop;
}
}
this.event_this.callEvent(events);
}
return void 0;
};
ReplaceManager.prototype.replace = function(content, replaceable_uid) {
var o;
o = this.getLastOperation();
(new Replaceable(content, this, replaceable_uid, o, o.next_cl)).execute();
return void 0;
};
ReplaceManager.prototype.val = function() {
var o;
o = this.getLastOperation();
return typeof o.val === "function" ? o.val() : void 0;
};
ReplaceManager.prototype._encode = function() {
var json;
json = {
'type': "ReplaceManager",
'uid': this.getUid(),
'beginning': this.beginning.getUid(),
'end': this.end.getUid()
};
if ((this.prev_cl != null) && (this.next_cl != null)) {
json['prev'] = this.prev_cl.getUid();
json['next'] = this.next_cl.getUid();
}
if (this.origin != null) {
json["origin"] = this.origin().getUid();
}
return json;
};
return ReplaceManager;
})(ListManager);
parser["ReplaceManager"] = function(json) {
var beginning, end, next, origin, prev, uid;
uid = json['uid'], prev = json['prev'], next = json['next'], origin = json['origin'], beginning = json['beginning'], end = json['end'];
return new ReplaceManager(uid, beginning, end, prev, next, origin);
};
Replaceable = (function(_super) {
__extends(Replaceable, _super);
function Replaceable(content, parent, uid, prev, next, origin) {
this.saveOperation('content', content);
this.saveOperation('parent', parent);
if (!((prev != null) && (next != null))) {
throw new Error("You must define prev, and next for Replaceable-types!");
}
Replaceable.__super__.constructor.call(this, uid, prev, next, origin);
}
Replaceable.prototype.type = "Replaceable";
Replaceable.prototype.val = function() {
return this.content;
};
Replaceable.prototype.applyDelete = function() {
if (this.content != null) {
if (this.next_cl.type !== "Delimiter") {
this.content.deleteAllObservers();
}
this.content.applyDelete();
this.content.dontSync();
}
this.content = null;
return Replaceable.__super__.applyDelete.apply(this, arguments);
};
Replaceable.prototype.cleanup = function() {
return Replaceable.__super__.cleanup.apply(this, arguments);
};
Replaceable.prototype.callOperationSpecificEvents = function() {
var old_value;
if (this.next_cl.type === "Delimiter" && this.prev_cl.type !== "Delimiter") {
old_value = this.prev_cl.content;
this.prev_cl.applyDelete();
this.parent.callEventDecorator([
{
type: "update",
changed_by: this.uid.creator,
oldValue: old_value
}
]);
} else if (this.next_cl.type !== "Delimiter") {
this.applyDelete();
} else {
this.parent.callEventDecorator([
{
type: "add",
changed_by: this.uid.creator
}
]);
}
return void 0;
};
Replaceable.prototype._encode = function() {
var json, _ref;
json = {
'type': "Replaceable",
'content': (_ref = this.content) != null ? _ref.getUid() : void 0,
'ReplaceManager': this.parent.getUid(),
'prev': this.prev_cl.getUid(),
'next': this.next_cl.getUid(),
'uid': this.getUid()
};
if ((this.origin != null) && this.origin !== this.prev_cl) {
json["origin"] = this.origin.getUid();
}
return json;
};
return Replaceable;
})(types.Insert);
parser["Replaceable"] = function(json) {
var content, next, origin, parent, prev, uid;
content = json['content'], parent = json['ReplaceManager'], uid = json['uid'], prev = json['prev'], next = json['next'], origin = json['origin'];
return new Replaceable(content, parent, uid, prev, next, origin);
};
types['ListManager'] = ListManager;
types['MapManager'] = MapManager;
types['ReplaceManager'] = ReplaceManager;
types['Replaceable'] = Replaceable;
return basic_types;
};
}).call(this);
//# sourceMappingURL=../Types/StructuredTypes.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,342 @@
(function() {
var structured_types_uninitialized,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
structured_types_uninitialized = require("./StructuredTypes");
module.exports = function(HB) {
var TextDelete, TextInsert, WordType, parser, structured_types, types;
structured_types = structured_types_uninitialized(HB);
types = structured_types.types;
parser = structured_types.parser;
TextDelete = (function(_super) {
__extends(TextDelete, _super);
function TextDelete() {
return TextDelete.__super__.constructor.apply(this, arguments);
}
return TextDelete;
})(types.Delete);
parser["TextDelete"] = parser["Delete"];
TextInsert = (function(_super) {
__extends(TextInsert, _super);
function TextInsert(content, uid, prev, next, origin) {
var _ref;
if (content != null ? (_ref = content.uid) != null ? _ref.creator : void 0 : void 0) {
this.saveOperation('content', content);
} else {
this.content = content;
}
if (!((prev != null) && (next != null))) {
throw new Error("You must define prev, and next for TextInsert-types!");
}
TextInsert.__super__.constructor.call(this, uid, prev, next, origin);
}
TextInsert.prototype.type = "TextInsert";
TextInsert.prototype.getLength = function() {
if (this.isDeleted()) {
return 0;
} else {
return this.content.length;
}
};
TextInsert.prototype.applyDelete = function() {
TextInsert.__super__.applyDelete.apply(this, arguments);
if (this.content instanceof types.Operation) {
this.content.applyDelete();
}
return this.content = null;
};
TextInsert.prototype.execute = function() {
if (!this.validateSavedOperations()) {
return false;
} else {
if (this.content instanceof types.Operation) {
this.content.insert_parent = this;
}
return TextInsert.__super__.execute.call(this);
}
};
TextInsert.prototype.val = function(current_position) {
if (this.isDeleted() || (this.content == null)) {
return "";
} else {
return this.content;
}
};
TextInsert.prototype._encode = function() {
var json, _ref;
json = {
'type': "TextInsert",
'uid': this.getUid(),
'prev': this.prev_cl.getUid(),
'next': this.next_cl.getUid()
};
if (((_ref = this.content) != null ? _ref.getUid : void 0) != null) {
json['content'] = this.content.getUid();
} else {
json['content'] = this.content;
}
if (this.origin !== this.prev_cl) {
json["origin"] = this.origin.getUid();
}
return json;
};
return TextInsert;
})(types.Insert);
parser["TextInsert"] = function(json) {
var content, next, origin, prev, uid;
content = json['content'], uid = json['uid'], prev = json['prev'], next = json['next'], origin = json['origin'];
return new TextInsert(content, uid, prev, next, origin);
};
WordType = (function(_super) {
__extends(WordType, _super);
function WordType(uid, beginning, end, prev, next, origin) {
WordType.__super__.constructor.call(this, uid, beginning, end, prev, next, origin);
}
WordType.prototype.type = "WordType";
WordType.prototype.applyDelete = function() {
var o;
o = this.beginning;
while (o != null) {
o.applyDelete();
o = o.next_cl;
}
return WordType.__super__.applyDelete.call(this);
};
WordType.prototype.cleanup = function() {
return WordType.__super__.cleanup.call(this);
};
WordType.prototype.push = function(content) {
return this.insertAfter(this.end.prev_cl, content);
};
WordType.prototype.insertAfter = function(left, content) {
var c, right, tmp, _i, _len;
while (left.isDeleted()) {
left = left.prev_cl;
}
right = left.next_cl;
if (content.type != null) {
(new TextInsert(content, void 0, left, right)).execute();
} else {
for (_i = 0, _len = content.length; _i < _len; _i++) {
c = content[_i];
tmp = (new TextInsert(c, void 0, left, right)).execute();
left = tmp;
}
}
return this;
};
WordType.prototype.insertText = function(position, content) {
var ith, left;
ith = this.getOperationByPosition(position);
left = ith.prev_cl;
return this.insertAfter(left, content);
};
WordType.prototype.deleteText = function(position, length) {
var d, delete_ops, i, o, _i;
o = this.getOperationByPosition(position);
delete_ops = [];
for (i = _i = 0; 0 <= length ? _i < length : _i > length; i = 0 <= length ? ++_i : --_i) {
if (o instanceof types.Delimiter) {
break;
}
d = (new TextDelete(void 0, o)).execute();
o = o.next_cl;
while (!(o instanceof types.Delimiter) && o.isDeleted()) {
o = o.next_cl;
}
delete_ops.push(d._encode());
}
return this;
};
WordType.prototype.val = function() {
var c, o;
c = (function() {
var _i, _len, _ref, _results;
_ref = this.toArray();
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
o = _ref[_i];
if (o.val != null) {
_results.push(o.val());
} else {
_results.push("");
}
}
return _results;
}).call(this);
return c.join('');
};
WordType.prototype.toString = function() {
return this.val();
};
WordType.prototype.bind = function(textfield) {
var word;
word = this;
textfield.value = this.val();
this.on("insert", function(event, op) {
var fix, left, o_pos, right;
o_pos = op.getPosition();
fix = function(cursor) {
if (cursor <= o_pos) {
return cursor;
} else {
cursor += 1;
return cursor;
}
};
left = fix(textfield.selectionStart);
right = fix(textfield.selectionEnd);
textfield.value = word.val();
return textfield.setSelectionRange(left, right);
});
this.on("delete", function(event, op) {
var fix, left, o_pos, right;
o_pos = op.getPosition();
fix = function(cursor) {
if (cursor < o_pos) {
return cursor;
} else {
cursor -= 1;
return cursor;
}
};
left = fix(textfield.selectionStart);
right = fix(textfield.selectionEnd);
textfield.value = word.val();
return textfield.setSelectionRange(left, right);
});
textfield.onkeypress = function(event) {
var char, diff, new_pos, pos;
char = null;
if (event.key != null) {
if (event.charCode === 32) {
char = " ";
} else if (event.keyCode === 13) {
char = '\n';
} else {
char = event.key;
}
} else {
char = String.fromCharCode(event.keyCode);
}
if (char.length > 0) {
pos = Math.min(textfield.selectionStart, textfield.selectionEnd);
diff = Math.abs(textfield.selectionEnd - textfield.selectionStart);
word.deleteText(pos, diff);
word.insertText(pos, char);
new_pos = pos + char.length;
textfield.setSelectionRange(new_pos, new_pos);
return event.preventDefault();
} else {
return event.preventDefault();
}
};
textfield.onpaste = function(event) {
return event.preventDefault();
};
textfield.oncut = function(event) {
return event.preventDefault();
};
return textfield.onkeydown = function(event) {
var del_length, diff, new_pos, pos, val;
pos = Math.min(textfield.selectionStart, textfield.selectionEnd);
diff = Math.abs(textfield.selectionEnd - textfield.selectionStart);
if ((event.keyCode != null) && event.keyCode === 8) {
if (diff > 0) {
word.deleteText(pos, diff);
textfield.setSelectionRange(pos, pos);
} else {
if ((event.ctrlKey != null) && event.ctrlKey) {
val = textfield.value;
new_pos = pos;
del_length = 0;
if (pos > 0) {
new_pos--;
del_length++;
}
while (new_pos > 0 && val[new_pos] !== " " && val[new_pos] !== '\n') {
new_pos--;
del_length++;
}
word.deleteText(new_pos, pos - new_pos);
textfield.setSelectionRange(new_pos, new_pos);
} else {
word.deleteText(pos - 1, 1);
}
}
return event.preventDefault();
} else if ((event.keyCode != null) && event.keyCode === 46) {
if (diff > 0) {
word.deleteText(pos, diff);
textfield.setSelectionRange(pos, pos);
} else {
word.deleteText(pos, 1);
textfield.setSelectionRange(pos, pos);
}
return event.preventDefault();
}
};
};
WordType.prototype._encode = function() {
var json;
json = {
'type': "WordType",
'uid': this.getUid(),
'beginning': this.beginning.getUid(),
'end': this.end.getUid()
};
if (this.prev_cl != null) {
json['prev'] = this.prev_cl.getUid();
}
if (this.next_cl != null) {
json['next'] = this.next_cl.getUid();
}
if (this.origin != null) {
json["origin"] = this.origin().getUid();
}
return json;
};
return WordType;
})(types.ListManager);
parser['WordType'] = function(json) {
var beginning, end, next, origin, prev, uid;
uid = json['uid'], beginning = json['beginning'], end = json['end'], prev = json['prev'], next = json['next'], origin = json['origin'];
return new WordType(uid, beginning, end, prev, next, origin);
};
types['TextInsert'] = TextInsert;
types['TextDelete'] = TextDelete;
types['WordType'] = WordType;
return structured_types;
};
}).call(this);
//# sourceMappingURL=../Types/TextTypes.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,409 @@
(function() {
var dont_proxy, json_types_uninitialized, proxy_token, _proxy,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
json_types_uninitialized = require("./JsonTypes");
proxy_token = false;
dont_proxy = function(f) {
var e;
proxy_token = true;
try {
f();
} catch (_error) {
e = _error;
proxy_token = false;
throw new Error(e);
}
return proxy_token = false;
};
_proxy = function(f_name, f) {
var old_f;
old_f = this[f_name];
if (old_f != null) {
return this[f_name] = function() {
var args, that, _ref;
if (!proxy_token && !((_ref = this._yatta) != null ? _ref.isDeleted() : void 0)) {
that = this;
args = arguments;
return dont_proxy(function() {
f.apply(that, args);
return old_f.apply(that, args);
});
} else {
return old_f.apply(this, arguments);
}
};
}
};
if (typeof Element !== "undefined" && Element !== null) {
Element.prototype._proxy = _proxy;
}
module.exports = function(HB) {
var TextNodeType, XmlType, json_types, parser, types;
json_types = json_types_uninitialized(HB);
types = json_types.types;
parser = json_types.parser;
XmlType = (function(_super) {
__extends(XmlType, _super);
function XmlType(uid, tagname, attributes, elements, xml) {
var attr, d, element, i, n, word, _i, _j, _len, _ref, _ref1, _ref2;
this.tagname = tagname;
this.xml = xml;
/* In case you make this instanceof Insert again
if prev? and (not next?) and prev.type?
* adjust what you actually mean. you want to insert after prev, then
* next is not defined. but we only insert after non-deleted elements.
* This is also handled in TextInsert.
while prev.isDeleted()
prev = prev.prev_cl
next = prev.next_cl
*/
XmlType.__super__.constructor.call(this, uid);
if (((_ref = this.xml) != null ? _ref._yatta : void 0) != null) {
d = new types.Delete(void 0, this.xml._yatta);
HB.addOperation(d).execute();
this.xml._yatta = null;
}
if ((attributes != null) && (elements != null)) {
this.saveOperation('attributes', attributes);
this.saveOperation('elements', elements);
} else if ((attributes == null) && (elements == null)) {
this.attributes = new types.JsonType();
this.attributes.setMutableDefault('immutable');
HB.addOperation(this.attributes).execute();
this.elements = new types.WordType();
this.elements.parent = this;
HB.addOperation(this.elements).execute();
} else {
throw new Error("Either define attribute and elements both, or none of them");
}
if (this.xml != null) {
this.tagname = this.xml.tagName;
for (i = _i = 0, _ref1 = this.xml.attributes.length; 0 <= _ref1 ? _i < _ref1 : _i > _ref1; i = 0 <= _ref1 ? ++_i : --_i) {
attr = xml.attributes[i];
this.attributes.val(attr.name, attr.value);
}
_ref2 = this.xml.childNodes;
for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
n = _ref2[_j];
if (n.nodeType === n.TEXT_NODE) {
word = new TextNodeType(void 0, n);
HB.addOperation(word).execute();
this.elements.push(word);
} else if (n.nodeType === n.ELEMENT_NODE) {
element = new XmlType(void 0, void 0, void 0, void 0, n);
HB.addOperation(element).execute();
this.elements.push(element);
} else {
throw new Error("I don't know Node-type " + n.nodeType + "!!");
}
}
this.setXmlProxy();
}
void 0;
}
XmlType.prototype.type = "XmlType";
XmlType.prototype.applyDelete = function(op) {
if ((this.insert_parent != null) && !this.insert_parent.isDeleted()) {
return this.insert_parent.applyDelete(op);
} else {
this.attributes.applyDelete();
this.elements.applyDelete();
return XmlType.__super__.applyDelete.apply(this, arguments);
}
};
XmlType.prototype.cleanup = function() {
return XmlType.__super__.cleanup.call(this);
};
XmlType.prototype.setXmlProxy = function() {
var findNode, insertBefore, removeChild, renewClassList, that;
this.xml._yatta = this;
that = this;
this.elements.on('insert', function(event, op) {
var newNode, right, rightNode;
if (op.creator !== HB.getUserId() && this === that.elements) {
newNode = op.content.val();
right = op.next_cl;
while ((right != null) && right.isDeleted()) {
right = right.next_cl;
}
rightNode = null;
if (right.type !== 'Delimiter') {
rightNode = right.val().val();
}
return dont_proxy(function() {
return that.xml.insertBefore(newNode, rightNode);
});
}
});
this.elements.on('delete', function(event, op) {
var del_op, deleted;
del_op = op.deleted_by[0];
if ((del_op != null) && del_op.creator !== HB.getUserId() && this === that.elements) {
deleted = op.content.val();
return dont_proxy(function() {
return that.xml.removeChild(deleted);
});
}
});
this.attributes.on(['add', 'update'], function(event, property_name, op) {
if (op.creator !== HB.getUserId() && this === that.attributes) {
return dont_proxy(function() {
var newval;
newval = op.val().val();
if (newval != null) {
return that.xml.setAttribute(property_name, op.val().val());
} else {
return that.xml.removeAttribute(property_name);
}
});
}
});
findNode = function(child) {
var elem;
if (child == null) {
throw new Error("you must specify a parameter!");
}
child = child._yatta;
elem = that.elements.beginning.next_cl;
while (elem.type !== 'Delimiter' && elem.content !== child) {
elem = elem.next_cl;
}
if (elem.type === 'Delimiter') {
return false;
} else {
return elem;
}
};
insertBefore = function(insertedNode_s, adjacentNode) {
var child, element, inserted_nodes, next, prev, _results;
next = null;
if (adjacentNode != null) {
next = findNode(adjacentNode);
}
prev = null;
if (next) {
prev = next.prev_cl;
} else {
prev = this._yatta.elements.end.prev_cl;
while (prev.isDeleted()) {
prev = prev.prev_cl;
}
}
inserted_nodes = null;
if (insertedNode_s.nodeType === insertedNode_s.DOCUMENT_FRAGMENT_NODE) {
child = insertedNode_s.lastChild;
_results = [];
while (child != null) {
element = new XmlType(void 0, void 0, void 0, void 0, child);
HB.addOperation(element).execute();
that.elements.insertAfter(prev, element);
_results.push(child = child.previousSibling);
}
return _results;
} else {
element = new XmlType(void 0, void 0, void 0, void 0, insertedNode_s);
HB.addOperation(element).execute();
return that.elements.insertAfter(prev, element);
}
};
this.xml._proxy('insertBefore', insertBefore);
this.xml._proxy('appendChild', insertBefore);
this.xml._proxy('removeAttribute', function(name) {
return that.attributes.val(name, void 0);
});
this.xml._proxy('setAttribute', function(name, value) {
return that.attributes.val(name, value);
});
renewClassList = function(newclass) {
var dont_do_it, elem, value, _i, _len;
dont_do_it = false;
if (newclass != null) {
for (_i = 0, _len = this.length; _i < _len; _i++) {
elem = this[_i];
if (newclass === elem) {
dont_do_it = true;
}
}
}
value = Array.prototype.join.call(this, " ");
if ((newclass != null) && !dont_do_it) {
value += " " + newclass;
}
return that.attributes.val('class', value);
};
_proxy.call(this.xml.classList, 'add', renewClassList);
_proxy.call(this.xml.classList, 'remove', renewClassList);
this.xml.__defineSetter__('className', function(val) {
return this.setAttribute('class', val);
});
this.xml.__defineGetter__('className', function() {
return that.attributes.val('class');
});
this.xml.__defineSetter__('textContent', function(val) {
var elem, remove, text_node;
elem = that.xml.firstChild;
while (elem != null) {
remove = elem;
elem = elem.nextSibling;
that.xml.removeChild(remove);
}
if (val !== "") {
text_node = document.createTextNode(val);
return that.xml.appendChild(text_node);
}
});
removeChild = function(node) {
var d, elem;
elem = findNode(node);
if (!elem) {
throw new Error("You are only allowed to delete existing (direct) child elements!");
}
d = new types.Delete(void 0, elem);
HB.addOperation(d).execute();
return node._yatta = null;
};
this.xml._proxy('removeChild', removeChild);
return this.xml._proxy('replaceChild', function(insertedNode, replacedNode) {
insertBefore.call(this, insertedNode, replacedNode);
return removeChild.call(this, replacedNode);
});
};
XmlType.prototype.val = function(enforce) {
var a, attr, attr_name, e, n, text_node, value;
if (enforce == null) {
enforce = false;
}
if (typeof document !== "undefined" && document !== null) {
if ((this.xml == null) || enforce) {
this.xml = document.createElement(this.tagname);
attr = this.attributes.val();
for (attr_name in attr) {
value = attr[attr_name];
if (value != null) {
a = document.createAttribute(attr_name);
a.value = value;
this.xml.setAttributeNode(a);
}
}
e = this.elements.beginning.next_cl;
while (e.type !== "Delimiter") {
n = e.content;
if (!e.isDeleted() && (e.content != null)) {
if (n.type === "XmlType") {
this.xml.appendChild(n.val(enforce));
} else if (n.type === "TextNodeType") {
text_node = n.val();
this.xml.appendChild(text_node);
} else {
throw new Error("Internal structure cannot be transformed to dom");
}
}
e = e.next_cl;
}
}
this.setXmlProxy();
return this.xml;
}
};
XmlType.prototype.execute = function() {
return XmlType.__super__.execute.call(this);
};
/*
if not @validateSavedOperations()
return false
else
return true
*/
XmlType.prototype.getParent = function() {
return this.parent;
};
XmlType.prototype._encode = function() {
var json;
json = {
'type': this.type,
'attributes': this.attributes.getUid(),
'elements': this.elements.getUid(),
'tagname': this.tagname,
'uid': this.getUid()
};
return json;
};
return XmlType;
})(types.Insert);
parser['XmlType'] = function(json) {
var attributes, elements, tagname, uid;
uid = json['uid'], attributes = json['attributes'], elements = json['elements'], tagname = json['tagname'];
return new XmlType(uid, tagname, attributes, elements, void 0);
};
TextNodeType = (function(_super) {
__extends(TextNodeType, _super);
function TextNodeType(uid, content) {
var d;
if (content._yatta != null) {
d = new types.Delete(void 0, content._yatta);
HB.addOperation(d).execute();
content._yatta = null;
}
content._yatta = this;
TextNodeType.__super__.constructor.call(this, uid, content);
}
TextNodeType.prototype.applyDelete = function(op) {
if ((this.insert_parent != null) && !this.insert_parent.isDeleted()) {
return this.insert_parent.applyDelete(op);
} else {
return TextNodeType.__super__.applyDelete.apply(this, arguments);
}
};
TextNodeType.prototype.type = "TextNodeType";
TextNodeType.prototype._encode = function() {
var json;
json = {
'type': this.type,
'uid': this.getUid(),
'content': this.content.textContent
};
return json;
};
return TextNodeType;
})(types.ImmutableObject);
parser['TextNodeType'] = function(json) {
var content, textnode, uid;
uid = json['uid'], content = json['content'];
textnode = document.createTextNode(content);
return new TextNodeType(uid, textnode);
};
types['XmlType'] = XmlType;
return json_types;
};
}).call(this);
//# sourceMappingURL=../Types/XmlTypes.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,7 @@
(function() { (function() {
var Engine, HistoryBuffer, Yatta, adaptConnector, json_types_uninitialized; var Engine, HistoryBuffer, adaptConnector, createYatta, json_types_uninitialized,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
json_types_uninitialized = require("./Types/JsonTypes"); json_types_uninitialized = require("./Types/JsonTypes");
@ -9,89 +11,35 @@
adaptConnector = require("./ConnectorAdapter"); adaptConnector = require("./ConnectorAdapter");
Yatta = (function() { createYatta = function(connector) {
function Yatta(connector) { var HB, Yatta, type_manager, types, user_id;
var beg, end, first_word, type_manager, uid_beg, uid_end, user_id; user_id = connector.id;
this.connector = connector; HB = new HistoryBuffer(user_id);
user_id = this.connector.id; type_manager = json_types_uninitialized(HB);
this.HB = new HistoryBuffer(user_id); types = type_manager.types;
type_manager = json_types_uninitialized(this.HB); Yatta = (function(_super) {
this.types = type_manager.types; __extends(Yatta, _super);
this.engine = new Engine(this.HB, type_manager.parser);
this.HB.engine = this.engine;
adaptConnector(this.connector, this.engine, this.HB, type_manager.execution_listener);
first_word = new this.types.JsonType(this.HB.getReservedUniqueIdentifier()).execute();
uid_beg = this.HB.getReservedUniqueIdentifier();
uid_end = this.HB.getReservedUniqueIdentifier();
beg = (new this.types.Delimiter(uid_beg, void 0, uid_end)).execute();
end = (new this.types.Delimiter(uid_end, beg, void 0)).execute();
this.root_element = (new this.types.ReplaceManager(void 0, this.HB.getReservedUniqueIdentifier(), beg, end)).execute();
this.root_element.replace(first_word, this.HB.getReservedUniqueIdentifier());
}
Yatta.prototype.getSharedObject = function() { function Yatta() {
return this.root_element.val(); this.connector = connector;
}; this.HB = HB;
this.types = types;
this.engine = new Engine(this.HB, type_manager.parser);
adaptConnector(this.connector, this.engine, this.HB, type_manager.execution_listener);
Yatta.__super__.constructor.apply(this, arguments);
}
Yatta.prototype.getConnector = function() { Yatta.prototype.getConnector = function() {
return this.connector; return this.connector;
}; };
Yatta.prototype.getHistoryBuffer = function() {
return this.HB;
};
Yatta.prototype.setMutableDefault = function(mutable) {
return this.getSharedObject().setMutableDefault(mutable);
};
Yatta.prototype.getUserId = function() {
return this.HB.getUserId();
};
Yatta.prototype.toJson = function() {
return this.getSharedObject().toJson();
};
Yatta.prototype.val = function() {
var _ref;
return (_ref = this.getSharedObject()).val.apply(_ref, arguments);
};
Yatta.prototype.on = function() {
var _ref;
return (_ref = this.getSharedObject()).on.apply(_ref, arguments);
};
Yatta.prototype.deleteListener = function() {
var _ref;
return (_ref = this.getSharedObject()).deleteListener.apply(_ref, arguments);
};
Object.defineProperty(Yatta.prototype, 'value', {
get: function() {
return this.getSharedObject().value;
},
set: function(o) {
var o_name, o_obj, _results;
if (o.constructor === {}.constructor) {
_results = [];
for (o_name in o) {
o_obj = o[o_name];
_results.push(this.val(o_name, o_obj, 'immutable'));
}
return _results;
} else {
throw new Error("You must only set Object values!");
}
}
});
return Yatta; return Yatta;
})(); })(types.JsonType);
return new Yatta(HB.getReservedUniqueIdentifier()).execute();
};
module.exports = Yatta; module.exports = createYatta;
if ((typeof window !== "undefined" && window !== null) && (window.Yatta == null)) { if ((typeof window !== "undefined" && window !== null) && (window.Yatta == null)) {
window.Yatta = Yatta; window.Yatta = Yatta;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,12 +13,13 @@
mocha.ui('bdd'); mocha.ui('bdd');
mocha.reporter('html'); mocha.reporter('html');
</script> </script>
<!--script src="TextYatta_test.js"></script--> <script src="TextYatta_test.js"></script>
<script src="JsonYatta_test.js"></script> <script src="JsonYatta_test.js"></script>
<!--script src="XmlYatta_test_browser.js"></script--> <!--script src="XmlYatta_test_browser.js"></script-->
<script> <script>
//mocha.checkLeaks(); //mocha.checkLeaks();
//mocha.run(); //mocha.run();
window.onerror = null;
if (window.mochaPhantomJS) { mochaPhantomJS.run(); } if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
else { mocha.run(); } else { mocha.run(); }
</script> </script>

View File

@ -178,7 +178,7 @@
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -359,7 +359,7 @@ E.g.: let x = {a:[]}. Then x.a.push 1 wouldn&#39;t change anything</p>
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -139,7 +139,7 @@ console.log(w.newProperty == &quot;Awesome&quot;) # true!</code></pre>
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -389,7 +389,7 @@ yatta.bind(textbox);</code></pre>
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -32,6 +32,12 @@
<td>Defined in:</td> <td>Defined in:</td>
<td>lib&#47;Yatta.coffee</td> <td>lib&#47;Yatta.coffee</td>
</tr> </tr>
<tr>
<td>Inherits:</td>
<td>
types.JsonType
</td>
</tr>
</table> </table>
<h2>Overview</h2> <h2>Overview</h2>
<div class='docstring'> <div class='docstring'>
@ -47,17 +53,6 @@ Known values that are supported:</p><ul>
</div> </div>
<h2>Instance Method Summary</h2> <h2>Instance Method Summary</h2>
<ul class='summary'> <ul class='summary'>
<li>
<span class='signature'>
<a href='#getSharedObject-dynamic'>
#
(?)
<b>getSharedObject</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li> <li>
<span class='signature'> <span class='signature'>
<a href='#getConnector-dynamic'> <a href='#getConnector-dynamic'>
@ -66,85 +61,6 @@ Known values that are supported:</p><ul>
<b>getConnector</b><span>()</span> <b>getConnector</b><span>()</span>
</a> </a>
</span> </span>
<span class='desc'>
Get the initialized connector.
</span>
</li>
<li>
<span class='signature'>
<a href='#getHistoryBuffer-dynamic'>
#
(void)
<b>getHistoryBuffer</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#setMutableDefault-dynamic'>
#
(void)
<b>setMutableDefault</b><span>(mutable)</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#getUserId-dynamic'>
#
(void)
<b>getUserId</b><span>()</span>
</a>
</span>
<span class='desc'>
Get the UserId from the HistoryBuffer object.
</span>
</li>
<li>
<span class='signature'>
<a href='#toJson-dynamic'>
#
(void)
<b>toJson</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#val-dynamic'>
#
(void)
<b>val</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#observe-dynamic'>
#
(void)
<b>observe</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#unobserve-dynamic'>
#
(void)
<b>unobserve</b><span>()</span>
</a>
</span>
<span class='desc'> <span class='desc'>
</span> </span>
</li> </li>
@ -155,7 +71,7 @@ Known values that are supported:</p><ul>
<p class='signature' id='constructor-dynamic'> <p class='signature' id='constructor-dynamic'>
# #
(void) (void)
<b>constructor</b><span>(connector)</span> <b>constructor</b><span>()</span>
<br> <br>
</p> </p>
<div class='tags'> <div class='tags'>
@ -187,27 +103,6 @@ Known values that are supported:</p><ul>
</div> </div>
<h2>Instance Method Details</h2> <h2>Instance Method Details</h2>
<div class='methods'> <div class='methods'>
<div class='method_details'>
<p class='signature' id='getSharedObject-dynamic'>
#
(?)
<b>getSharedObject</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>Returns:</h3>
<ul class='return'>
<li>
<span class='type'></span>
(
<tt>?</tt>
)
&mdash;
<span class='desc'>JsonType </span>
</li>
</ul>
</div>
</div>
<div class='method_details'> <div class='method_details'>
<p class='signature' id='getConnector-dynamic'> <p class='signature' id='getConnector-dynamic'>
# #
@ -215,127 +110,12 @@ Known values that are supported:</p><ul>
<b>getConnector</b><span>()</span> <b>getConnector</b><span>()</span>
<br> <br>
</p> </p>
<div class='docstring'>
<p>Get the initialized connector.</p>
</div>
<div class='tags'>
</div>
</div>
<div class='method_details'>
<p class='signature' id='getHistoryBuffer-dynamic'>
#
(void)
<b>getHistoryBuffer</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='HistoryBuffer'>HistoryBuffer</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='setMutableDefault-dynamic'>
#
(void)
<b>setMutableDefault</b><span>(mutable)</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='JsonType.setMutableDefault'>JsonType.setMutableDefault</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='getUserId-dynamic'>
#
(void)
<b>getUserId</b><span>()</span>
<br>
</p>
<div class='docstring'>
<p>Get the UserId from the HistoryBuffer object.
In most cases this will be the same as the user_id value with which
Yatta was initialized (Depending on the HistoryBuffer implementation).</p>
</div>
<div class='tags'>
</div>
</div>
<div class='method_details'>
<p class='signature' id='toJson-dynamic'>
#
(void)
<b>toJson</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='JsonType.toJson'>JsonType.toJson</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='val-dynamic'>
#
(void)
<b>val</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='JsonType.val'>JsonType.val</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='observe-dynamic'>
#
(void)
<b>observe</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='Operation.on'>Operation.on</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='unobserve-dynamic'>
#
(void)
<b>unobserve</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='Operation.deleteListener'>Operation.deleteListener</a>
</li>
</ul>
</div>
</div> </div>
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -65,6 +65,10 @@
<a href='class/Yatta.html' target='main'> <a href='class/Yatta.html' target='main'>
Yatta Yatta
</a> </a>
<small class='parent'>
<
types.JsonType
</small>
<small class='namespace'> <small class='namespace'>
</small> </small>

View File

@ -38,7 +38,7 @@
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -76,7 +76,7 @@ But I would become really motivated if you gave me some feedback :) (<a href="ht
</ul> </ul>
<h2 id="support">Support</h2><p>Please report <em>any</em> issues to the <a href="https://github.com/DadaMonad/Yatta/issues">Github issue page</a>! <h2 id="support">Support</h2><p>Please report <em>any</em> issues to the <a href="https://github.com/DadaMonad/Yatta/issues">Github issue page</a>!
I would appreciate if developers gave me feedback on how <em>convenient</em> the framework is, and if it is easy to use. Particularly the XML-support may not support every DOM-methods - if you encounter a method that does not cause any change on other peers, I would appreciate if developers gave me feedback on how <em>convenient</em> the framework is, and if it is easy to use. Particularly the XML-support may not support every DOM-methods - if you encounter a method that does not cause any change on other peers,
please state function name, and sample parameters. However, there are browser-specific features, that Yatta won&#39;t support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="&#109;&#97;&#105;&#108;&#x74;&#111;&#58;&#107;&#101;&#118;&#x69;&#x6e;&#x2e;&#x6a;&#x61;&#104;&#x6e;&#115;&#64;&#x72;&#119;&#x74;&#104;&#45;&#x61;&#97;&#99;&#104;&#101;&#110;&#x2e;&#100;&#101;">&#107;&#101;&#118;&#x69;&#x6e;&#x2e;&#x6a;&#x61;&#104;&#x6e;&#115;&#64;&#x72;&#119;&#x74;&#104;&#45;&#x61;&#97;&#99;&#104;&#101;&#110;&#x2e;&#100;&#101;</a> please state function name, and sample parameters. However, there are browser-specific features, that Yatta won&#39;t support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="&#x6d;&#97;&#x69;&#108;&#116;&#111;&#58;&#107;&#101;&#118;&#105;&#110;&#46;&#x6a;&#x61;&#x68;&#x6e;&#115;&#x40;&#x72;&#119;&#116;&#x68;&#45;&#x61;&#97;&#x63;&#104;&#x65;&#110;&#x2e;&#x64;&#x65;">&#107;&#101;&#118;&#105;&#110;&#46;&#x6a;&#x61;&#x68;&#x6e;&#115;&#x40;&#x72;&#119;&#116;&#x68;&#45;&#x61;&#97;&#x63;&#104;&#x65;&#110;&#x2e;&#x64;&#x65;</a>
@ -85,7 +85,7 @@ please state function name, and sample parameters. However, there are browser-sp
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -106,7 +106,7 @@
</div> </div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -72,7 +72,7 @@
</dl> </dl>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -48,7 +48,7 @@
</dl> </dl>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -39,7 +39,7 @@
</table> </table>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -39,7 +39,7 @@
</table> </table>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -39,7 +39,7 @@
</table> </table>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -39,7 +39,7 @@
</table> </table>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -34,16 +34,6 @@
<td>Defined in:</td> <td>Defined in:</td>
<td>lib</td> <td>lib</td>
</tr> </tr>
<tr>
<td>
Classes:
</td>
<td>
<a href='../../class/Yatta.html'>
Yatta
</a>
</td>
</tr>
</table> </table>
<h2>Variables Summary</h2> <h2>Variables Summary</h2>
<dl class='constants'> <dl class='constants'>
@ -52,13 +42,39 @@
= =
</dt> </dt>
<dd> <dd>
<pre><code class='coffeescript'>Yatta</code></pre> <pre><code class='coffeescript'>createYatta</code></pre>
</dd> </dd>
</dl> </dl>
<h2>Method Summary</h2>
<ul class='summary'>
<li>
<span class='signature'>
<a href='#createYatta-'>
~
(void)
<b>createYatta</b><span>(connector)</span>
</a>
</span>
<span class='desc'>
</span>
</li>
</ul>
<h2>Method Details</h2>
<div class='methods'>
<div class='method_details'>
<p class='signature' id='createYatta-'>
~
(void)
<b>createYatta</b><span>(connector)</span>
<br>
</p>
</div>
</div>
</div> </div>
<div id='footer'> <div id='footer'>
December 17, 14 22:46:39 by December 22, 14 14:36:45 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'> <a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo Codo
</a> </a>

View File

@ -1 +1 @@
window.searchData = [{"t":"JsonTypeWrapper","p":"class/JsonTypeWrapper.html"},{"t":"JsonType","p":"class/JsonType.html"},{"t":"WordType","p":"class/WordType.html"},{"t":"Yatta","p":"class/Yatta.html"},{"t":"lib/ConnectorAdapter.coffee","p":"file/lib/ConnectorAdapter.coffee.html"},{"t":"lib/Engine.coffee","p":"file/lib/Engine.coffee.html"},{"t":"lib/HistoryBuffer.coffee","p":"file/lib/HistoryBuffer.coffee.html"},{"t":"lib/Types/BasicTypes.coffee","p":"file/lib/Types/BasicTypes.coffee.html"},{"t":"lib/Types/JsonTypes.coffee","p":"file/lib/Types/JsonTypes.coffee.html"},{"t":"lib/Types/StructuredTypes.coffee","p":"file/lib/Types/StructuredTypes.coffee.html"},{"t":"lib/Types/TextTypes.coffee","p":"file/lib/Types/TextTypes.coffee.html"},{"t":"lib/Yatta.coffee","p":"file/lib/Yatta.coffee.html"},{"t":"README.md","p":"extra/README.md.html"},{"t":"LICENSE.txt","p":"extra/LICENSE.txt.html"},{"t":"JsonType#_encode","p":"class/JsonType.html#_encode-dynamic"},{"t":"WordType#_encode","p":"class/WordType.html#_encode-dynamic"},{"t":"lib/ConnectorAdapter.coffee~adaptConnector","p":"file/lib/ConnectorAdapter.coffee.html#adaptConnector-"},{"t":"WordType#applyDelete","p":"class/WordType.html#applyDelete-dynamic"},{"t":"JsonType#applyDelete","p":"class/JsonType.html#applyDelete-dynamic"},{"t":"WordType#bind","p":"class/WordType.html#bind-dynamic"},{"t":"JsonType#cleanup","p":"class/JsonType.html#cleanup-dynamic"},{"t":"WordType#cleanup","p":"class/WordType.html#cleanup-dynamic"},{"t":"Yatta#constructor","p":"class/Yatta.html#constructor-dynamic"},{"t":"WordType#constructor","p":"class/WordType.html#constructor-dynamic"},{"t":"JsonTypeWrapper#constructor","p":"class/JsonTypeWrapper.html#constructor-dynamic"},{"t":"WordType#deleteText","p":"class/WordType.html#deleteText-dynamic"},{"t":"Yatta#getConnector","p":"class/Yatta.html#getConnector-dynamic"},{"t":"Yatta#getHistoryBuffer","p":"class/Yatta.html#getHistoryBuffer-dynamic"},{"t":"Yatta#getSharedObject","p":"class/Yatta.html#getSharedObject-dynamic"},{"t":"Yatta#getUserId","p":"class/Yatta.html#getUserId-dynamic"},{"t":"WordType#insertAfter","p":"class/WordType.html#insertAfter-dynamic"},{"t":"WordType#insertText","p":"class/WordType.html#insertText-dynamic"},{"t":"Yatta#observe","p":"class/Yatta.html#observe-dynamic"},{"t":"WordType#push","p":"class/WordType.html#push-dynamic"},{"t":"Yatta#setMutableDefault","p":"class/Yatta.html#setMutableDefault-dynamic"},{"t":"JsonType#setMutableDefault","p":"class/JsonType.html#setMutableDefault-dynamic"},{"t":"JsonType#toJson","p":"class/JsonType.html#toJson-dynamic"},{"t":"Yatta#toJson","p":"class/Yatta.html#toJson-dynamic"},{"t":"WordType#toString","p":"class/WordType.html#toString-dynamic"},{"t":"Yatta#unobserve","p":"class/Yatta.html#unobserve-dynamic"},{"t":"Yatta#val","p":"class/Yatta.html#val-dynamic"},{"t":"WordType#val","p":"class/WordType.html#val-dynamic"},{"t":"JsonType#val","p":"class/JsonType.html#val-dynamic"}] window.searchData = [{"t":"JsonTypeWrapper","p":"class/JsonTypeWrapper.html"},{"t":"JsonType","p":"class/JsonType.html"},{"t":"WordType","p":"class/WordType.html"},{"t":"Yatta","p":"class/Yatta.html"},{"t":"lib/ConnectorAdapter.coffee","p":"file/lib/ConnectorAdapter.coffee.html"},{"t":"lib/Engine.coffee","p":"file/lib/Engine.coffee.html"},{"t":"lib/HistoryBuffer.coffee","p":"file/lib/HistoryBuffer.coffee.html"},{"t":"lib/Types/BasicTypes.coffee","p":"file/lib/Types/BasicTypes.coffee.html"},{"t":"lib/Types/JsonTypes.coffee","p":"file/lib/Types/JsonTypes.coffee.html"},{"t":"lib/Types/StructuredTypes.coffee","p":"file/lib/Types/StructuredTypes.coffee.html"},{"t":"lib/Types/TextTypes.coffee","p":"file/lib/Types/TextTypes.coffee.html"},{"t":"lib/Yatta.coffee","p":"file/lib/Yatta.coffee.html"},{"t":"README.md","p":"extra/README.md.html"},{"t":"LICENSE.txt","p":"extra/LICENSE.txt.html"},{"t":"WordType#_encode","p":"class/WordType.html#_encode-dynamic"},{"t":"JsonType#_encode","p":"class/JsonType.html#_encode-dynamic"},{"t":"lib/ConnectorAdapter.coffee~adaptConnector","p":"file/lib/ConnectorAdapter.coffee.html#adaptConnector-"},{"t":"JsonType#applyDelete","p":"class/JsonType.html#applyDelete-dynamic"},{"t":"WordType#applyDelete","p":"class/WordType.html#applyDelete-dynamic"},{"t":"WordType#bind","p":"class/WordType.html#bind-dynamic"},{"t":"JsonType#cleanup","p":"class/JsonType.html#cleanup-dynamic"},{"t":"WordType#cleanup","p":"class/WordType.html#cleanup-dynamic"},{"t":"Yatta#constructor","p":"class/Yatta.html#constructor-dynamic"},{"t":"JsonTypeWrapper#constructor","p":"class/JsonTypeWrapper.html#constructor-dynamic"},{"t":"WordType#constructor","p":"class/WordType.html#constructor-dynamic"},{"t":"lib/Yatta.coffee~createYatta","p":"file/lib/Yatta.coffee.html#createYatta-"},{"t":"WordType#deleteText","p":"class/WordType.html#deleteText-dynamic"},{"t":"Yatta#getConnector","p":"class/Yatta.html#getConnector-dynamic"},{"t":"WordType#insertAfter","p":"class/WordType.html#insertAfter-dynamic"},{"t":"WordType#insertText","p":"class/WordType.html#insertText-dynamic"},{"t":"WordType#push","p":"class/WordType.html#push-dynamic"},{"t":"JsonType#setMutableDefault","p":"class/JsonType.html#setMutableDefault-dynamic"},{"t":"JsonType#toJson","p":"class/JsonType.html#toJson-dynamic"},{"t":"WordType#toString","p":"class/WordType.html#toString-dynamic"},{"t":"WordType#val","p":"class/WordType.html#val-dynamic"},{"t":"JsonType#val","p":"class/JsonType.html#val-dynamic"}]

View File

@ -29,14 +29,6 @@
<input type='text'> <input type='text'>
</div> </div>
<ul> <ul>
<li>
<a href='class/JsonType.html#_encode-dynamic' target='main' title='_encode'>
#_encode
</a>
<small>
(JsonType)
</small>
</li>
<li> <li>
<a href='class/WordType.html#_encode-dynamic' target='main' title='_encode'> <a href='class/WordType.html#_encode-dynamic' target='main' title='_encode'>
#_encode #_encode
@ -45,6 +37,14 @@
(WordType) (WordType)
</small> </small>
</li> </li>
<li>
<a href='class/JsonType.html#_encode-dynamic' target='main' title='_encode'>
#_encode
</a>
<small>
(JsonType)
</small>
</li>
<li> <li>
<a href='file/lib/ConnectorAdapter.coffee.html#adaptConnector-' target='main' title='adaptConnector'> <a href='file/lib/ConnectorAdapter.coffee.html#adaptConnector-' target='main' title='adaptConnector'>
~adaptConnector ~adaptConnector
@ -53,14 +53,6 @@
(lib&#47;ConnectorAdapter.coffee) (lib&#47;ConnectorAdapter.coffee)
</small> </small>
</li> </li>
<li>
<a href='class/WordType.html#applyDelete-dynamic' target='main' title='applyDelete'>
#applyDelete
</a>
<small>
(WordType)
</small>
</li>
<li> <li>
<a href='class/JsonType.html#applyDelete-dynamic' target='main' title='applyDelete'> <a href='class/JsonType.html#applyDelete-dynamic' target='main' title='applyDelete'>
#applyDelete #applyDelete
@ -69,6 +61,14 @@
(JsonType) (JsonType)
</small> </small>
</li> </li>
<li>
<a href='class/WordType.html#applyDelete-dynamic' target='main' title='applyDelete'>
#applyDelete
</a>
<small>
(WordType)
</small>
</li>
<li> <li>
<a href='class/WordType.html#bind-dynamic' target='main' title='bind'> <a href='class/WordType.html#bind-dynamic' target='main' title='bind'>
#bind #bind
@ -101,6 +101,14 @@
(Yatta) (Yatta)
</small> </small>
</li> </li>
<li>
<a href='class/JsonTypeWrapper.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(JsonTypeWrapper)
</small>
</li>
<li> <li>
<a href='class/WordType.html#constructor-dynamic' target='main' title='constructor'> <a href='class/WordType.html#constructor-dynamic' target='main' title='constructor'>
#constructor #constructor
@ -110,11 +118,11 @@
</small> </small>
</li> </li>
<li> <li>
<a href='class/JsonTypeWrapper.html#constructor-dynamic' target='main' title='constructor'> <a href='file/lib/Yatta.coffee.html#createYatta-' target='main' title='createYatta'>
#constructor ~createYatta
</a> </a>
<small> <small>
(JsonTypeWrapper) (lib&#47;Yatta.coffee)
</small> </small>
</li> </li>
<li> <li>
@ -133,30 +141,6 @@
(Yatta) (Yatta)
</small> </small>
</li> </li>
<li>
<a href='class/Yatta.html#getHistoryBuffer-dynamic' target='main' title='getHistoryBuffer'>
#getHistoryBuffer
</a>
<small>
(Yatta)
</small>
</li>
<li>
<a href='class/Yatta.html#getSharedObject-dynamic' target='main' title='getSharedObject'>
#getSharedObject
</a>
<small>
(Yatta)
</small>
</li>
<li>
<a href='class/Yatta.html#getUserId-dynamic' target='main' title='getUserId'>
#getUserId
</a>
<small>
(Yatta)
</small>
</li>
<li> <li>
<a href='class/WordType.html#insertAfter-dynamic' target='main' title='insertAfter'> <a href='class/WordType.html#insertAfter-dynamic' target='main' title='insertAfter'>
#insertAfter #insertAfter
@ -173,14 +157,6 @@
(WordType) (WordType)
</small> </small>
</li> </li>
<li>
<a href='class/Yatta.html#observe-dynamic' target='main' title='observe'>
#observe
</a>
<small>
(Yatta)
</small>
</li>
<li> <li>
<a href='class/WordType.html#push-dynamic' target='main' title='push'> <a href='class/WordType.html#push-dynamic' target='main' title='push'>
#push #push
@ -189,14 +165,6 @@
(WordType) (WordType)
</small> </small>
</li> </li>
<li>
<a href='class/Yatta.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'>
#setMutableDefault
</a>
<small>
(Yatta)
</small>
</li>
<li> <li>
<a href='class/JsonType.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'> <a href='class/JsonType.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'>
#setMutableDefault #setMutableDefault
@ -213,14 +181,6 @@
(JsonType) (JsonType)
</small> </small>
</li> </li>
<li>
<a href='class/Yatta.html#toJson-dynamic' target='main' title='toJson'>
#toJson
</a>
<small>
(Yatta)
</small>
</li>
<li> <li>
<a href='class/WordType.html#toString-dynamic' target='main' title='toString'> <a href='class/WordType.html#toString-dynamic' target='main' title='toString'>
#toString #toString
@ -229,22 +189,6 @@
(WordType) (WordType)
</small> </small>
</li> </li>
<li>
<a href='class/Yatta.html#unobserve-dynamic' target='main' title='unobserve'>
#unobserve
</a>
<small>
(Yatta)
</small>
</li>
<li>
<a href='class/Yatta.html#val-dynamic' target='main' title='val'>
#val
</a>
<small>
(Yatta)
</small>
</li>
<li> <li>
<a href='class/WordType.html#val-dynamic' target='main' title='val'> <a href='class/WordType.html#val-dynamic' target='main' title='val'>
#val #val

View File

@ -22,8 +22,17 @@ You don't have to use the proposed user_id.
```js ```js
console.log("me is number 2") // console.log("me is number 1");
yatta = new Y.JsonYatta(2, Connector); // yatta = new JsonYatta(1, Connector);
```
Though, it is recommended to use the user_id
```js
yatta = new Y.JsonYatta(user_id, Connector);
}) })
} }

View File

@ -16,18 +16,18 @@ run = require 'gulp-run'
ljs = require 'gulp-ljs' ljs = require 'gulp-ljs'
plumber = require 'gulp-plumber' plumber = require 'gulp-plumber'
mochaPhantomJS = require 'gulp-mocha-phantomjs' mochaPhantomJS = require 'gulp-mocha-phantomjs'
cache = require 'gulp-cached'
gulp.task 'default', ['lint', 'browser', 'test', 'literate', 'lib', 'codo'] gulp.task 'default', ['deploy']
gulp.task 'build', ['lint', 'browser']
files = files =
lib : ['./lib/**/*.coffee'] lib : ['./lib/**/*.coffee']
build : ['./build/**'] build : ['./build/**']
browser : './lib/Yatta.coffee' browser : './lib/Yatta.coffee'
#test : ['./test/**/*_test.coffee'] #test : ['./test/**/*_test.coffee']
test : ['./test/JsonYatta_test.coffee'] test : ['./test/JsonYatta_test.coffee', './test/TextYatta_test.coffee']
gulp : ['./gulpfile.coffee'] gulp : ['./gulpfile.coffee']
examples : ['./examples/**/*.js'] examples : ['./examples/**/*.js']
other: ['./lib/**/*'] other: ['./lib/**/*']
@ -37,7 +37,7 @@ for name,file_list of files
if name isnt 'build' if name isnt 'build'
files.all = files.all.concat file_list files.all = files.all.concat file_list
gulp.task 'lib', -> gulp.task 'deploy_nodejs', ->
gulp.src files.lib gulp.src files.lib
.pipe sourcemaps.init() .pipe sourcemaps.init()
.pipe coffee() .pipe coffee()
@ -45,7 +45,9 @@ gulp.task 'lib', ->
.pipe gulp.dest 'build/node/' .pipe gulp.dest 'build/node/'
.pipe gulpif '!**/', git.add({args : "-A"}) .pipe gulpif '!**/', git.add({args : "-A"})
gulp.task 'browser', -> gulp.task 'deploy', ['mocha', 'build_browser', 'deploy_nodejs', 'lint', 'phantom_test', 'codo']
gulp.task 'build_browser', ->
gulp.src files.browser, { read: false } gulp.src files.browser, { read: false }
.pipe plumber() .pipe plumber()
.pipe browserify .pipe browserify
@ -69,12 +71,12 @@ gulp.task 'browser', ->
extname: ".js" extname: ".js"
.pipe gulp.dest './build/test' .pipe gulp.dest './build/test'
gulp.task 'browser_test_watch', ['browser'], -> gulp.task 'watch', ['build_browser','mocha'], ->
gulp.watch files.all, ['browser'] gulp.watch files.all, ['build_browser', 'mocha']
gulp.task 'mocha', ->
gulp.task 'test', ->
gulp.src files.test, { read: false } gulp.src files.test, { read: false }
.pipe plumber()
.pipe mocha {reporter : 'list'} .pipe mocha {reporter : 'list'}
.pipe ignore.include '**/*.coffee' .pipe ignore.include '**/*.coffee'
.pipe browserify .pipe browserify
@ -95,11 +97,6 @@ gulp.task 'lint', ->
} }
.pipe coffeelint.reporter() .pipe coffeelint.reporter()
gulp.task 'watch', ['default'], ->
gulp.watch files.lib, ['build', 'test']
gulp.watch files.test, ['test']
gulp.watch files.examples, ['literate']
gulp.task 'phantom_watch', ['phantom_test'], -> gulp.task 'phantom_watch', ['phantom_test'], ->
gulp.watch files.all, ['phantom_test'] gulp.watch files.all, ['phantom_test']
@ -112,14 +109,11 @@ gulp.task 'literate', ->
.pipe gulp.dest 'examples/' .pipe gulp.dest 'examples/'
.pipe gulpif '!**/', git.add({args : "-A"}) .pipe gulpif '!**/', git.add({args : "-A"})
gulp.task 'upload', [], ()->
run('scp -r ./build ./examples jahns@manet.informatik.rwth-aachen.de:/home/jahns/public_html/collaborative_preview/').exec()
gulp.task 'codo', [], ()-> gulp.task 'codo', [], ()->
command = 'codo -o "./doc" --name "Yatta!" --readme "README.md" --undocumented false --private true --title "Yatta! API" ./lib - LICENSE.txt ' command = 'codo -o "./doc" --name "Yatta!" --readme "README.md" --undocumented false --private true --title "Yatta! API" ./lib - LICENSE.txt '
run(command).exec() run(command).exec()
gulp.task 'phantom_test', ['browser'], ()-> gulp.task 'phantom_test', ['build_browser'], ()->
gulp.src 'build/test/index.html' gulp.src 'build/test/index.html'
.pipe mochaPhantomJS() .pipe mochaPhantomJS()

View File

@ -45,7 +45,7 @@ module.exports = (HB)->
# @overload unobserve(event, f) # @overload unobserve(event, f)
# @param f {Function} The function that you want to delete # @param f {Function} The function that you want to delete
unobserve: (f)-> unobserve: (f)->
@event_listeners.filter (g)-> @event_listeners = @event_listeners.filter (g)->
f isnt g f isnt g
# #
@ -59,7 +59,7 @@ module.exports = (HB)->
# #
# Fire an event. # Fire an event.
# TODO: Do something with timeouts. You don't want this to fire for every operation (e.g. insert). # TODO: Do something with timeouts. You don't want this to fire for every operation (e.g. insert).
# # TODO: do you need callEvent+forwardEvent? Only one suffices probably
callEvent: ()-> callEvent: ()->
@forwardEvent @, arguments... @forwardEvent @, arguments...
@ -215,8 +215,10 @@ module.exports = (HB)->
# #
execute: ()-> execute: ()->
if @validateSavedOperations() if @validateSavedOperations()
res = super
if res
@deletes.applyDelete @ @deletes.applyDelete @
super res
else else
false false
@ -275,7 +277,12 @@ module.exports = (HB)->
garbagecollect = true garbagecollect = true
super garbagecollect super garbagecollect
if callLater if callLater
@parent.callEvent "delete", @, o @parent.callEvent [
type: "insert"
position: @getPosition()
object: @parent # TODO: You can combine getPosition + getParent in a more efficient manner! (only left Delimiter will hold @parent)
changed_by: o.uid.creator
]
if @next_cl?.isDeleted() if @next_cl?.isDeleted()
# garbage collect next_cl # garbage collect next_cl
@next_cl.applyDelete() @next_cl.applyDelete()
@ -317,8 +324,7 @@ module.exports = (HB)->
# #
# @private # @private
# Include this operation in the associative lists. # Include this operation in the associative lists.
# @param fire_event {boolean} Whether to fire the insert-event. execute: ()->
execute: (fire_event = true)->
if not @validateSavedOperations() if not @validateSavedOperations()
return false return false
else else
@ -336,7 +342,8 @@ module.exports = (HB)->
# therefore $this would be always to the right of o3 # therefore $this would be always to the right of o3
# case 2: $origin < $o.origin # case 2: $origin < $o.origin
# if current $this insert_position > $o origin: $this ins # if current $this insert_position > $o origin: $this ins
# else $insert_position will not change (maybe we encounter case 1 later, then this will be to the right of $o) # else $insert_position will not change
# (maybe we encounter case 1 later, then this will be to the right of $o)
# case 3: $origin > $o.origin # case 3: $origin > $o.origin
# $this insert_position is to the left of $o (forever!) # $this insert_position is to the left of $o (forever!)
while true while true
@ -369,13 +376,20 @@ module.exports = (HB)->
@prev_cl.next_cl = @ @prev_cl.next_cl = @
@next_cl.prev_cl = @ @next_cl.prev_cl = @
parent = @prev_cl?.getParent() @setParent @prev_cl.getParent() # do Insertions always have a parent?
super # notify the execution_listeners super # notify the execution_listeners
if parent? and fire_event @callOperationSpecificEvents()
@setParent parent
@parent.callEvent "insert", @
@ @
callOperationSpecificEvents: ()->
@parent?.callEvent [
type: "insert"
position: @getPosition()
object: @parent
changed_by: @uid.creator
value: @content
]
# #
# Compute the position of this operation. # Compute the position of this operation.
# #

View File

@ -148,30 +148,31 @@ module.exports = (HB)->
if not event.changed_by? and (event.type is "add" or event.type = "update") if not event.changed_by? and (event.type is "add" or event.type = "update")
# this event is not created by Yatta. # this event is not created by Yatta.
that.val(event.name, event.object[event.name]) that.val(event.name, event.object[event.name])
that.observe (event_name, property_name, op)-> @observe (events)->
if this is that and op.uid.creator isnt HB.getUserId() for event in events
if event.created_ isnt HB.getUserId()
notifier = Object.getNotifier(that.bound_json) notifier = Object.getNotifier(that.bound_json)
oldVal = that.bound_json[property_name] oldVal = that.bound_json[event.name]
if oldVal? if oldVal?
notifier.performChange 'update', ()-> notifier.performChange 'update', ()->
that.bound_json[property_name] = that.val(property_name) that.bound_json[event.name] = that.val(event.name)
, that.bound_json , that.bound_json
notifier.notify notifier.notify
object: that.bound_json object: that.bound_json
type: 'update' type: 'update'
name: property_name name: event.name
oldValue: oldVal oldValue: oldVal
changed_by: op.uid.creator changed_by: event.changed_by
else else
notifier.performChange 'add', ()-> notifier.performChange 'add', ()->
that.bound_json[property_name] = that.val(property_name) that.bound_json[event.name] = that.val(event.name)
, that.bound_json , that.bound_json
notifier.notify notifier.notify
object: that.bound_json object: that.bound_json
type: 'add' type: 'add'
name: property_name name: event.name
oldValue: oldVal oldValue: oldVal
changed_by: op.uid.creator changed_by:event.changed_by
@bound_json @bound_json
# #

View File

@ -110,7 +110,10 @@ module.exports = (HB)->
uid_end.op_number = "#{uid_r.op_number}_end" uid_end.op_number = "#{uid_r.op_number}_end"
beg = (new types.Delimiter uid_beg, undefined, uid_end).execute() beg = (new types.Delimiter uid_beg, undefined, uid_end).execute()
end = (new types.Delimiter uid_end, beg, undefined).execute() end = (new types.Delimiter uid_end, beg, undefined).execute()
@map_manager.map[@name] = new ReplaceManager uid_r, beg, end event_properties =
name: @name
event_this = @map_manager
@map_manager.map[@name] = new ReplaceManager event_properties, event_this, uid_r, beg, end
@map_manager.map[@name].setParent @map_manager, @name @map_manager.map[@name].setParent @map_manager, @name
(@map_manager.map[@name].add_name_ops ?= []).push @ (@map_manager.map[@name].add_name_ops ?= []).push @
@map_manager.map[@name].execute() @map_manager.map[@name].execute()
@ -192,19 +195,24 @@ module.exports = (HB)->
# #
# Retrieves the x-th not deleted element. # Retrieves the x-th not deleted element.
# e.g. "abc" : the 1th character is "a"
# the 0th character is the left Delimiter
# #
getOperationByPosition: (position)-> getOperationByPosition: (position)->
o = @beginning.next_cl o = @beginning
if (position > 0 or o.isDeleted()) and not (o instanceof types.Delimiter)
while o.isDeleted() and not (o instanceof types.Delimiter)
# find first non deleted op
o = o.next_cl
while true while true
# find the i-th op # find the i-th op
if o instanceof types.Delimiter if o instanceof types.Delimiter and o.prev_cl?
# the user or you gave a position parameter that is to big
# for the current array. Therefore we reach a Delimiter.
# Then, we'll just return the last character.
o = o.prev_cl
while o.isDeleted() or not (o instanceof types.Delimiter)
o = o.prev_cl
break break
if position <= 0 and not o.isDeleted() if position <= 0 and not o.isDeleted()
break break
o = o.next_cl o = o.next_cl
if not o.isDeleted() if not o.isDeleted()
position -= 1 position -= 1
@ -220,12 +228,14 @@ module.exports = (HB)->
# #
class ReplaceManager extends ListManager class ReplaceManager extends ListManager
# #
# @param {Object} event_properties Decorates the event that is thrown by the RM
# @param {Object} event_this The object on which the event shall be executed
# @param {Operation} initial_content Initialize this with a Replaceable that holds the initial_content. # @param {Operation} initial_content Initialize this with a Replaceable that holds the initial_content.
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created. # @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Delimiter} beginning Reference or Object. # @param {Delimiter} beginning Reference or Object.
# @param {Delimiter} end Reference or Object. # @param {Delimiter} end Reference or Object.
# constructor: (uid, beginning, end, prev, next, origin)-> constructor: (@event_porperties, @event_this, uid, beginning, end, prev, next, origin)->
# super uid, beginning, end, prev, next, origin super uid, beginning, end, prev, next, origin
type: "ReplaceManager" type: "ReplaceManager"
@ -243,6 +253,21 @@ module.exports = (HB)->
cleanup: ()-> cleanup: ()->
super() super()
#
# This doesn't throw the same events as the ListManager. Therefore, the
# Replaceables also not throw the same events.
# So, ReplaceManager and ListManager both implement
# these functions that are called when an Insertion is executed (at the end).
#
#
callEventDecorator: (events)->
if not @isDeleted()
for name,prop of @event_porperties
for event in events
event[name] = prop
@event_this.callEvent events
undefined
# #
# Replace the existing word with a new word. # Replace the existing word with a new word.
# #
@ -278,7 +303,7 @@ module.exports = (HB)->
if @prev_cl? and @next_cl? if @prev_cl? and @next_cl?
json['prev'] = @prev_cl.getUid() json['prev'] = @prev_cl.getUid()
json['next'] = @next_cl.getUid() json['next'] = @next_cl.getUid()
if @origin? # and @origin isnt @prev_cl if @origin? # TODO: do this everywhere: and @origin isnt @prev_cl
json["origin"] = @origin().getUid() json["origin"] = @origin().getUid()
json json
@ -334,23 +359,30 @@ module.exports = (HB)->
super super
# #
# This is called, when the Insert-type was successfully executed.
# TODO: consider doing this in a more consistent manner. This could also be
# done with execute. But currently, there are no specital Insert-types for ListManager.
# #
execute: ()-> callOperationSpecificEvents: ()->
if not @validateSavedOperations()
return false
else
# only fire 'insert-event' (which will result in addProperty and change events),
# when content is added.
# In case of Json, empty content means that this is not the last update,
# since content is deleted when 'applyDelete' was exectuted.
ins_result = super(@content?) # @content? whether to fire or not
if ins_result
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter" if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
# this replaces another Replaceable
old_value = @prev_cl.content
@prev_cl.applyDelete() @prev_cl.applyDelete()
@parent.callEventDecorator [
type: "update"
changed_by: @uid.creator
oldValue: old_value
]
else if @next_cl.type isnt "Delimiter" else if @next_cl.type isnt "Delimiter"
# This will never be recognized by the user, because another
# concurrent operation is set as the current value of the RM
@applyDelete() @applyDelete()
else # prev _and_ next are Delimiters. This is the first created Replaceable in the RM
return ins_result @parent.callEventDecorator [
type: "add"
changed_by: @uid.creator
]
undefined
# #
# Encode this operation in such a way that it can be parsed by remote peers. # Encode this operation in such a way that it can be parsed by remote peers.

View File

@ -152,10 +152,10 @@ module.exports = (HB)->
# @return {WordType} This WordType object. # @return {WordType} This WordType object.
# #
insertText: (position, content)-> insertText: (position, content)->
# TODO: getOperationByPosition should return "(i-2)th" character ith = @getOperationByPosition position
ith = @getOperationByPosition position # the (i-1)th character. e.g. "abc" a is the 0th character # the (i-1)th character. e.g. "abc" the 1th character is "a"
left = ith.prev_cl # left is the non-deleted charather to the left of ith # the 0th character is the left Delimiter
@insertAfter left, content @insertAfter ith, content
# #
# Deletes a part of the word. # Deletes a part of the word.
@ -163,7 +163,7 @@ module.exports = (HB)->
# @return {WordType} This WordType object # @return {WordType} This WordType object
# #
deleteText: (position, length)-> deleteText: (position, length)->
o = @getOperationByPosition position o = @getOperationByPosition(position+1) # position 0 in this case is the deletion of the first character
delete_ops = [] delete_ops = []
for i in [0...length] for i in [0...length]

View File

@ -4,6 +4,12 @@ HistoryBuffer = require "./HistoryBuffer"
Engine = require "./Engine" Engine = require "./Engine"
adaptConnector = require "./ConnectorAdapter" adaptConnector = require "./ConnectorAdapter"
createYatta = (connector)->
user_id = connector.id # TODO: change to getUniqueId()
HB = new HistoryBuffer user_id
type_manager = json_types_uninitialized HB
types = type_manager.types
# #
# Framework for Json data-structures. # Framework for Json data-structures.
# Known values that are supported: # Known values that are supported:
@ -11,100 +17,25 @@ adaptConnector = require "./ConnectorAdapter"
# * Integer # * Integer
# * Array # * Array
# #
class Yatta class Yatta extends types.JsonType
# #
# @param {String} user_id Unique id of the peer. # @param {String} user_id Unique id of the peer.
# @param {Connector} Connector the connector class. # @param {Connector} Connector the connector class.
# #
constructor: (@connector)-> constructor: ()->
user_id = @connector.id # TODO: change to getUniqueId() @connector = connector
@HB = new HistoryBuffer user_id @HB = HB
type_manager = json_types_uninitialized @HB @types = types
@types = type_manager.types
@engine = new Engine @HB, type_manager.parser @engine = new Engine @HB, type_manager.parser
@HB.engine = @engine # TODO: !! only for debugging
adaptConnector @connector, @engine, @HB, type_manager.execution_listener adaptConnector @connector, @engine, @HB, type_manager.execution_listener
#first_word = super
@root_element = new @types.JsonType(@HB.getReservedUniqueIdentifier()).execute()
###
uid_beg = @HB.getReservedUniqueIdentifier()
uid_end = @HB.getReservedUniqueIdentifier()
beg = (new @types.Delimiter uid_beg, undefined, uid_end).execute()
end = (new @types.Delimiter uid_end, beg, undefined).execute()
@root_element = (new @types.ReplaceManager @HB.getReservedUniqueIdentifier(), beg, end).execute()
@root_element.replace first_word, @HB.getReservedUniqueIdentifier()
###
#
# @return JsonType
#
getSharedObject: ()->
@root_element
#
# Get the initialized connector.
#
getConnector: ()-> getConnector: ()->
@connector @connector
# return new Yatta(HB.getReservedUniqueIdentifier()).execute()
# @see HistoryBuffer
#
getHistoryBuffer: ()->
@HB
# module.exports = createYatta
# @see JsonType.setMutableDefault
#
setMutableDefault: (mutable)->
@getSharedObject().setMutableDefault(mutable)
#
# Get the UserId from the HistoryBuffer object.
# In most cases this will be the same as the user_id value with which
# Yatta was initialized (Depending on the HistoryBuffer implementation).
#
getUserId: ()->
@HB.getUserId()
#
# @see JsonType.toJson
#
toJson : ()->
@getSharedObject().toJson()
#
# @see JsonType.val
#
val : ()->
@getSharedObject().val arguments...
#
# @see Operation.on
#
observe: ()->
@getSharedObject().observe arguments...
#
# @see Operation.deleteListener
#
unobserve: ()->
@getSharedObject().unobserve arguments...
#
# @see JsonType.value
#
Object.defineProperty Yatta.prototype, 'value',
get : -> @getSharedObject().value
set : (o)->
if o.constructor is {}.constructor
for o_name,o_obj of o
@val(o_name, o_obj, 'immutable')
else
throw new Error "You must only set Object values!"
module.exports = Yatta
if window? and not window.Yatta? if window? and not window.Yatta?
window.Yatta = Yatta window.Yatta = createYatta

View File

@ -40,6 +40,7 @@
"coffeeify": "^0.6.0", "coffeeify": "^0.6.0",
"gulp": "^3.8.7", "gulp": "^3.8.7",
"gulp-browserify": "^0.5.0", "gulp-browserify": "^0.5.0",
"gulp-cached": "^1.0.1",
"gulp-coffee": "^2.1.1", "gulp-coffee": "^2.1.1",
"gulp-coffeelint": "^0.3.3", "gulp-coffeelint": "^0.3.3",
"gulp-concat": "^2.3.4", "gulp-concat": "^2.3.4",
@ -57,6 +58,7 @@
"gulp-run": "^1.6.3", "gulp-run": "^1.6.3",
"gulp-sourcemaps": "^1.1.1", "gulp-sourcemaps": "^1.1.1",
"gulp-uglify": "^0.3.1", "gulp-uglify": "^0.3.1",
"gulp-watch": "^3.0.0",
"jquery": "^2.1.1", "jquery": "^2.1.1",
"mocha": "^1.21.4", "mocha": "^1.21.4",
"sinon": "^1.10.2", "sinon": "^1.10.2",

View File

@ -20,7 +20,7 @@ class JsonTest extends Test
type: "JsonTest" type: "JsonTest"
getRandomRoot: (user_num, root)-> getRandomRoot: (user_num, root)->
root ?= @users[user_num].getSharedObject() root ?= @users[user_num]
types = @users[user_num].types types = @users[user_num].types
if _.random(0,1) is 1 # take root if _.random(0,1) is 1 # take root
root root
@ -98,7 +98,7 @@ describe "JsonFramework", ->
### ###
it "has a JsonTypeWrapper", -> it "has a JsonTypeWrapper", ->
y = this.yTest.getSomeUser().getSharedObject() y = this.yTest.getSomeUser()
y.val('x',"dtrn", 'immutable') y.val('x',"dtrn", 'immutable')
y.val('set',{x:"x"}, 'immutable') y.val('set',{x:"x"}, 'immutable')
w = y.value w = y.value

View File

@ -13,12 +13,12 @@ module.exports = class Test
constructor: (@name_suffix = "")-> constructor: (@name_suffix = "")->
@number_of_test_cases_multiplier = 1 @number_of_test_cases_multiplier = 1
@repeat_this = 1 * @number_of_test_cases_multiplier @repeat_this = 1 * @number_of_test_cases_multiplier
@doSomething_amount = 50 + @number_of_test_cases_multiplier @doSomething_amount = 50 * @number_of_test_cases_multiplier
@number_of_engines = 5 + @number_of_test_cases_multiplier - 1 @number_of_engines = 4 + @number_of_test_cases_multiplier - 1
@time = 0 @time = 0 # denotes to the time when run was started
@ops = 0 @ops = 0 # number of operations (used with @time)
@time_now = 0 @time_now = 0 # current time
@debug = false @debug = false
@ -85,11 +85,6 @@ module.exports = class Test
ops1 = y.deleteText pos, length ops1 = y.deleteText pos, length
undefined undefined
types : [types.WordType] types : [types.WordType]
,
f : (y)=> # REPLACE TEXT
y.replaceText @getRandomText()
null
types: [types.WordType]
] ]
getRandomRoot: (user_num)-> getRandomRoot: (user_num)->
throw new Error "overwrite me!" throw new Error "overwrite me!"

View File

@ -7,7 +7,7 @@ _ = require("underscore")
chai.use(sinonChai) chai.use(sinonChai)
Y = require "../lib/index" Yatta = require "../lib/Yatta"
Connector = require "../bower_components/connector/lib/test-connector/test-connector.coffee" Connector = require "../bower_components/connector/lib/test-connector/test-connector.coffee"
Test = require "./TestSuite" Test = require "./TestSuite"
@ -15,14 +15,17 @@ class TextTest extends Test
type: "TextTest" type: "TextTest"
makeNewUser: (user, conn)-> makeNewUser: (userId)->
super new Y.TextFramework user, conn conn = new Connector userId
y = new Yatta conn
y.val("TextTest","","mutable")
y
getRandomRoot: (user_num)-> getRandomRoot: (user_num)->
@users[user_num].getSharedObject() @users[user_num].val("TextTest")
getContent: (user_num)-> getContent: (user_num)->
@users[user_num].val() @users[user_num].val("TextTest").val()
describe "TextFramework", -> describe "TextFramework", ->
beforeEach (done)-> beforeEach (done)->
@ -35,13 +38,81 @@ describe "TextFramework", ->
done() done()
it "simple multi-char insert", -> it "simple multi-char insert", ->
u = @yTest.users[0] u = @yTest.users[0].val("TextTest")
u.insertText 0, "abc" u.insertText 0, "abc"
u = @yTest.users[1] u = @yTest.users[1].val("TextTest")
u.insertText 0, "xyz" u.insertText 0, "xyz"
@yTest.compareAll() @yTest.compareAll()
expect(u.val()).to.equal("abcxyz") expect(u.val()).to.equal("abcxyz")
it "Observers work on shared Text (insert type observers, local and foreign)", ->
u = @yTest.users[0].val("TextTest","my awesome Text").val("TextTest")
@yTest.flushAll()
last_task = null
observer1 = (changes)->
expect(changes.length).to.equal(1)
change = changes[0]
expect(change.type).to.equal("insert")
expect(change.object).to.equal(u)
expect(change.value).to.equal("a")
expect(change.position).to.equal(1)
expect(change.changed_by).to.equal('0')
last_task = "observer1"
u.observe observer1
u.insertText 1, "a"
expect(last_task).to.equal("observer1")
u.unobserve observer1
observer2 = (changes)->
expect(changes.length).to.equal(1)
change = changes[0]
expect(change.type).to.equal("insert")
expect(change.object).to.equal(u)
expect(change.value).to.equal("x")
expect(change.position).to.equal(0)
expect(change.changed_by).to.equal('1')
last_task = "observer2"
u.observe observer2
v = @yTest.users[1].val("TextTest")
v.insertText 0, "x"
@yTest.flushAll()
expect(last_task).to.equal("observer2")
u.unobserve observer2
it "Observers work on shared Text (delete type observers, local and foreign)", ->
u = @yTest.users[0].val("TextTest","my awesome Text").val("TextTest")
@yTest.flushAll()
last_task = null
observer1 = (changes)->
expect(changes.length).to.equal(1)
change = changes[0]
expect(change.type).to.equal("delete")
expect(change.object).to.equal(u)
expect(change.position).to.equal(1)
expect(change.length).to.equal(1)
expect(change.changed_by).to.equal('0')
last_task = "observer1"
u.observe observer1
u.deleteText 1
expect(last_task).to.equal("observer1")
u.unobserve observer1
observer2 = (changes)->
expect(changes.length).to.equal(1)
change = changes[0]
expect(change.type).to.equal("delete")
expect(change.object).to.equal(u)
expect(change.position).to.equal(0)
expect(change.length).to.equal(0)
expect(change.changed_by).to.equal('1')
last_task = "observer2"
u.observe observer2
v = @yTest.users[1].val("TextTest")
v.deleteText 0
@yTest.flushAll()
expect(last_task).to.equal("observer2")
u.unobserve observer2
it "can handle many engines, many operations, concurrently (random)", -> it "can handle many engines, many operations, concurrently (random)", ->
@yTest.run() @yTest.run()

File diff suppressed because one or more lines are too long