testing observers, refactoring some Basic Types

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

2
.gitignore vendored
View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

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

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,7 @@
(function() {
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");
@ -9,89 +11,35 @@
adaptConnector = require("./ConnectorAdapter");
Yatta = (function() {
function Yatta(connector) {
var beg, end, first_word, type_manager, uid_beg, uid_end, user_id;
this.connector = connector;
user_id = this.connector.id;
this.HB = new HistoryBuffer(user_id);
type_manager = json_types_uninitialized(this.HB);
this.types = type_manager.types;
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());
}
createYatta = function(connector) {
var HB, Yatta, type_manager, types, user_id;
user_id = connector.id;
HB = new HistoryBuffer(user_id);
type_manager = json_types_uninitialized(HB);
types = type_manager.types;
Yatta = (function(_super) {
__extends(Yatta, _super);
Yatta.prototype.getSharedObject = function() {
return this.root_element.val();
};
Yatta.prototype.getConnector = function() {
return this.connector;
};
Yatta.prototype.getHistoryBuffer = function() {
return this.HB;
};
Yatta.prototype.setMutableDefault = function(mutable) {
return this.getSharedObject().setMutableDefault(mutable);
};
Yatta.prototype.getUserId = function() {
return this.HB.getUserId();
};
Yatta.prototype.toJson = function() {
return this.getSharedObject().toJson();
};
Yatta.prototype.val = function() {
var _ref;
return (_ref = this.getSharedObject()).val.apply(_ref, arguments);
};
Yatta.prototype.on = function() {
var _ref;
return (_ref = this.getSharedObject()).on.apply(_ref, arguments);
};
Yatta.prototype.deleteListener = function() {
var _ref;
return (_ref = this.getSharedObject()).deleteListener.apply(_ref, arguments);
};
Object.defineProperty(Yatta.prototype, 'value', {
get: function() {
return this.getSharedObject().value;
},
set: function(o) {
var o_name, o_obj, _results;
if (o.constructor === {}.constructor) {
_results = [];
for (o_name in o) {
o_obj = o[o_name];
_results.push(this.val(o_name, o_obj, 'immutable'));
}
return _results;
} else {
throw new Error("You must only set Object values!");
}
function Yatta() {
this.connector = connector;
this.HB = HB;
this.types = types;
this.engine = new Engine(this.HB, type_manager.parser);
adaptConnector(this.connector, this.engine, this.HB, type_manager.execution_listener);
Yatta.__super__.constructor.apply(this, arguments);
}
});
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)) {
window.Yatta = Yatta;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

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

View File

@ -178,7 +178,7 @@
</div>
</div>
<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'>
Codo
</a>

View File

@ -359,7 +359,7 @@ E.g.: let x = {a:[]}. Then x.a.push 1 wouldn&#39;t change anything</p>
</div>
</div>
<div 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'>
Codo
</a>

View File

@ -139,7 +139,7 @@ console.log(w.newProperty == &quot;Awesome&quot;) # true!</code></pre>
</div>
</div>
<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'>
Codo
</a>

View File

@ -389,7 +389,7 @@ yatta.bind(textbox);</code></pre>
</div>
</div>
<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'>
Codo
</a>

View File

@ -32,6 +32,12 @@
<td>Defined in:</td>
<td>lib&#47;Yatta.coffee</td>
</tr>
<tr>
<td>Inherits:</td>
<td>
types.JsonType
</td>
</tr>
</table>
<h2>Overview</h2>
<div class='docstring'>
@ -47,17 +53,6 @@ Known values that are supported:</p><ul>
</div>
<h2>Instance Method Summary</h2>
<ul class='summary'>
<li>
<span class='signature'>
<a href='#getSharedObject-dynamic'>
#
(?)
<b>getSharedObject</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#getConnector-dynamic'>
@ -66,85 +61,6 @@ Known values that are supported:</p><ul>
<b>getConnector</b><span>()</span>
</a>
</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>
</li>
@ -155,7 +71,7 @@ Known values that are supported:</p><ul>
<p class='signature' id='constructor-dynamic'>
#
(void)
<b>constructor</b><span>(connector)</span>
<b>constructor</b><span>()</span>
<br>
</p>
<div class='tags'>
@ -187,27 +103,6 @@ Known values that are supported:</p><ul>
</div>
<h2>Instance Method Details</h2>
<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'>
<p class='signature' id='getConnector-dynamic'>
#
@ -215,127 +110,12 @@ Known values that are supported:</p><ul>
<b>getConnector</b><span>()</span>
<br>
</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 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'>
Codo
</a>

View File

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

View File

@ -38,7 +38,7 @@
</div>
</div>
<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'>
Codo
</a>

View File

@ -76,7 +76,7 @@ But I would become really motivated if you gave me some feedback :) (<a href="ht
</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>!
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 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'>
Codo
</a>

View File

@ -106,7 +106,7 @@
</div>
</div>
<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'>
Codo
</a>

View File

@ -72,7 +72,7 @@
</dl>
</div>
<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'>
Codo
</a>

View File

@ -48,7 +48,7 @@
</dl>
</div>
<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'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<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'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<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'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<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'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<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'>
Codo
</a>

View File

@ -34,16 +34,6 @@
<td>Defined in:</td>
<td>lib</td>
</tr>
<tr>
<td>
Classes:
</td>
<td>
<a href='../../class/Yatta.html'>
Yatta
</a>
</td>
</tr>
</table>
<h2>Variables Summary</h2>
<dl class='constants'>
@ -52,13 +42,39 @@
=
</dt>
<dd>
<pre><code class='coffeescript'>Yatta</code></pre>
<pre><code class='coffeescript'>createYatta</code></pre>
</dd>
</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 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'>
Codo
</a>

View File

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

View File

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

View File

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

View File

@ -16,18 +16,18 @@ run = require 'gulp-run'
ljs = require 'gulp-ljs'
plumber = require 'gulp-plumber'
mochaPhantomJS = require 'gulp-mocha-phantomjs'
cache = require 'gulp-cached'
gulp.task 'default', ['lint', 'browser', 'test', 'literate', 'lib', 'codo']
gulp.task 'build', ['lint', 'browser']
gulp.task 'default', ['deploy']
files =
lib : ['./lib/**/*.coffee']
build : ['./build/**']
browser : './lib/Yatta.coffee'
#test : ['./test/**/*_test.coffee']
test : ['./test/JsonYatta_test.coffee']
test : ['./test/JsonYatta_test.coffee', './test/TextYatta_test.coffee']
gulp : ['./gulpfile.coffee']
examples : ['./examples/**/*.js']
other: ['./lib/**/*']
@ -37,7 +37,7 @@ for name,file_list of files
if name isnt 'build'
files.all = files.all.concat file_list
gulp.task 'lib', ->
gulp.task 'deploy_nodejs', ->
gulp.src files.lib
.pipe sourcemaps.init()
.pipe coffee()
@ -45,7 +45,9 @@ gulp.task 'lib', ->
.pipe gulp.dest 'build/node/'
.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 }
.pipe plumber()
.pipe browserify
@ -53,7 +55,7 @@ gulp.task 'browser', ->
extensions: ['.coffee']
debug : true
.pipe rename
basename: "yatta"
basename: "yatta"
extname: ".js"
.pipe gulp.dest './build/browser/'
.pipe uglify()
@ -69,12 +71,12 @@ gulp.task 'browser', ->
extname: ".js"
.pipe gulp.dest './build/test'
gulp.task 'browser_test_watch', ['browser'], ->
gulp.watch files.all, ['browser']
gulp.task 'watch', ['build_browser','mocha'], ->
gulp.watch files.all, ['build_browser', 'mocha']
gulp.task 'test', ->
gulp.task 'mocha', ->
gulp.src files.test, { read: false }
.pipe plumber()
.pipe mocha {reporter : 'list'}
.pipe ignore.include '**/*.coffee'
.pipe browserify
@ -95,11 +97,6 @@ gulp.task 'lint', ->
}
.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.watch files.all, ['phantom_test']
@ -112,14 +109,11 @@ gulp.task 'literate', ->
.pipe gulp.dest 'examples/'
.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', [], ()->
command = 'codo -o "./doc" --name "Yatta!" --readme "README.md" --undocumented false --private true --title "Yatta! API" ./lib - LICENSE.txt '
run(command).exec()
gulp.task 'phantom_test', ['browser'], ()->
gulp.task 'phantom_test', ['build_browser'], ()->
gulp.src 'build/test/index.html'
.pipe mochaPhantomJS()

View File

@ -45,7 +45,7 @@ module.exports = (HB)->
# @overload unobserve(event, f)
# @param f {Function} The function that you want to delete
unobserve: (f)->
@event_listeners.filter (g)->
@event_listeners = @event_listeners.filter (g)->
f isnt g
#
@ -59,7 +59,7 @@ module.exports = (HB)->
#
# Fire an event.
# 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: ()->
@forwardEvent @, arguments...
@ -215,8 +215,10 @@ module.exports = (HB)->
#
execute: ()->
if @validateSavedOperations()
@deletes.applyDelete @
super
res = super
if res
@deletes.applyDelete @
res
else
false
@ -275,7 +277,12 @@ module.exports = (HB)->
garbagecollect = true
super garbagecollect
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()
# garbage collect next_cl
@next_cl.applyDelete()
@ -317,8 +324,7 @@ module.exports = (HB)->
#
# @private
# Include this operation in the associative lists.
# @param fire_event {boolean} Whether to fire the insert-event.
execute: (fire_event = true)->
execute: ()->
if not @validateSavedOperations()
return false
else
@ -336,7 +342,8 @@ module.exports = (HB)->
# therefore $this would be always to the right of o3
# case 2: $origin < $o.origin
# 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
# $this insert_position is to the left of $o (forever!)
while true
@ -369,13 +376,20 @@ module.exports = (HB)->
@prev_cl.next_cl = @
@next_cl.prev_cl = @
parent = @prev_cl?.getParent()
@setParent @prev_cl.getParent() # do Insertions always have a parent?
super # notify the execution_listeners
if parent? and fire_event
@setParent parent
@parent.callEvent "insert", @
@callOperationSpecificEvents()
@
callOperationSpecificEvents: ()->
@parent?.callEvent [
type: "insert"
position: @getPosition()
object: @parent
changed_by: @uid.creator
value: @content
]
#
# Compute the position of this operation.
#

View File

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

View File

@ -110,7 +110,10 @@ module.exports = (HB)->
uid_end.op_number = "#{uid_r.op_number}_end"
beg = (new types.Delimiter uid_beg, undefined, uid_end).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].add_name_ops ?= []).push @
@map_manager.map[@name].execute()
@ -192,22 +195,27 @@ module.exports = (HB)->
#
# Retrieves the x-th not deleted element.
# e.g. "abc" : the 1th character is "a"
# the 0th character is the left Delimiter
#
getOperationByPosition: (position)->
o = @beginning.next_cl
if (position > 0 or o.isDeleted()) and not (o instanceof types.Delimiter)
while o.isDeleted() and not (o instanceof types.Delimiter)
# find first non deleted op
o = o.next_cl
while true
# find the i-th op
if o instanceof types.Delimiter
break
if position <= 0 and not o.isDeleted()
break
o = o.next_cl
if not o.isDeleted()
position -= 1
o = @beginning
while true
# find the i-th op
if o instanceof types.Delimiter and o.prev_cl?
# the user or you gave a position parameter that is to big
# for the current array. Therefore we reach a Delimiter.
# Then, we'll just return the last character.
o = o.prev_cl
while o.isDeleted() or not (o instanceof types.Delimiter)
o = o.prev_cl
break
if position <= 0 and not o.isDeleted()
break
o = o.next_cl
if not o.isDeleted()
position -= 1
o
#
@ -220,12 +228,14 @@ module.exports = (HB)->
#
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 {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Delimiter} beginning Reference or Object.
# @param {Delimiter} end Reference or Object.
# constructor: (uid, beginning, end, prev, next, origin)->
# super uid, beginning, end, prev, next, origin
constructor: (@event_porperties, @event_this, uid, beginning, end, prev, next, origin)->
super uid, beginning, end, prev, next, origin
type: "ReplaceManager"
@ -243,6 +253,21 @@ module.exports = (HB)->
cleanup: ()->
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.
#
@ -278,7 +303,7 @@ module.exports = (HB)->
if @prev_cl? and @next_cl?
json['prev'] = @prev_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
@ -334,23 +359,30 @@ module.exports = (HB)->
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: ()->
if not @validateSavedOperations()
return false
else
# only fire 'insert-event' (which will result in addProperty and change events),
# when content is added.
# In case of Json, empty content means that this is not the last update,
# since content is deleted when 'applyDelete' was exectuted.
ins_result = super(@content?) # @content? whether to fire or not
if ins_result
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
@prev_cl.applyDelete()
else if @next_cl.type isnt "Delimiter"
@applyDelete()
return ins_result
callOperationSpecificEvents: ()->
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
# this replaces another Replaceable
old_value = @prev_cl.content
@prev_cl.applyDelete()
@parent.callEventDecorator [
type: "update"
changed_by: @uid.creator
oldValue: old_value
]
else if @next_cl.type isnt "Delimiter"
# This will never be recognized by the user, because another
# concurrent operation is set as the current value of the RM
@applyDelete()
else # prev _and_ next are Delimiters. This is the first created Replaceable in the RM
@parent.callEventDecorator [
type: "add"
changed_by: @uid.creator
]
undefined
#
# Encode this operation in such a way that it can be parsed by remote peers.

View File

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

View File

@ -4,107 +4,38 @@ HistoryBuffer = require "./HistoryBuffer"
Engine = require "./Engine"
adaptConnector = require "./ConnectorAdapter"
#
# Framework for Json data-structures.
# Known values that are supported:
# * String
# * Integer
# * Array
#
class Yatta
createYatta = (connector)->
user_id = connector.id # TODO: change to getUniqueId()
HB = new HistoryBuffer user_id
type_manager = json_types_uninitialized HB
types = type_manager.types
#
# @param {String} user_id Unique id of the peer.
# @param {Connector} Connector the connector class.
# Framework for Json data-structures.
# Known values that are supported:
# * String
# * Integer
# * Array
#
constructor: (@connector)->
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()
class Yatta extends types.JsonType
@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
#
# @return JsonType
#
getSharedObject: ()->
@root_element
getConnector: ()->
@connector
#
# Get the initialized connector.
#
getConnector: ()->
@connector
return new Yatta(HB.getReservedUniqueIdentifier()).execute()
#
# @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
module.exports = createYatta
if window? and not window.Yatta?
window.Yatta = Yatta
window.Yatta = createYatta

View File

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

View File

@ -20,7 +20,7 @@ class JsonTest extends Test
type: "JsonTest"
getRandomRoot: (user_num, root)->
root ?= @users[user_num].getSharedObject()
root ?= @users[user_num]
types = @users[user_num].types
if _.random(0,1) is 1 # take root
root
@ -98,7 +98,7 @@ describe "JsonFramework", ->
###
it "has a JsonTypeWrapper", ->
y = this.yTest.getSomeUser().getSharedObject()
y = this.yTest.getSomeUser()
y.val('x',"dtrn", 'immutable')
y.val('set',{x:"x"}, 'immutable')
w = y.value
@ -127,7 +127,7 @@ describe "JsonFramework", ->
u1.engine.applyOps ops2
u2.engine.applyOps ops1
expect(test.getContent(0)).to.equal(@yTest.getContent(1))
it "can handle creaton of complex json (1)", ->
@yTest.users[0].val('a', 'q')
@yTest.users[2].val('a', 't')

View File

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

View File

@ -7,7 +7,7 @@ _ = require("underscore")
chai.use(sinonChai)
Y = require "../lib/index"
Yatta = require "../lib/Yatta"
Connector = require "../bower_components/connector/lib/test-connector/test-connector.coffee"
Test = require "./TestSuite"
@ -15,14 +15,17 @@ class TextTest extends Test
type: "TextTest"
makeNewUser: (user, conn)->
super new Y.TextFramework user, conn
makeNewUser: (userId)->
conn = new Connector userId
y = new Yatta conn
y.val("TextTest","","mutable")
y
getRandomRoot: (user_num)->
@users[user_num].getSharedObject()
@users[user_num].val("TextTest")
getContent: (user_num)->
@users[user_num].val()
@users[user_num].val("TextTest").val()
describe "TextFramework", ->
beforeEach (done)->
@ -33,15 +36,83 @@ describe "TextFramework", ->
@test_user = @yTest.makeNewUser 'test_user', test_user_connector
test_user_connector.join @users[0].connector
done()
it "simple multi-char insert", ->
u = @yTest.users[0]
u = @yTest.users[0].val("TextTest")
u.insertText 0, "abc"
u = @yTest.users[1]
u = @yTest.users[1].val("TextTest")
u.insertText 0, "xyz"
@yTest.compareAll()
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)", ->
@yTest.run()

File diff suppressed because one or more lines are too long