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
View File
@@ -4,3 +4,5 @@
.directory .directory
.c9 .c9
myftppass myftppass
.codio
.settings
+179 -292
View File
File diff suppressed because one or more lines are too long
+209
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
+458
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
+246
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
+401
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
+342
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
+409
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
+27 -79
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;
Yatta.prototype.getConnector = function() { this.engine = new Engine(this.HB, type_manager.parser);
return this.connector; adaptConnector(this.connector, this.engine, this.HB, type_manager.execution_listener);
}; Yatta.__super__.constructor.apply(this, arguments);
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; Yatta.prototype.getConnector = function() {
return this.connector;
};
})(); return Yatta;
module.exports = Yatta; })(types.JsonType);
return new Yatta(HB.getReservedUniqueIdentifier()).execute();
};
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
+463 -1106
View File
File diff suppressed because one or more lines are too long
+2 -1
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>
+1 -1
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>
+1 -1
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>
+1 -1
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>
+1 -1
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>
+9 -229
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>
+4
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>
+1 -1
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>
+2 -2
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>
+1 -1
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>
+1 -1
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>
+1 -1
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>
+1 -1
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>
+1 -1
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>
@@ -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>
+1 -1
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>
+28 -12
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>
+1 -1
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"}]
+27 -83
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
+11 -2
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);
}) })
} }
+13 -19
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
@@ -53,7 +55,7 @@ gulp.task 'browser', ->
extensions: ['.coffee'] extensions: ['.coffee']
debug : true debug : true
.pipe rename .pipe rename
basename: "yatta" basename: "yatta"
extname: ".js" extname: ".js"
.pipe gulp.dest './build/browser/' .pipe gulp.dest './build/browser/'
.pipe uglify() .pipe uglify()
@@ -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()
+26 -12
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()
@deletes.applyDelete @ res = super
super if res
@deletes.applyDelete @
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.
# #
+25 -24
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
notifier = Object.getNotifier(that.bound_json) if event.created_ isnt HB.getUserId()
oldVal = that.bound_json[property_name] notifier = Object.getNotifier(that.bound_json)
if oldVal? oldVal = that.bound_json[event.name]
notifier.performChange 'update', ()-> if oldVal?
that.bound_json[property_name] = that.val(property_name) notifier.performChange 'update', ()->
, that.bound_json that.bound_json[event.name] = that.val(event.name)
notifier.notify , that.bound_json
object: that.bound_json notifier.notify
type: 'update' object: that.bound_json
name: property_name type: 'update'
oldValue: oldVal name: event.name
changed_by: op.uid.creator oldValue: oldVal
else changed_by: event.changed_by
notifier.performChange 'add', ()-> else
that.bound_json[property_name] = that.val(property_name) notifier.performChange 'add', ()->
, that.bound_json that.bound_json[event.name] = that.val(event.name)
notifier.notify , that.bound_json
object: that.bound_json notifier.notify
type: 'add' object: that.bound_json
name: property_name type: 'add'
oldValue: oldVal name: event.name
changed_by: op.uid.creator oldValue: oldVal
changed_by:event.changed_by
@bound_json @bound_json
# #
+66 -34
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,22 +195,27 @@ 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 true
while o.isDeleted() and not (o instanceof types.Delimiter) # find the i-th op
# find first non deleted op if o instanceof types.Delimiter and o.prev_cl?
o = o.next_cl # the user or you gave a position parameter that is to big
while true # for the current array. Therefore we reach a Delimiter.
# find the i-th op # Then, we'll just return the last character.
if o instanceof types.Delimiter o = o.prev_cl
break while o.isDeleted() or not (o instanceof types.Delimiter)
if position <= 0 and not o.isDeleted() o = o.prev_cl
break break
o = o.next_cl if position <= 0 and not o.isDeleted()
if not o.isDeleted() break
position -= 1
o = o.next_cl
if not o.isDeleted()
position -= 1
o o
# #
@@ -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() if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
return false # this replaces another Replaceable
else old_value = @prev_cl.content
# only fire 'insert-event' (which will result in addProperty and change events), @prev_cl.applyDelete()
# when content is added. @parent.callEventDecorator [
# In case of Json, empty content means that this is not the last update, type: "update"
# since content is deleted when 'applyDelete' was exectuted. changed_by: @uid.creator
ins_result = super(@content?) # @content? whether to fire or not oldValue: old_value
if ins_result ]
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter" else if @next_cl.type isnt "Delimiter"
@prev_cl.applyDelete() # This will never be recognized by the user, because another
else if @next_cl.type isnt "Delimiter" # 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.
+5 -5
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]
+27 -96
View File
@@ -4,107 +4,38 @@ HistoryBuffer = require "./HistoryBuffer"
Engine = require "./Engine" Engine = require "./Engine"
adaptConnector = require "./ConnectorAdapter" adaptConnector = require "./ConnectorAdapter"
# createYatta = (connector)->
# Framework for Json data-structures. user_id = connector.id # TODO: change to getUniqueId()
# Known values that are supported: HB = new HistoryBuffer user_id
# * String type_manager = json_types_uninitialized HB
# * Integer types = type_manager.types
# * Array
#
class Yatta
# #
# @param {String} user_id Unique id of the peer. # Framework for Json data-structures.
# @param {Connector} Connector the connector class. # Known values that are supported:
# * String
# * Integer
# * Array
# #
constructor: (@connector)-> class Yatta extends types.JsonType
user_id = @connector.id # TODO: change to getUniqueId()
@HB = new HistoryBuffer user_id
type_manager = json_types_uninitialized @HB
@types = type_manager.types
@engine = new Engine @HB, type_manager.parser
@HB.engine = @engine # TODO: !! only for debugging
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
#first_word =
@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() # @param {String} user_id Unique id of the peer.
### # @param {Connector} Connector the connector class.
#
constructor: ()->
@connector = connector
@HB = HB
@types = types
@engine = new Engine @HB, type_manager.parser
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
super
# getConnector: ()->
# @return JsonType @connector
#
getSharedObject: ()->
@root_element
# return new Yatta(HB.getReservedUniqueIdentifier()).execute()
# Get the initialized connector.
#
getConnector: ()->
@connector
# module.exports = createYatta
# @see HistoryBuffer
#
getHistoryBuffer: ()->
@HB
#
# @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
+2
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",
+3 -3
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
@@ -127,7 +127,7 @@ describe "JsonFramework", ->
u1.engine.applyOps ops2 u1.engine.applyOps ops2
u2.engine.applyOps ops1 u2.engine.applyOps ops1
expect(test.getContent(0)).to.equal(@yTest.getContent(1)) expect(test.getContent(0)).to.equal(@yTest.getContent(1))
it "can handle creaton of complex json (1)", -> it "can handle creaton of complex json (1)", ->
@yTest.users[0].val('a', 'q') @yTest.users[0].val('a', 'q')
@yTest.users[2].val('a', 't') @yTest.users[2].val('a', 't')
+7 -12
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
@@ -33,7 +33,7 @@ module.exports = class Test
@users.push u @users.push u
@flushAll() @flushAll()
# is called by implementing class # is called by implementing class
makeNewUser: (user)-> makeNewUser: (user)->
user.HB.setManualGarbageCollect() user.HB.setManualGarbageCollect()
user user
@@ -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!"
+79 -8
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)->
@@ -33,15 +36,83 @@ describe "TextFramework", ->
@test_user = @yTest.makeNewUser 'test_user', test_user_connector @test_user = @yTest.makeNewUser 'test_user', test_user_connector
test_user_connector.join @users[0].connector test_user_connector.join @users[0].connector
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()
+1 -1
View File
File diff suppressed because one or more lines are too long