Operations are now Garbage Collected!
This commit is contained in:
@@ -9,12 +9,18 @@
|
||||
execution_listener = [];
|
||||
Operation = (function() {
|
||||
function Operation(uid) {
|
||||
if (uid == null) {
|
||||
this.is_deleted = false;
|
||||
this.doSync = true;
|
||||
if (uid != null) {
|
||||
this.doSync = !isNaN(parseInt(uid.op_number));
|
||||
} else {
|
||||
uid = HB.getNextOperationIdentifier();
|
||||
}
|
||||
this.creator = uid['creator'], this.op_number = uid['op_number'];
|
||||
}
|
||||
|
||||
Operation.prototype.type = "Insert";
|
||||
|
||||
Operation.prototype.on = function(events, f) {
|
||||
var e, _base, _i, _len, _results;
|
||||
if (this.event_listeners == null) {
|
||||
@@ -71,6 +77,26 @@
|
||||
}
|
||||
};
|
||||
|
||||
Operation.prototype.isDeleted = function() {
|
||||
return this.is_deleted;
|
||||
};
|
||||
|
||||
Operation.prototype.applyDelete = function(garbagecollect) {
|
||||
if (garbagecollect == null) {
|
||||
garbagecollect = true;
|
||||
}
|
||||
if (!this.isDeleted()) {
|
||||
this.is_deleted = true;
|
||||
if (garbagecollect) {
|
||||
return HB.addToGarbageCollector(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Operation.prototype.cleanup = function() {
|
||||
return HB.removeOperation(this);
|
||||
};
|
||||
|
||||
Operation.prototype.setParent = function(parent) {
|
||||
this.parent = parent;
|
||||
};
|
||||
@@ -82,10 +108,15 @@
|
||||
Operation.prototype.getUid = function() {
|
||||
return {
|
||||
'creator': this.creator,
|
||||
'op_number': this.op_number
|
||||
'op_number': this.op_number,
|
||||
'sync': this.doSync
|
||||
};
|
||||
};
|
||||
|
||||
Operation.prototype.dontSync = function() {
|
||||
return this.doSync = false;
|
||||
};
|
||||
|
||||
Operation.prototype.execute = function() {
|
||||
var l, _i, _len;
|
||||
this.is_executed = true;
|
||||
@@ -140,6 +171,8 @@
|
||||
Delete.__super__.constructor.call(this, uid);
|
||||
}
|
||||
|
||||
Delete.prototype.type = "Delete";
|
||||
|
||||
Delete.prototype._encode = function() {
|
||||
return {
|
||||
'type': "Delete",
|
||||
@@ -179,19 +212,47 @@
|
||||
Insert.__super__.constructor.call(this, uid);
|
||||
}
|
||||
|
||||
Insert.prototype.type = "Insert";
|
||||
|
||||
Insert.prototype.applyDelete = function(o) {
|
||||
var garbagecollect;
|
||||
if (this.deleted_by == null) {
|
||||
this.deleted_by = [];
|
||||
}
|
||||
this.deleted_by.push(o);
|
||||
if ((this.parent != null) && this.deleted_by.length === 1) {
|
||||
return this.parent.callEvent("delete", this);
|
||||
if ((this.parent != null) && !this.isDeleted()) {
|
||||
this.parent.callEvent("delete", this);
|
||||
}
|
||||
if (o != null) {
|
||||
this.deleted_by.push(o);
|
||||
}
|
||||
garbagecollect = false;
|
||||
if (this.prev_cl.isDeleted()) {
|
||||
garbagecollect = true;
|
||||
} else if (this.next_cl.isDeleted()) {
|
||||
this.next_cl.applyDelete();
|
||||
}
|
||||
return Insert.__super__.applyDelete.call(this, garbagecollect);
|
||||
};
|
||||
|
||||
Insert.prototype.isDeleted = function() {
|
||||
var _ref;
|
||||
return ((_ref = this.deleted_by) != null ? _ref.length : void 0) > 0;
|
||||
Insert.prototype.cleanup = function() {
|
||||
var d, o, _i, _len, _ref;
|
||||
if (this.prev_cl.isDeleted()) {
|
||||
_ref = this.deleted_by;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
d = _ref[_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() {
|
||||
@@ -203,53 +264,21 @@
|
||||
break;
|
||||
}
|
||||
d++;
|
||||
if (this === this.prev_cl) {
|
||||
throw new Error("this should not happen ;) ");
|
||||
}
|
||||
o = o.prev_cl;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
Insert.prototype.update_sl = function() {
|
||||
var o;
|
||||
o = this.prev_cl;
|
||||
({
|
||||
update: function(dest_cl, dest_sl) {
|
||||
var _results;
|
||||
_results = [];
|
||||
while (true) {
|
||||
if (o.isDeleted()) {
|
||||
_results.push(o = o[dest_cl]);
|
||||
} else {
|
||||
this[dest_sl] = o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
}
|
||||
});
|
||||
update("prev_cl", "prev_sl");
|
||||
return update("next_cl", "prev_sl");
|
||||
};
|
||||
|
||||
Insert.prototype.execute = function() {
|
||||
var distance_to_origin, i, o, parent, _ref, _ref1, _ref2;
|
||||
if (this.is_executed != null) {
|
||||
return this;
|
||||
}
|
||||
var distance_to_origin, i, o, parent, _ref;
|
||||
if (!this.validateSavedOperations()) {
|
||||
return false;
|
||||
} else {
|
||||
if (((_ref = this.prev_cl) != null ? _ref.validateSavedOperations() : void 0) && ((_ref1 = this.next_cl) != null ? _ref1.validateSavedOperations() : void 0) && this.prev_cl.next_cl !== this) {
|
||||
distance_to_origin = 0;
|
||||
if (this.prev_cl != null) {
|
||||
distance_to_origin = this.getDistanceToOrigin();
|
||||
o = this.prev_cl.next_cl;
|
||||
i = 0;
|
||||
i = distance_to_origin;
|
||||
while (true) {
|
||||
if (o == null) {
|
||||
console.log(JSON.stringify(this.prev_cl.getUid()));
|
||||
console.log(JSON.stringify(this.next_cl.getUid()));
|
||||
}
|
||||
if (o !== this.next_cl) {
|
||||
if (o.getDistanceToOrigin() === i) {
|
||||
if (o.creator < this.creator) {
|
||||
@@ -278,7 +307,7 @@
|
||||
this.prev_cl.next_cl = this;
|
||||
this.next_cl.prev_cl = this;
|
||||
}
|
||||
parent = (_ref2 = this.prev_cl) != null ? _ref2.getParent() : void 0;
|
||||
parent = (_ref = this.prev_cl) != null ? _ref.getParent() : void 0;
|
||||
if (parent != null) {
|
||||
this.setParent(parent);
|
||||
this.parent.callEvent("insert", this);
|
||||
@@ -295,7 +324,7 @@
|
||||
if (prev instanceof Delimiter) {
|
||||
break;
|
||||
}
|
||||
if ((prev.isDeleted != null) && !prev.isDeleted()) {
|
||||
if (!prev.isDeleted()) {
|
||||
position++;
|
||||
}
|
||||
prev = prev.prev_cl;
|
||||
@@ -314,6 +343,8 @@
|
||||
ImmutableObject.__super__.constructor.call(this, uid, prev, next, origin);
|
||||
}
|
||||
|
||||
ImmutableObject.prototype.type = "ImmutableObject";
|
||||
|
||||
ImmutableObject.prototype.val = function() {
|
||||
return this.content;
|
||||
};
|
||||
@@ -331,15 +362,15 @@
|
||||
if (this.next_cl != null) {
|
||||
json['next'] = this.next_cl.getUid();
|
||||
}
|
||||
if ((this.origin != null) && this.origin !== this.prev_cl) {
|
||||
json["origin"] = this.origin.getUid();
|
||||
if (this.origin != null) {
|
||||
json["origin"] = this.origin().getUid();
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
return ImmutableObject;
|
||||
|
||||
})(Insert);
|
||||
})(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'];
|
||||
@@ -355,8 +386,21 @@
|
||||
Delimiter.__super__.constructor.call(this, uid);
|
||||
}
|
||||
|
||||
Delimiter.prototype.isDeleted = function() {
|
||||
return false;
|
||||
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() {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -78,6 +78,14 @@
|
||||
|
||||
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, val;
|
||||
val = this.val();
|
||||
@@ -100,16 +108,18 @@
|
||||
return json;
|
||||
};
|
||||
|
||||
JsonType.prototype.setReplaceManager = function(rm) {
|
||||
this.parent = rm.parent;
|
||||
JsonType.prototype.setReplaceManager = function(replace_manager) {
|
||||
this.replace_manager = replace_manager;
|
||||
return this.on(['change', 'addProperty'], function() {
|
||||
var _ref;
|
||||
return (_ref = rm.parent).forwardEvent.apply(_ref, [this].concat(__slice.call(arguments)));
|
||||
if (replace_manager.parent != null) {
|
||||
return (_ref = replace_manager.parent).forwardEvent.apply(_ref, [this].concat(__slice.call(arguments)));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
JsonType.prototype.getParent = function() {
|
||||
return this.parent;
|
||||
return this.replace_manager.parent;
|
||||
};
|
||||
|
||||
JsonType.prototype.mutable_default = true;
|
||||
@@ -126,12 +136,11 @@
|
||||
};
|
||||
|
||||
JsonType.prototype.val = function(name, content, mutable) {
|
||||
var json, o, o_name, obj, word;
|
||||
var json, obj, word;
|
||||
if (typeof name === 'object') {
|
||||
for (o_name in name) {
|
||||
o = name[o_name];
|
||||
this.val(o_name, o, content);
|
||||
}
|
||||
json = new JsonType(void 0, name, content);
|
||||
HB.addOperation(json).execute();
|
||||
this.replace_manager.replace(json);
|
||||
return this;
|
||||
} else if ((name != null) && ((content != null) || content === null)) {
|
||||
if (mutable != null) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -18,6 +18,22 @@
|
||||
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, result, _ref, _ref1;
|
||||
if (content != null) {
|
||||
@@ -60,8 +76,18 @@
|
||||
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, end, uid_beg, uid_end, uid_r;
|
||||
var beg, end, uid_beg, uid_end, uid_r, _base;
|
||||
if (!this.validateSavedOperations()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -76,6 +102,7 @@
|
||||
end = HB.addOperation(new types.Delimiter(uid_end, beg, void 0)).execute();
|
||||
this.map_manager.map[this.name] = HB.addOperation(new ReplaceManager(void 0, 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);
|
||||
@@ -116,6 +143,8 @@
|
||||
ListManager.__super__.constructor.call(this, uid, prev, next, origin);
|
||||
}
|
||||
|
||||
ListManager.prototype.type = "ListManager";
|
||||
|
||||
ListManager.prototype.execute = function() {
|
||||
if (this.validateSavedOperations()) {
|
||||
this.beginning.setParent(this);
|
||||
@@ -170,7 +199,7 @@
|
||||
|
||||
return ListManager;
|
||||
|
||||
})(types.Insert);
|
||||
})(types.Operation);
|
||||
ReplaceManager = (function(_super) {
|
||||
__extends(ReplaceManager, _super);
|
||||
|
||||
@@ -181,11 +210,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
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.replace = function(content, replaceable_uid) {
|
||||
var o, op;
|
||||
o = this.getLastOperation();
|
||||
op = new Replaceable(content, this, replaceable_uid, o, o.next_cl);
|
||||
return HB.addOperation(op).execute();
|
||||
HB.addOperation(op).execute();
|
||||
return void 0;
|
||||
};
|
||||
|
||||
ReplaceManager.prototype.setParent = function(parent, property_name) {
|
||||
@@ -232,8 +285,8 @@
|
||||
json['prev'] = this.prev_cl.getUid();
|
||||
json['next'] = this.next_cl.getUid();
|
||||
}
|
||||
if ((this.origin != null) && this.origin !== this.prev_cl) {
|
||||
json["origin"] = this.origin.getUid();
|
||||
if (this.origin != null) {
|
||||
json["origin"] = this.origin().getUid();
|
||||
}
|
||||
return json;
|
||||
};
|
||||
@@ -252,12 +305,14 @@
|
||||
function Replaceable(content, parent, uid, prev, next, origin) {
|
||||
this.saveOperation('content', content);
|
||||
this.saveOperation('parent', parent);
|
||||
if (!((prev != null) && (next != null) && (content != null))) {
|
||||
throw new Error("You must define content, prev, and next for Replaceable-types!");
|
||||
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;
|
||||
};
|
||||
@@ -266,23 +321,47 @@
|
||||
return this.parent.replace(content);
|
||||
};
|
||||
|
||||
Replaceable.prototype.applyDelete = function() {
|
||||
if (this.content != null) {
|
||||
this.content.applyDelete();
|
||||
this.content.dontSync();
|
||||
}
|
||||
this.beforeDelete = this.content;
|
||||
this.content = null;
|
||||
return Replaceable.__super__.applyDelete.apply(this, arguments);
|
||||
};
|
||||
|
||||
Replaceable.prototype.cleanup = function() {
|
||||
return Replaceable.__super__.cleanup.apply(this, arguments);
|
||||
};
|
||||
|
||||
Replaceable.prototype.execute = function() {
|
||||
var _base;
|
||||
var ins_result, _ref;
|
||||
if (!this.validateSavedOperations()) {
|
||||
return false;
|
||||
} else {
|
||||
if (typeof (_base = this.content).setReplaceManager === "function") {
|
||||
_base.setReplaceManager(this.parent);
|
||||
if ((_ref = this.content) != null) {
|
||||
if (typeof _ref.setReplaceManager === "function") {
|
||||
_ref.setReplaceManager(this.parent);
|
||||
}
|
||||
}
|
||||
return Replaceable.__super__.execute.apply(this, arguments);
|
||||
ins_result = Replaceable.__super__.execute.call(this);
|
||||
if (ins_result) {
|
||||
if (this.next_cl.type === "Delimiter" && this.prev_cl.type !== "Delimiter") {
|
||||
this.prev_cl.applyDelete();
|
||||
} else if (this.next_cl.type !== "Delimiter") {
|
||||
this.applyDelete();
|
||||
}
|
||||
}
|
||||
return ins_result;
|
||||
}
|
||||
};
|
||||
|
||||
Replaceable.prototype._encode = function() {
|
||||
var json;
|
||||
var json, _ref;
|
||||
json = {
|
||||
'type': "Replaceable",
|
||||
'content': this.content.getUid(),
|
||||
'content': (_ref = this.content) != null ? _ref.getUid() : void 0,
|
||||
'ReplaceManager': this.parent.getUid(),
|
||||
'prev': this.prev_cl.getUid(),
|
||||
'next': this.next_cl.getUid(),
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -32,6 +32,8 @@
|
||||
TextInsert.__super__.constructor.call(this, uid, prev, next, origin);
|
||||
}
|
||||
|
||||
TextInsert.prototype.type = "TextInsert";
|
||||
|
||||
TextInsert.prototype.getLength = function() {
|
||||
if (this.isDeleted()) {
|
||||
return 0;
|
||||
@@ -40,8 +42,13 @@
|
||||
}
|
||||
};
|
||||
|
||||
TextInsert.prototype.applyDelete = function() {
|
||||
this.content = null;
|
||||
return TextInsert.__super__.applyDelete.apply(this, arguments);
|
||||
};
|
||||
|
||||
TextInsert.prototype.val = function(current_position) {
|
||||
if (this.isDeleted()) {
|
||||
if (this.isDeleted() || (this.content == null)) {
|
||||
return "";
|
||||
} else {
|
||||
return this.content;
|
||||
@@ -57,7 +64,7 @@
|
||||
'prev': this.prev_cl.getUid(),
|
||||
'next': this.next_cl.getUid()
|
||||
};
|
||||
if ((this.origin != null) && this.origin !== this.prev_cl) {
|
||||
if (this.origin !== this.prev_cl) {
|
||||
json["origin"] = this.origin.getUid();
|
||||
}
|
||||
return json;
|
||||
@@ -80,13 +87,33 @@
|
||||
|
||||
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.insertText = function(position, content) {
|
||||
var c, o, op, _i, _len;
|
||||
o = this.getOperationByPosition(position);
|
||||
var c, ith, left, op, right, _i, _len;
|
||||
ith = this.getOperationByPosition(position);
|
||||
left = ith.prev_cl;
|
||||
while (left.isDeleted()) {
|
||||
left = left.prev_cl;
|
||||
}
|
||||
right = left.next_cl;
|
||||
for (_i = 0, _len = content.length; _i < _len; _i++) {
|
||||
c = content[_i];
|
||||
op = new TextInsert(c, void 0, o.prev_cl, o);
|
||||
op = new TextInsert(c, void 0, left, right);
|
||||
HB.addOperation(op).execute();
|
||||
left = op;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
@@ -278,8 +305,8 @@
|
||||
if (this.next_cl != null) {
|
||||
json['next'] = this.next_cl.getUid();
|
||||
}
|
||||
if ((this.origin != null) && this.origin !== this.prev_cl) {
|
||||
json["origin"] = this.origin.getUid();
|
||||
if (this.origin != null) {
|
||||
json["origin"] = this.origin().getUid();
|
||||
}
|
||||
return json;
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user