Documentation and cleanup

This commit is contained in:
Kevin Jahns
2014-08-24 01:52:15 +02:00
parent 77739deda3
commit 86849ae8b1
496 changed files with 10102 additions and 87342 deletions

View File

@@ -1,112 +0,0 @@
#
# @param {Function} callback The callback is called when the connector is initialized.
#
createIwcConnector = (callback)->
iwcHandler = {}
duiClient = new DUIClient()
#@duiClient = new iwc.Client()
duiClient.connect (intent)->
#console.log "intent received iwc: #{JSON.stringify(intent)}"
#console.log "#{JSON.stringify(@iwcHandler)}"
iwcHandler[intent.action]?.map (f)->
setTimeout ()->
f intent
, 0
duiClient.initOK()
received_HB = null
#
# The Iwc Connector adds support for the Inter-Widget-Communication protocol that is used in the Role-SDK.
# @see http://dbis.rwth-aachen.de/cms/projects/the-xmpp-experience#interwidget-communication
# @see http://dbis.rwth-aachen.de/cms/projects/ROLE
#
class IwcConnector
#
# @param {Engine} engine The transformation engine
# @param {HistoryBuffer} HB
# @param {Array<Function>} execution_listener You must ensure that whenever an operation is executed, every function in this Array is called.
# @param {Yatta} yatta The Yatta framework.
#
constructor: (@engine, @HB, @execution_listener, @yatta)->
@duiClient = duiClient
@iwcHandler = iwcHandler
send_ = (o)=>
@send o
@execution_listener.push send_
receive_ = (intent)=>
o = intent.extras
@receive o
@iwcHandler["Yatta_new_operation"] = [receive_]
if received_HB?
@engine.applyOpsCheckDouble received_HB
sendHistoryBuffer = ()=>
json =
HB : @yatta.getHistoryBuffer()._encode()
@sendIwcIntent "Yatta_push_HB_element", json
@iwcHandler["Yatta_get_HB_element"] = [sendHistoryBuffer]
#
# This function is called whenever an operation was executed.
# @param {Operation} o The operation that was executed.
#
send: (o)->
if o.uid.creator is @HB.getUserId() and (typeof o.uid.op_number isnt "string")
@sendIwcIntent "Yatta_new_operation", o
#
# This function is called whenever an operation was received from another peer.
# @param {Operation} o The operation that was received.
#
receive: (o)->
if o.uid.creator isnt @HB.getUserId()
@engine.applyOp o
#
# Helper for sending iwc intents.
# @param {String} action_name The name of the action that is going to be send.
# @param {String} content The content that is atteched to the intent.
#
sendIwcIntent: (action_name, content)->
intent =
action: action_name
component: ""
data: ""
dataType: ""
extras: content
@duiClient.sendIntent(intent)
get_HB_intent =
action: "Yatta_get_HB_element"
component: ""
data: ""
dataType: ""
extras: {}
init = ()->
duiClient.sendIntent(get_HB_intent)
is_initialized = false
receiveHB = (json)->
proposed_user_id = duiClient.getIwcClient()._componentName
received_HB = json?.extras.HB
if not is_initialized
is_initialized = true
callback IwcConnector, proposed_user_id
iwcHandler["Yatta_push_HB_element"] = [receiveHB]
setTimeout receiveHB, 0
setTimeout init, (Math.random()*0)
undefined
module.exports = createIwcConnector
window?.createConnector = createIwcConnector

View File

@@ -1,2 +1,142 @@
(function(){var t;t=function(t,n){var e,i,r,o,u,a;return a=null,null!=n&&(a=n.iwcHandler),o={},i=new DUIClient,i.connect(function(t){var n;return null!=(n=o[t.action])&&n.map(function(n){return setTimeout(function(){return n(t)},0)}),null!=a?a(t):void 0}),i.initOK(),u=null,e=function(){function t(t,n,e,r){var a,s,l,c;this.engine=t,this.HB=n,this.execution_listener=e,this.yatta=r,this.duiClient=i,this.iwcHandler=o,c=function(t){return function(n){return 0!==Object.getOwnPropertyNames(t.initialized).length?t.send(n):void 0}}(this),this.execution_listener.push(c),this.initialized={},a=function(t){return function(e){var i;return n=e.extras.HB,i=e.extras.user,t.engine.applyOpsCheckDouble(n),t.initialized[i]=!0}}(this),o.Yatta_push_HB_element=[a],this.sendIwcIntent("Yatta_get_HB_element",this.HB.getOperationCounter()),s=function(t){return function(n){var e;return e=n.extras,null!=t.initialized[e.uid.creator]?t.receive(e):void 0}}(this),this.iwcHandler.Yatta_new_operation=[s],null!=u&&this.engine.applyOpsCheckDouble(u),l=function(t){return function(n){var e,i;return i=n.extras,console.log(i),e={HB:t.yatta.getHistoryBuffer()._encode(i),user:t.yatta.getUserId()},t.sendIwcIntent("Yatta_push_HB_element",e)}}(this),this.iwcHandler.Yatta_get_HB_element=[l]}return t.prototype.send=function(t){return t.uid.creator===this.HB.getUserId()&&"string"!=typeof t.uid.op_number?this.sendIwcIntent("Yatta_new_operation",t):void 0},t.prototype.receive=function(t){return t.uid.creator!==this.HB.getUserId()?this.engine.applyOp(t):void 0},t.prototype.sendIwcIntent=function(t,n){var e;return e=null,arguments.length>=2?(t=arguments[0],n=arguments[1],e={action:t,component:"",data:"",dataType:"",flags:["PUBLISH_GLOBAL"],extras:n}):e=arguments[0],this.duiClient.sendIntent(e)},t.prototype.setIwcHandler=function(t){return a=t},t}(),r=function(){var n;return n=Math.floor(1e6*Math.random()),t(e,n)},void setTimeout(r,5e3)},module.exports=t,"undefined"!=typeof window&&null!==window&&(null==window.Y&&(window.Y={}),window.Y.createIwcConnector=t)}).call(this);
(function() {
var createIwcConnector;
createIwcConnector = function(callback, options) {
var IwcConnector, duiClient, init, iwcHandler, received_HB, userIwcHandler;
userIwcHandler = null;
if (options != null) {
userIwcHandler = options.iwcHandler;
}
iwcHandler = {};
duiClient = new DUIClient();
duiClient.connect(function(intent) {
var _ref;
if ((_ref = iwcHandler[intent.action]) != null) {
_ref.map(function(f) {
return setTimeout(function() {
return f(intent);
}, 0);
});
}
if (userIwcHandler != null) {
return userIwcHandler(intent);
}
});
duiClient.initOK();
received_HB = null;
IwcConnector = (function() {
function IwcConnector(engine, HB, execution_listener, yatta) {
var receiveHB, receive_, sendHistoryBuffer, send_;
this.engine = engine;
this.HB = HB;
this.execution_listener = execution_listener;
this.yatta = yatta;
this.duiClient = duiClient;
this.iwcHandler = iwcHandler;
send_ = (function(_this) {
return function(o) {
if (Object.getOwnPropertyNames(_this.initialized).length !== 0) {
return _this.send(o);
}
};
})(this);
this.execution_listener.push(send_);
this.initialized = {};
receiveHB = (function(_this) {
return function(json) {
var him;
HB = json.extras.HB;
him = json.extras.user;
_this.engine.applyOpsCheckDouble(HB);
return _this.initialized[him] = true;
};
})(this);
iwcHandler["Yatta_push_HB_element"] = [receiveHB];
this.sendIwcIntent("Yatta_get_HB_element", this.HB.getOperationCounter());
receive_ = (function(_this) {
return function(intent) {
var o;
o = intent.extras;
if (_this.initialized[o.uid.creator] != null) {
return _this.receive(o);
}
};
})(this);
this.iwcHandler["Yatta_new_operation"] = [receive_];
if (received_HB != null) {
this.engine.applyOpsCheckDouble(received_HB);
}
sendHistoryBuffer = (function(_this) {
return function(intent) {
var json, state_vector;
state_vector = intent.extras;
console.log(state_vector);
json = {
HB: _this.yatta.getHistoryBuffer()._encode(state_vector),
user: _this.yatta.getUserId()
};
return _this.sendIwcIntent("Yatta_push_HB_element", json);
};
})(this);
this.iwcHandler["Yatta_get_HB_element"] = [sendHistoryBuffer];
}
IwcConnector.prototype.setIwcHandler = function(f) {
return userIwcHandler = f;
};
IwcConnector.prototype.sendIwcIntent = function(action_name, content) {
var intent;
intent = null;
if (arguments.length >= 2) {
action_name = arguments[0], content = arguments[1];
intent = {
action: action_name,
component: "",
data: "",
dataType: "",
flags: ["PUBLISH_GLOBAL"],
extras: content
};
} else {
intent = arguments[0];
}
return this.duiClient.sendIntent(intent);
};
IwcConnector.prototype.send = function(o) {
if (o.uid.creator === this.HB.getUserId() && (typeof o.uid.op_number !== "string")) {
return this.sendIwcIntent("Yatta_new_operation", o);
}
};
IwcConnector.prototype.receive = function(o) {
if (o.uid.creator !== this.HB.getUserId()) {
return this.engine.applyOp(o);
}
};
return IwcConnector;
})();
init = function() {
var proposed_user_id;
proposed_user_id = Math.floor(Math.random() * 1000000);
return callback(IwcConnector, proposed_user_id);
};
setTimeout(init, 5000);
return void 0;
};
module.exports = createIwcConnector;
if (typeof window !== "undefined" && window !== null) {
if (window.Y == null) {
window.Y = {};
}
window.Y.createIwcConnector = createIwcConnector;
}
}).call(this);
//# sourceMappingURL=../Connectors/IwcConnector.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,132 @@
(function(){var n;n=function(){var n,t,e;return e=null,2===arguments.length?(e=new Peer(arguments[0]),t=arguments[1]):(e=new Peer(arguments[0],arguments[1]),t=arguments[2]),n=function(){function n(n,t,o,r){var i;this.engine=n,this.HB=t,this.execution_listener=o,this.yatta=r,this.peer=e,this.connections={},this.peer.on("connection",function(n){return function(t){return n.addConnection(t)}}(this)),i=function(n){return function(t){return n.send(t)}}(this),this.execution_listener.push(i)}return n.prototype.connectToPeer=function(n){return null==this.connections[n]&&n!==this.yatta.getUserId()?this.addConnection(e.connect(n)):void 0},n.prototype.getAllConnectionIds=function(){var n,t;t=[];for(n in this.connections)t.push(n);return t},n.prototype.addConnection=function(n){var t,e,o;return this.connections[n.peer]=n,e=!1,t=!1,n.on("data",function(o){return function(r){var i,s,u,c,a;if("empty_message"===r);else{if(null!=r.HB)return e=!0,o.engine.applyOpsCheckDouble(r.HB),n.send({conns:o.getAllConnectionIds()});if(null!=r.op)return o.engine.applyOp(r.op);if(null!=r.conns){for(c=r.conns,a=[],s=0,u=c.length;u>s;s++)i=c[s],a.push(o.connectToPeer(i));return a}if(null==r.state_vector)throw new Error("Can't parse this operation");if(!t)return n.send({HB:o.yatta.getHistoryBuffer()._encode(r.state_vector)}),t=!0}}}(this)),(o=function(t){return function(){return n.send({state_vector:t.HB.getOperationCounter()}),e?void 0:setTimeout(o,100)}}(this))()},n.prototype.send=function(n){var t,e,o,r;if(n.uid.creator===this.HB.getUserId()&&"string"!=typeof n.uid.op_number){o=this.connections,r=[];for(e in o)t=o[e],r.push(t.send({op:n}));return r}},n.prototype.receive=function(n){return n.uid.creator!==this.HB.getUserId()?this.engine.applyOp(n):void 0},n}(),e.on("open",function(e){return t(n,e)})},module.exports=n,"undefined"!=typeof window&&null!==window&&(null==window.Y&&(window.Y={}),window.Y.createPeerJsConnector=n)}).call(this);
(function() {
var createPeerJsConnector;
createPeerJsConnector = function() {
var PeerJsConnector, callback, peer;
peer = null;
if (arguments.length === 2) {
peer = new Peer(arguments[0]);
callback = arguments[1];
} else {
peer = new Peer(arguments[0], arguments[1]);
callback = arguments[2];
}
PeerJsConnector = (function() {
function PeerJsConnector(engine, HB, execution_listener, yatta) {
var send_;
this.engine = engine;
this.HB = HB;
this.execution_listener = execution_listener;
this.yatta = yatta;
this.peer = peer;
this.connections = {};
this.peer.on('connection', (function(_this) {
return function(conn) {
return _this.addConnection(conn);
};
})(this));
send_ = (function(_this) {
return function(o) {
var conn, conn_id, _ref, _results;
if (o.uid.creator === _this.HB.getUserId() && (typeof o.uid.op_number !== "string")) {
_ref = _this.connections;
_results = [];
for (conn_id in _ref) {
conn = _ref[conn_id];
_results.push(conn.send({
op: o
}));
}
return _results;
}
};
})(this);
this.execution_listener.push(send_);
}
PeerJsConnector.prototype.connectToPeer = function(id) {
if ((this.connections[id] == null) && id !== this.yatta.getUserId()) {
return this.addConnection(peer.connect(id));
}
};
PeerJsConnector.prototype.getAllConnectionIds = function() {
var conn_id, _results;
_results = [];
for (conn_id in this.connections) {
_results.push(conn_id);
}
return _results;
};
PeerJsConnector.prototype.addConnection = function(conn) {
var initialized_him, initialized_me, sendStateVector;
this.connections[conn.peer] = conn;
initialized_me = false;
initialized_him = false;
conn.on('data', (function(_this) {
return function(data) {
var conn_id, _i, _len, _ref, _results;
if (data === "empty_message") {
} else if (data.HB != null) {
initialized_me = true;
_this.engine.applyOpsCheckDouble(data.HB);
return conn.send({
conns: _this.getAllConnectionIds()
});
} else if (data.op != null) {
return _this.engine.applyOp(data.op);
} else if (data.conns != null) {
_ref = data.conns;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
conn_id = _ref[_i];
_results.push(_this.connectToPeer(conn_id));
}
return _results;
} else if (data.state_vector != null) {
if (!initialized_him) {
conn.send({
HB: _this.yatta.getHistoryBuffer()._encode(data.state_vector)
});
return initialized_him = true;
}
} else {
throw new Error("Can't parse this operation");
}
};
})(this));
sendStateVector = (function(_this) {
return function() {
conn.send({
state_vector: _this.HB.getOperationCounter()
});
if (!initialized_me) {
return setTimeout(sendStateVector, 100);
}
};
})(this);
return sendStateVector();
};
return PeerJsConnector;
})();
return peer.on('open', function(id) {
return callback(PeerJsConnector, id);
});
};
module.exports = createPeerJsConnector;
if (typeof window !== "undefined" && window !== null) {
if (window.Y == null) {
window.Y = {};
}
window.Y.createPeerJsConnector = createPeerJsConnector;
}
}).call(this);
//# sourceMappingURL=../Connectors/PeerJsConnector.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,76 +0,0 @@
_ = require "underscore"
module.exports = (user_list)->
#
# A trivial Connector that simulates network delay.
#
class TestConnector
#
# @param {Engine} engine The transformation engine
# @param {HistoryBuffer} HB
# @param {Array<Function>} execution_listener You must ensure that whenever an operation is executed, every function in this Array is called.
# @param {Yatta} yatta The Yatta framework.
#
constructor: (@engine, @HB, @execution_listener)->
send_ = (o)=>
@send o
@execution_listener.push send_
@applied_operations = []
appliedOperationsListener = (o)=>
@applied_operations.push o
@execution_listener.push appliedOperationsListener
if not (user_list?.length is 0)
@engine.applyOps user_list[0].getHistoryBuffer()._encode()
@unexecuted = {}
#
# This engine applied operations in a specific order.
# Get the ops in the right order.
#
getOpsInExecutionOrder: ()->
@applied_operations
#
# This function is called whenever an operation was executed.
# @param {Operation} o The operation that was executed.
#
send: (o)->
if (o.uid.creator is @HB.getUserId()) and (typeof o.uid.op_number isnt "string")
for user in user_list
if user.getUserId() isnt @HB.getUserId()
user.getConnector().receive(o)
#
# This function is called whenever an operation was received from another peer.
# @param {Operation} o The operation that was received.
#
receive: (o)->
@unexecuted[o.uid.creator] ?= []
@unexecuted[o.uid.creator].push o
#
# Flush one operation from the line of a specific user.
#
flushOne: (user)->
if @unexecuted[user]?.length > 0
@engine.applyOp @unexecuted[user].shift()
#
# Flush one operation on a random line.
#
flushOneRandom: ()->
@flushOne (_.random 0, (user_list.length-1))
#
# Flush all operations on every line.
#
flushAll: ()->
for n,ops of @unexecuted
@engine.applyOps ops
@unexecuted = {}

View File

@@ -1,2 +1,89 @@
(function(){var e;e=require("underscore"),module.exports=function(t){var n;return n=function(){function n(e,n,i){var r,u;this.engine=e,this.HB=n,this.execution_listener=i,u=function(e){return function(t){return e.send(t)}}(this),this.execution_listener.push(u),this.applied_operations=[],r=function(e){return function(t){return e.applied_operations.push(t)}}(this),this.execution_listener.push(r),0!==(null!=t?t.length:void 0)&&this.engine.applyOps(t[0].getHistoryBuffer()._encode()),this.unexecuted={}}return n.prototype.getOpsInExecutionOrder=function(){return this.applied_operations},n.prototype.send=function(e){var n,i,r,u;if(e.uid.creator===this.HB.getUserId()&&"string"!=typeof e.uid.op_number){for(u=[],i=0,r=t.length;r>i;i++)n=t[i],u.push(n.getUserId()!==this.HB.getUserId()?n.getConnector().receive(e):void 0);return u}},n.prototype.receive=function(e){var t,n;return null==(t=this.unexecuted)[n=e.uid.creator]&&(t[n]=[]),this.unexecuted[e.uid.creator].push(e)},n.prototype.flushOne=function(e){var t;return(null!=(t=this.unexecuted[e])?t.length:void 0)>0?this.engine.applyOp(this.unexecuted[e].shift()):void 0},n.prototype.flushOneRandom=function(){return this.flushOne(e.random(0,t.length-1))},n.prototype.flushAll=function(){var e,t,n;n=this.unexecuted;for(e in n)t=n[e],this.engine.applyOps(t);return this.unexecuted={}},n}()}}).call(this);
(function() {
var _;
_ = require("underscore");
module.exports = function(user_list) {
var TestConnector;
return TestConnector = (function() {
function TestConnector(engine, HB, execution_listener) {
var appliedOperationsListener, send_;
this.engine = engine;
this.HB = HB;
this.execution_listener = execution_listener;
send_ = (function(_this) {
return function(o) {
return _this.send(o);
};
})(this);
this.execution_listener.push(send_);
this.applied_operations = [];
appliedOperationsListener = (function(_this) {
return function(o) {
return _this.applied_operations.push(o);
};
})(this);
this.execution_listener.push(appliedOperationsListener);
if (!((user_list != null ? user_list.length : void 0) === 0)) {
this.engine.applyOps(user_list[0].getHistoryBuffer()._encode());
}
this.unexecuted = {};
}
TestConnector.prototype.getOpsInExecutionOrder = function() {
return this.applied_operations;
};
TestConnector.prototype.send = function(o) {
var user, _i, _len, _results;
if ((o.uid.creator === this.HB.getUserId()) && (typeof o.uid.op_number !== "string")) {
_results = [];
for (_i = 0, _len = user_list.length; _i < _len; _i++) {
user = user_list[_i];
if (user.getUserId() !== this.HB.getUserId()) {
_results.push(user.getConnector().receive(o));
} else {
_results.push(void 0);
}
}
return _results;
}
};
TestConnector.prototype.receive = function(o) {
var _base, _name;
if ((_base = this.unexecuted)[_name = o.uid.creator] == null) {
_base[_name] = [];
}
return this.unexecuted[o.uid.creator].push(o);
};
TestConnector.prototype.flushOne = function(user) {
var _ref;
if (((_ref = this.unexecuted[user]) != null ? _ref.length : void 0) > 0) {
return this.engine.applyOp(this.unexecuted[user].shift());
}
};
TestConnector.prototype.flushOneRandom = function() {
return this.flushOne(_.random(0, user_list.length - 1));
};
TestConnector.prototype.flushAll = function() {
var n, ops, _ref;
_ref = this.unexecuted;
for (n in _ref) {
ops = _ref[n];
this.engine.applyOps(ops);
}
return this.unexecuted = {};
};
return TestConnector;
})();
};
}).call(this);
//# sourceMappingURL=../Connectors/TestConnector.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"Connectors/TestConnector.js","sources":["Connectors/TestConnector.coffee"],"names":[],"mappings":"CACA,WAAA,GAAA,EAAA,GAAI,QAAQ,cAEZ,OAAO,QAAU,SAAC,GAKhB,GAAA,SAAM,GAAA,WAQS,QAAA,GAAE,EAAS,EAAK,GAC3B,GAAA,GAAA,CADY,MAAC,OAAA,EAAQ,KAAC,GAAA,EAAI,KAAC,mBAAA,EAC3B,EAAQ,SAAA,SAAA,UAAC,SACP,GAAC,KAAK,KADA,MAER,KAAC,mBAAmB,KAAK,GAEzB,KAAC,sBACD,EAA4B,SAAA,SAAA,UAAC,SAC3B,GAAC,mBAAmB,KAAK,KADC,MAE5B,KAAC,mBAAmB,KAAK,GACI,KAA1B,MAAA,EAAK,EAAW,OAAA,SACjB,KAAC,OAAO,SAAS,EAAU,GAAG,mBAAmB,WAEnD,KAAC,oBAZH,GAAA,UAkBA,uBAAwB,iBACtB,MAAC,oBAnBH,EAAA,UAyBA,KAAM,SAAC,GACL,GAAA,GAAA,EAAA,EAAA,CAAA,IAAI,EAAE,IAAI,UAAW,KAAC,GAAG,aAA8C,gBAA5B,GAAS,IAAI,UAAxD,KACE,KAAA,EAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,kBACK,EAAK,cAAiB,KAAC,GAAG,YAC3B,EAAK,eAAe,QAAQ,sBA7BpC,EAAA,UAmCA,QAAS,SAAC,GACR,GAAA,GAAA,+DACA,KAAC,WAAW,EAAE,IAAI,SAAS,KAAK,IArClC,EAAA,UA0CA,SAAU,SAAC,GACT,GAAA,EAAA,QAAA,OAAA,EAAA,KAAA,WAAA,IAAA,EAAsB,OAAA,QAAS,EAC7B,KAAC,OAAO,QAAQ,KAAC,WAAW,GAAM,SADpC,QA3CF,EAAA,UAiDA,eAAgB,iBACd,MAAC,SAAU,EAAE,OAAO,EAAI,EAAU,OAAO,KAlD3C,EAAA,UAuDA,SAAU,WACR,GAAA,GAAA,EAAA,CAAA,GAAA,KAAA,UAAA,KAAA,IAAA,UACE,KAAC,OAAO,SAAS,SACnB,MAAC","sourcesContent":["\n_ = require \"underscore\"\n\nmodule.exports = (user_list)->\n\n #\n # A trivial Connector that simulates network delay.\n #\n class TestConnector\n\n #\n # @param {Engine} engine The transformation engine\n # @param {HistoryBuffer} HB\n # @param {Array<Function>} execution_listener You must ensure that whenever an operation is executed, every function in this Array is called.\n # @param {Yatta} yatta The Yatta framework.\n #\n constructor: (@engine, @HB, @execution_listener)->\n send_ = (o)=>\n @send o\n @execution_listener.push send_\n\n @applied_operations = []\n appliedOperationsListener = (o)=>\n @applied_operations.push o\n @execution_listener.push appliedOperationsListener\n if not (user_list?.length is 0)\n @engine.applyOps user_list[0].getHistoryBuffer()._encode()\n\n @unexecuted = {}\n\n #\n # This engine applied operations in a specific order.\n # Get the ops in the right order.\n #\n getOpsInExecutionOrder: ()->\n @applied_operations\n\n #\n # This function is called whenever an operation was executed.\n # @param {Operation} o The operation that was executed.\n #\n send: (o)->\n if (o.uid.creator is @HB.getUserId()) and (typeof o.uid.op_number isnt \"string\")\n for user in user_list\n if user.getUserId() isnt @HB.getUserId()\n user.getConnector().receive(o)\n\n #\n # This function is called whenever an operation was received from another peer.\n # @param {Operation} o The operation that was received.\n #\n receive: (o)->\n @unexecuted[o.uid.creator] ?= []\n @unexecuted[o.uid.creator].push o\n\n #\n # Flush one operation from the line of a specific user.\n #\n flushOne: (user)->\n if @unexecuted[user]?.length > 0\n @engine.applyOp @unexecuted[user].shift()\n\n #\n # Flush one operation on a random line.\n #\n flushOneRandom: ()->\n @flushOne (_.random 0, (user_list.length-1))\n\n #\n # Flush all operations on every line.\n #\n flushAll: ()->\n for n,ops of @unexecuted\n @engine.applyOps ops\n @unexecuted = {}\n\n"],"sourceRoot":"/source/"}
{"version":3,"sources":["Connectors/TestConnector.coffee"],"names":[],"mappings":"AACA;AAAA,MAAA,CAAA;;AAAA,EAAA,CAAA,GAAI,OAAA,CAAQ,YAAR,CAAJ,CAAA;;AAAA,EAEA,MAAM,CAAC,OAAP,GAAiB,SAAC,SAAD,GAAA;AAMf,QAAA,aAAA;WAAM;AAQS,MAAA,uBAAE,MAAF,EAAW,EAAX,EAAgB,kBAAhB,GAAA;AACX,YAAA,gCAAA;AAAA,QADY,IAAC,CAAA,SAAA,MACb,CAAA;AAAA,QADqB,IAAC,CAAA,KAAA,EACtB,CAAA;AAAA,QAD0B,IAAC,CAAA,qBAAA,kBAC3B,CAAA;AAAA,QAAA,KAAA,GAAQ,CAAA,SAAA,KAAA,GAAA;iBAAA,SAAC,CAAD,GAAA;mBACN,KAAC,CAAA,IAAD,CAAM,CAAN,EADM;UAAA,EAAA;QAAA,CAAA,CAAA,CAAA,IAAA,CAAR,CAAA;AAAA,QAEA,IAAC,CAAA,kBAAkB,CAAC,IAApB,CAAyB,KAAzB,CAFA,CAAA;AAAA,QAIA,IAAC,CAAA,kBAAD,GAAsB,EAJtB,CAAA;AAAA,QAKA,yBAAA,GAA4B,CAAA,SAAA,KAAA,GAAA;iBAAA,SAAC,CAAD,GAAA;mBAC1B,KAAC,CAAA,kBAAkB,CAAC,IAApB,CAAyB,CAAzB,EAD0B;UAAA,EAAA;QAAA,CAAA,CAAA,CAAA,IAAA,CAL5B,CAAA;AAAA,QAOA,IAAC,CAAA,kBAAkB,CAAC,IAApB,CAAyB,yBAAzB,CAPA,CAAA;AAQA,QAAA,IAAG,CAAA,sBAAK,SAAS,CAAE,gBAAX,KAAqB,CAAtB,CAAP;AACE,UAAA,IAAC,CAAA,MAAM,CAAC,QAAR,CAAiB,SAAU,CAAA,CAAA,CAAE,CAAC,gBAAb,CAAA,CAA+B,CAAC,OAAhC,CAAA,CAAjB,CAAA,CADF;SARA;AAAA,QAWA,IAAC,CAAA,UAAD,GAAc,EAXd,CADW;MAAA,CAAb;;AAAA,8BAkBA,sBAAA,GAAwB,SAAA,GAAA;eACtB,IAAC,CAAA,mBADqB;MAAA,CAlBxB,CAAA;;AAAA,8BAyBA,IAAA,GAAM,SAAC,CAAD,GAAA;AACJ,YAAA,wBAAA;AAAA,QAAA,IAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAN,KAAiB,IAAC,CAAA,EAAE,CAAC,SAAJ,CAAA,CAAlB,CAAA,IAAuC,CAAC,MAAA,CAAA,CAAQ,CAAC,GAAG,CAAC,SAAb,KAA4B,QAA7B,CAA1C;AACE;eAAA,gDAAA;iCAAA;AACE,YAAA,IAAG,IAAI,CAAC,SAAL,CAAA,CAAA,KAAsB,IAAC,CAAA,EAAE,CAAC,SAAJ,CAAA,CAAzB;4BACE,IAAI,CAAC,YAAL,CAAA,CAAmB,CAAC,OAApB,CAA4B,CAA5B,GADF;aAAA,MAAA;oCAAA;aADF;AAAA;0BADF;SADI;MAAA,CAzBN,CAAA;;AAAA,8BAmCA,OAAA,GAAS,SAAC,CAAD,GAAA;AACP,YAAA,YAAA;;yBAA8B;SAA9B;eACA,IAAC,CAAA,UAAW,CAAA,CAAC,CAAC,GAAG,CAAC,OAAN,CAAc,CAAC,IAA3B,CAAgC,CAAhC,EAFO;MAAA,CAnCT,CAAA;;AAAA,8BA0CA,QAAA,GAAU,SAAC,IAAD,GAAA;AACR,YAAA,IAAA;AAAA,QAAA,kDAAoB,CAAE,gBAAnB,GAA4B,CAA/B;iBACE,IAAC,CAAA,MAAM,CAAC,OAAR,CAAgB,IAAC,CAAA,UAAW,CAAA,IAAA,CAAK,CAAC,KAAlB,CAAA,CAAhB,EADF;SADQ;MAAA,CA1CV,CAAA;;AAAA,8BAiDA,cAAA,GAAgB,SAAA,GAAA;eACd,IAAC,CAAA,QAAD,CAAW,CAAC,CAAC,MAAF,CAAS,CAAT,EAAa,SAAS,CAAC,MAAV,GAAiB,CAA9B,CAAX,EADc;MAAA,CAjDhB,CAAA;;AAAA,8BAuDA,QAAA,GAAU,SAAA,GAAA;AACR,YAAA,YAAA;AAAA;AAAA,aAAA,SAAA;wBAAA;AACE,UAAA,IAAC,CAAA,MAAM,CAAC,QAAR,CAAiB,GAAjB,CAAA,CADF;AAAA,SAAA;eAEA,IAAC,CAAA,UAAD,GAAc,GAHN;MAAA,CAvDV,CAAA;;2BAAA;;SAda;EAAA,CAFjB,CAAA;AAAA","file":"Connectors/TestConnector.js","sourceRoot":"/source/","sourcesContent":["\n_ = require \"underscore\"\n\nmodule.exports = (user_list)->\n\n #\n # @nodoc\n # A trivial Connector that simulates network delay.\n #\n class TestConnector\n\n #\n # @param {Engine} engine The transformation engine\n # @param {HistoryBuffer} HB\n # @param {Array<Function>} execution_listener You must ensure that whenever an operation is executed, every function in this Array is called.\n # @param {Yatta} yatta The Yatta framework.\n #\n constructor: (@engine, @HB, @execution_listener)->\n send_ = (o)=>\n @send o\n @execution_listener.push send_\n\n @applied_operations = []\n appliedOperationsListener = (o)=>\n @applied_operations.push o\n @execution_listener.push appliedOperationsListener\n if not (user_list?.length is 0)\n @engine.applyOps user_list[0].getHistoryBuffer()._encode()\n\n @unexecuted = {}\n\n #\n # This engine applied operations in a specific order.\n # Get the ops in the right order.\n #\n getOpsInExecutionOrder: ()->\n @applied_operations\n\n #\n # This function is called whenever an operation was executed.\n # @param {Operation} o The operation that was executed.\n #\n send: (o)->\n if (o.uid.creator is @HB.getUserId()) and (typeof o.uid.op_number isnt \"string\")\n for user in user_list\n if user.getUserId() isnt @HB.getUserId()\n user.getConnector().receive(o)\n\n #\n # This function is called whenever an operation was received from another peer.\n # @param {Operation} o The operation that was received.\n #\n receive: (o)->\n @unexecuted[o.uid.creator] ?= []\n @unexecuted[o.uid.creator].push o\n\n #\n # Flush one operation from the line of a specific user.\n #\n flushOne: (user)->\n if @unexecuted[user]?.length > 0\n @engine.applyOp @unexecuted[user].shift()\n\n #\n # Flush one operation on a random line.\n #\n flushOneRandom: ()->\n @flushOne (_.random 0, (user_list.length-1))\n\n #\n # Flush all operations on every line.\n #\n flushAll: ()->\n for n,ops of @unexecuted\n @engine.applyOps ops\n @unexecuted = {}\n\n"]}

View File

@@ -1,101 +0,0 @@
#
# The Engine handles how and in which order to execute operations and add operations to the HistoryBuffer.
#
class Engine
#
# @param {HistoryBuffer} HB
# @param {Array} parser Defines how to parse encoded messages.
#
constructor: (@HB, @parser)->
@unprocessed_ops = []
#
# Parses an operatio from the json format. It uses the specified parser in your OperationType module.
#
parseOperation: (json)->
typeParser = @parser[json.type]
if typeParser?
typeParser json
else
throw new Error "You forgot to specify a parser for type #{json.type}. The message is #{JSON.stringify json}."
#
# Apply a set of operations. E.g. the operations you received from another users HB.toJson().
# @note You must not use this method when you already have ops in your HB!
#
applyOpsBundle: (ops_json)->
ops = []
for o in ops_json
ops.push @parseOperation o
for o in ops
@HB.addOperation o
for o in ops
if not o.execute()
@unprocessed_ops.push o
@tryUnprocessed()
#
# Same as applyOps but operations that are already in the HB are not applied.
# @see Engine.applyOps
#
applyOpsCheckDouble: (ops_json)->
for o in ops_json
if @HB.getOperation(o.uid)?
@applyOp o
#
# Apply a set of operations. (Helper for using applyOp on Arrays)
# @see Engine.applyOp
applyOps: (ops_json)->
for o in ops_json
@applyOp o
#
# Apply an operation that you received from another peer.
#
applyOp: (op_json)->
# $parse_and_execute will return false if $o_json was parsed and executed, otherwise the parsed operadion
o = @parseOperation op_json
@HB.addToCounter o
# @HB.addOperation o
if not o.execute()
@unprocessed_ops.push o
else
@HB.addOperation o
@tryUnprocessed()
#
# Call this method when you applied a new operation.
# It checks if operations that were previously not executable are now executable.
#
tryUnprocessed: ()->
while true
old_length = @unprocessed_ops.length
unprocessed = []
for op in @unprocessed_ops
if not op.execute()
unprocessed.push op
else
@HB.addOperation op
@unprocessed_ops = unprocessed
if @unprocessed_ops.length is old_length
break
module.exports = Engine

View File

@@ -1,2 +1,110 @@
(function(){var t;t=function(){function t(t,e){this.HB=t,this.parser=e,this.unprocessed_ops=[]}return t.prototype.parseOperation=function(t){var e;if(e=this.parser[t.type],null!=e)return e(t);throw new Error("You forgot to specify a parser for type "+t.type+". The message is "+JSON.stringify(t)+".")},t.prototype.applyOpsBundle=function(t){var e,r,p,s,o,n,i,u;for(r=[],p=0,n=t.length;n>p;p++)e=t[p],r.push(this.parseOperation(e));for(s=0,i=r.length;i>s;s++)e=r[s],this.HB.addOperation(e);for(o=0,u=r.length;u>o;o++)e=r[o],e.execute()||this.unprocessed_ops.push(e);return this.tryUnprocessed()},t.prototype.applyOpsCheckDouble=function(t){var e,r,p,s;for(s=[],r=0,p=t.length;p>r;r++)e=t[r],s.push(null==this.HB.getOperation(e.uid)?this.applyOp(e):void 0);return s},t.prototype.applyOps=function(t){var e,r,p,s;for(s=[],r=0,p=t.length;p>r;r++)e=t[r],s.push(this.applyOp(e));return s},t.prototype.applyOp=function(t){var e;return e=this.parseOperation(t),this.HB.addToCounter(e),e.execute()?this.HB.addOperation(e):this.unprocessed_ops.push(e),this.tryUnprocessed()},t.prototype.tryUnprocessed=function(){var t,e,r,p,s,o,n;for(n=[];;){for(t=this.unprocessed_ops.length,r=[],o=this.unprocessed_ops,p=0,s=o.length;s>p;p++)e=o[p],e.execute()?this.HB.addOperation(e):r.push(e);if(this.unprocessed_ops=r,this.unprocessed_ops.length===t)break;n.push(void 0)}return n},t}(),module.exports=t}).call(this);
(function() {
var Engine;
Engine = (function() {
function Engine(HB, parser) {
this.HB = HB;
this.parser = parser;
this.unprocessed_ops = [];
}
Engine.prototype.parseOperation = function(json) {
var typeParser;
typeParser = this.parser[json.type];
if (typeParser != null) {
return typeParser(json);
} else {
throw new Error("You forgot to specify a parser for type " + json.type + ". The message is " + (JSON.stringify(json)) + ".");
}
};
Engine.prototype.applyOpsBundle = function(ops_json) {
var o, ops, _i, _j, _k, _len, _len1, _len2;
ops = [];
for (_i = 0, _len = ops_json.length; _i < _len; _i++) {
o = ops_json[_i];
ops.push(this.parseOperation(o));
}
for (_j = 0, _len1 = ops.length; _j < _len1; _j++) {
o = ops[_j];
this.HB.addOperation(o);
}
for (_k = 0, _len2 = ops.length; _k < _len2; _k++) {
o = ops[_k];
if (!o.execute()) {
this.unprocessed_ops.push(o);
}
}
return this.tryUnprocessed();
};
Engine.prototype.applyOpsCheckDouble = function(ops_json) {
var o, _i, _len, _results;
_results = [];
for (_i = 0, _len = ops_json.length; _i < _len; _i++) {
o = ops_json[_i];
if (this.HB.getOperation(o.uid) == null) {
_results.push(this.applyOp(o));
} else {
_results.push(void 0);
}
}
return _results;
};
Engine.prototype.applyOps = function(ops_json) {
var o, _i, _len, _results;
_results = [];
for (_i = 0, _len = ops_json.length; _i < _len; _i++) {
o = ops_json[_i];
_results.push(this.applyOp(o));
}
return _results;
};
Engine.prototype.applyOp = function(op_json) {
var o;
o = this.parseOperation(op_json);
this.HB.addToCounter(o);
if (!o.execute()) {
this.unprocessed_ops.push(o);
} else {
this.HB.addOperation(o);
}
return this.tryUnprocessed();
};
Engine.prototype.tryUnprocessed = function() {
var old_length, op, unprocessed, _i, _len, _ref, _results;
_results = [];
while (true) {
old_length = this.unprocessed_ops.length;
unprocessed = [];
_ref = this.unprocessed_ops;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
op = _ref[_i];
if (!op.execute()) {
unprocessed.push(op);
} else {
this.HB.addOperation(op);
}
}
this.unprocessed_ops = unprocessed;
if (this.unprocessed_ops.length === old_length) {
break;
} else {
_results.push(void 0);
}
}
return _results;
};
return Engine;
})();
module.exports = Engine;
}).call(this);
//# sourceMappingURL=Engine.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,95 @@
(function() {
var Engine, HistoryBuffer, JsonFramework, json_types_uninitialized;
json_types_uninitialized = require("../Types/JsonTypes");
HistoryBuffer = require("../HistoryBuffer");
Engine = require("../Engine");
JsonFramework = (function() {
function JsonFramework(user_id, Connector) {
var first_word, type_manager;
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.connector = new Connector(this.engine, this.HB, type_manager.execution_listener, this);
first_word = new this.types.JsonType(this.HB.getReservedUniqueIdentifier());
this.HB.addOperation(first_word).execute();
this.root_element = first_word;
}
JsonFramework.prototype.getSharedObject = function() {
return this.root_element;
};
JsonFramework.prototype.getConnector = function() {
return this.connector;
};
JsonFramework.prototype.getHistoryBuffer = function() {
return this.HB;
};
JsonFramework.prototype.setMutableDefault = function(mutable) {
return this.root_element.setMutableDefault(mutable);
};
JsonFramework.prototype.getUserId = function() {
return this.HB.getUserId();
};
JsonFramework.prototype.toJson = function() {
return this.root_element.toJson();
};
JsonFramework.prototype.val = function(name, content, mutable) {
return this.root_element.val(name, content, mutable);
};
JsonFramework.prototype.on = function() {
var _ref;
return (_ref = this.root_element).on.apply(_ref, arguments);
};
JsonFramework.prototype.deleteListener = function() {
var _ref;
return (_ref = this.root_element).deleteListener.apply(_ref, arguments);
};
Object.defineProperty(JsonFramework.prototype, 'value', {
get: function() {
return this.root_element.value;
},
set: function(o) {
var o_name, o_obj, _results;
if (o.constructor === {}.constructor) {
_results = [];
for (o_name in o) {
o_obj = o[o_name];
_results.push(this.val(o_name, o_obj, 'immutable'));
}
return _results;
} else {
throw new Error("You must only set Object values!");
}
}
});
return JsonFramework;
})();
module.exports = JsonFramework;
if (typeof window !== "undefined" && window !== null) {
if (window.Y == null) {
window.Y = {};
}
window.Y.JsonFramework = JsonFramework;
}
}).call(this);
//# sourceMappingURL=../Frameworks/JsonFramework.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["Frameworks/JsonFramework.coffee"],"names":[],"mappings":"AACA;AAAA,MAAA,8DAAA;;AAAA,EAAA,wBAAA,GAA2B,OAAA,CAAQ,oBAAR,CAA3B,CAAA;;AAAA,EACA,aAAA,GAAgB,OAAA,CAAQ,kBAAR,CADhB,CAAA;;AAAA,EAEA,MAAA,GAAS,OAAA,CAAQ,WAAR,CAFT,CAAA;;AAAA,EAWM;AAMS,IAAA,uBAAC,OAAD,EAAU,SAAV,GAAA;AACX,UAAA,wBAAA;AAAA,MAAA,IAAC,CAAA,EAAD,GAAU,IAAA,aAAA,CAAc,OAAd,CAAV,CAAA;AAAA,MACA,YAAA,GAAe,wBAAA,CAAyB,IAAC,CAAA,EAA1B,CADf,CAAA;AAAA,MAEA,IAAC,CAAA,KAAD,GAAS,YAAY,CAAC,KAFtB,CAAA;AAAA,MAGA,IAAC,CAAA,MAAD,GAAc,IAAA,MAAA,CAAO,IAAC,CAAA,EAAR,EAAY,YAAY,CAAC,MAAzB,CAHd,CAAA;AAAA,MAIA,IAAC,CAAA,SAAD,GAAiB,IAAA,SAAA,CAAU,IAAC,CAAA,MAAX,EAAmB,IAAC,CAAA,EAApB,EAAwB,YAAY,CAAC,kBAArC,EAAyD,IAAzD,CAJjB,CAAA;AAAA,MAKA,UAAA,GAAiB,IAAA,IAAC,CAAA,KAAK,CAAC,QAAP,CAAgB,IAAC,CAAA,EAAE,CAAC,2BAAJ,CAAA,CAAhB,CALjB,CAAA;AAAA,MAMA,IAAC,CAAA,EAAE,CAAC,YAAJ,CAAiB,UAAjB,CAA4B,CAAC,OAA7B,CAAA,CANA,CAAA;AAAA,MAOA,IAAC,CAAA,YAAD,GAAgB,UAPhB,CADW;IAAA,CAAb;;AAAA,4BAaA,eAAA,GAAiB,SAAA,GAAA;aACf,IAAC,CAAA,aADc;IAAA,CAbjB,CAAA;;AAAA,4BAmBA,YAAA,GAAc,SAAA,GAAA;aACZ,IAAC,CAAA,UADW;IAAA,CAnBd,CAAA;;AAAA,4BAyBA,gBAAA,GAAkB,SAAA,GAAA;aAChB,IAAC,CAAA,GADe;IAAA,CAzBlB,CAAA;;AAAA,4BA+BA,iBAAA,GAAmB,SAAC,OAAD,GAAA;aACjB,IAAC,CAAA,YAAY,CAAC,iBAAd,CAAgC,OAAhC,EADiB;IAAA,CA/BnB,CAAA;;AAAA,4BAuCA,SAAA,GAAW,SAAA,GAAA;aACT,IAAC,CAAA,EAAE,CAAC,SAAJ,CAAA,EADS;IAAA,CAvCX,CAAA;;AAAA,4BA6CA,MAAA,GAAS,SAAA,GAAA;aACP,IAAC,CAAA,YAAY,CAAC,MAAd,CAAA,EADO;IAAA,CA7CT,CAAA;;AAAA,4BAmDA,GAAA,GAAM,SAAC,IAAD,EAAO,OAAP,EAAgB,OAAhB,GAAA;aACJ,IAAC,CAAA,YAAY,CAAC,GAAd,CAAkB,IAAlB,EAAwB,OAAxB,EAAiC,OAAjC,EADI;IAAA,CAnDN,CAAA;;AAAA,4BAyDA,EAAA,GAAI,SAAA,GAAA;AACF,UAAA,IAAA;aAAA,QAAA,IAAC,CAAA,YAAD,CAAa,CAAC,EAAd,aAAiB,SAAjB,EADE;IAAA,CAzDJ,CAAA;;AAAA,4BA+DA,cAAA,GAAgB,SAAA,GAAA;AACd,UAAA,IAAA;aAAA,QAAA,IAAC,CAAA,YAAD,CAAa,CAAC,cAAd,aAA6B,SAA7B,EADc;IAAA,CA/DhB,CAAA;;AAAA,IAqEA,MAAM,CAAC,cAAP,CAAsB,aAAa,CAAC,SAApC,EAA+C,OAA/C,EACE;AAAA,MAAA,GAAA,EAAM,SAAA,GAAA;eAAG,IAAC,CAAA,YAAY,CAAC,MAAjB;MAAA,CAAN;AAAA,MACA,GAAA,EAAM,SAAC,CAAD,GAAA;AACJ,YAAA,uBAAA;AAAA,QAAA,IAAG,CAAC,CAAC,WAAF,KAAiB,EAAE,CAAC,WAAvB;AACE;eAAA,WAAA;8BAAA;AACE,0BAAA,IAAC,CAAA,GAAD,CAAK,MAAL,EAAa,KAAb,EAAoB,WAApB,EAAA,CADF;AAAA;0BADF;SAAA,MAAA;AAIE,gBAAU,IAAA,KAAA,CAAM,kCAAN,CAAV,CAJF;SADI;MAAA,CADN;KADF,CArEA,CAAA;;yBAAA;;MAjBF,CAAA;;AAAA,EA+FA,MAAM,CAAC,OAAP,GAAiB,aA/FjB,CAAA;;AAgGA,EAAA,IAAG,gDAAH;AACE,IAAA,IAAO,gBAAP;AACE,MAAA,MAAM,CAAC,CAAP,GAAW,EAAX,CADF;KAAA;AAAA,IAEA,MAAM,CAAC,CAAC,CAAC,aAAT,GAAyB,aAFzB,CADF;GAhGA;AAAA","file":"Frameworks/JsonFramework.js","sourceRoot":"/source/","sourcesContent":["\njson_types_uninitialized = require \"../Types/JsonTypes\"\nHistoryBuffer = require \"../HistoryBuffer\"\nEngine = require \"../Engine\"\n\n#\n# Framework for Json data-structures.\n# Known values that are supported:\n# * String\n# * Integer\n# * Array\n#\nclass JsonFramework\n\n #\n # @param {String} user_id Unique id of the peer.\n # @param {Connector} Connector the connector class.\n #\n constructor: (user_id, Connector)->\n @HB = new HistoryBuffer user_id\n type_manager = json_types_uninitialized @HB\n @types = type_manager.types\n @engine = new Engine @HB, type_manager.parser\n @connector = new Connector @engine, @HB, type_manager.execution_listener, @\n first_word = new @types.JsonType @HB.getReservedUniqueIdentifier()\n @HB.addOperation(first_word).execute()\n @root_element = first_word\n\n #\n # @return JsonType\n #\n getSharedObject: ()->\n @root_element\n\n #\n # Get the initialized connector.\n #\n getConnector: ()->\n @connector\n\n #\n # @see HistoryBuffer\n #\n getHistoryBuffer: ()->\n @HB\n\n #\n # @see JsonType.setMutableDefault\n #\n setMutableDefault: (mutable)->\n @root_element.setMutableDefault(mutable)\n\n #\n # Get the UserId from the HistoryBuffer object.\n # In most cases this will be the same as the user_id value with which\n # JsonFramework was initialized (Depending on the HistoryBuffer implementation).\n #\n getUserId: ()->\n @HB.getUserId()\n\n #\n # @see JsonType.toJson\n #\n toJson : ()->\n @root_element.toJson()\n\n #\n # @see JsonType.val\n #\n val : (name, content, mutable)->\n @root_element.val(name, content, mutable)\n\n #\n # @see Operation.on\n #\n on: ()->\n @root_element.on arguments...\n\n #\n # @see Operation.deleteListener\n #\n deleteListener: ()->\n @root_element.deleteListener arguments...\n\n #\n # @see JsonType.value\n #\n Object.defineProperty JsonFramework.prototype, 'value',\n get : -> @root_element.value\n set : (o)->\n if o.constructor is {}.constructor\n for o_name,o_obj of o\n @val(o_name, o_obj, 'immutable')\n else\n throw new Error \"You must only set Object values!\"\n\nmodule.exports = JsonFramework\nif window?\n if not window.Y?\n window.Y = {}\n window.Y.JsonFramework = JsonFramework\n"]}

View File

@@ -1,85 +0,0 @@
json_types_uninitialized = require "../Types/JsonTypes"
HistoryBuffer = require "../HistoryBuffer"
Engine = require "../Engine"
#
# Framework for Json data-structures.
# Known values that are supported:
# * String
# * Integer
# * Array
#
class JsonYatta
#
# @param {String} user_id Unique id of the peer.
# @param {Connector} Connector the connector class.
#
constructor: (user_id, Connector)->
@HB = new HistoryBuffer user_id
json_types = json_types_uninitialized @HB
@engine = new Engine @HB, json_types.parser
@connector = new Connector @engine, @HB, json_types.execution_listener, @
first_word = new json_types.types.JsonType @HB.getReservedUniqueIdentifier()
@HB.addOperation(first_word).execute()
@root_element = first_word
#
# @result JsonType
#
getSharedObject: ()->
@root_element
#
# @see Engine
#
getEngine: ()->
@engine
#
# Get the initialized connector.
#
getConnector: ()->
@connector
#
# @see HistoryBuffer
#
getHistoryBuffer: ()->
@HB
#
# @see JsonType.setMutableDefault
#
setMutableDefault: (mutable)->
@root_element.setMutableDefault(mutable)
#
# Get the UserId from the HistoryBuffer object.
# In most cases this will be the same as the user_id value with which
# JsonYatta was initialized (Depending on the HistoryBuffer implementation).
#
getUserId: ()->
@HB.getUserId()
#
# @see JsonType.val
#
val : (name, content, mutable)->
@root_element.val(name, content, mutable)
#
# @see JsonType.value
#
Object.defineProperty JsonYatta.prototype, 'value',
get : -> @root_element.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!"
window?.JsonYatta = JsonYatta
module.exports = JsonYatta

View File

@@ -1,2 +0,0 @@
(function(){var t,e,n,o;o=require("../Types/JsonTypes"),e=require("../HistoryBuffer"),t=require("../Engine"),n=function(){function n(n,r){var i,s;this.HB=new e(n),s=o(this.HB),this.types=s.types,this.engine=new t(this.HB,s.parser),this.connector=new r(this.engine,this.HB,s.execution_listener,this),i=new this.types.JsonType(this.HB.getReservedUniqueIdentifier()),this.HB.addOperation(i).execute(),this.root_element=i}return n.prototype.getSharedObject=function(){return this.root_element},n.prototype.getEngine=function(){return this.engine},n.prototype.getConnector=function(){return this.connector},n.prototype.getHistoryBuffer=function(){return this.HB},n.prototype.setMutableDefault=function(t){return this.root_element.setMutableDefault(t)},n.prototype.getUserId=function(){return this.HB.getUserId()},n.prototype.toJson=function(){return this.root_element.toJson()},n.prototype.val=function(t,e,n){return this.root_element.val(t,e,n)},n.prototype.on=function(){var t;return(t=this.root_element).on.apply(t,arguments)},n.prototype.deleteListener=function(){var t;return(t=this.root_element).deleteListener.apply(t,arguments)},Object.defineProperty(n.prototype,"value",{get:function(){return this.root_element.value},set:function(t){var e,n,o;if(t.constructor==={}.constructor){o=[];for(e in t)n=t[e],o.push(this.val(e,n,"immutable"));return o}throw new Error("You must only set Object values!")}}),n}(),module.exports=n,"undefined"!=typeof window&&null!==window&&(null==window.Y&&(window.Y={}),window.Y.JsonYatta=n)}).call(this);
//# sourceMappingURL=../Frameworks/JsonYatta.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Frameworks/JsonYatta.js","sources":["Frameworks/JsonYatta.coffee"],"names":[],"mappings":"CACA,WAAA,GAAA,GAAA,EAAA,EAAA,CAAA,GAA2B,QAAQ,sBACnC,EAAgB,QAAQ,oBACxB,EAAS,QAAQ,aASX,EAAA,WAMS,QAAA,GAAC,EAAS,GACrB,GAAA,GAAA,CAAA,MAAC,GAAS,GAAA,GAAc,GACxB,EAAe,EAAyB,KAAC,IACzC,KAAC,MAAQ,EAAa,MACtB,KAAC,OAAa,GAAA,GAAO,KAAC,GAAI,EAAa,QACvC,KAAC,UAAgB,GAAA,GAAU,KAAC,OAAQ,KAAC,GAAI,EAAa,mBAAoB,MAE1E,EAAiB,GAAA,MAAC,MAAM,SAAS,KAAC,GAAG,+BACrC,KAAC,GAAG,aAAa,GAAY,UAC7B,KAAC,aAAe,QATlB,GAAA,UAcA,gBAAiB,iBACf,MAAC,cAfH,EAAA,UAoBA,UAAW,iBACT,MAAC,QArBH,EAAA,UA0BA,aAAc,iBACZ,MAAC,WA3BH,EAAA,UAgCA,iBAAkB,iBAChB,MAAC,IAjCH,EAAA,UAsCA,kBAAmB,SAAC,SAClB,MAAC,aAAa,kBAAkB,IAvClC,EAAA,UA8CA,UAAW,iBACT,MAAC,GAAG,aA/CN,EAAA,UAoDA,OAAS,iBACP,MAAC,aAAa,UArDhB,EAAA,UA0DA,IAAM,SAAC,EAAM,EAAS,SACpB,MAAC,aAAa,IAAI,EAAM,EAAS,IA3DnC,EAAA,UA6DA,GAAI,WACF,GAAA,UAAA,EAAA,KAAC,cAAa,GAAd,MAAA,EAAiB,YA9DnB,EAAA,UAgEA,eAAgB,WACd,GAAA,UAAA,EAAA,KAAC,cAAa,eAAd,MAAA,EAA6B,YAK/B,OAAO,eAAe,EAAU,UAAW,SACzC,IAAM,iBAAG,MAAC,aAAa,OACvB,IAAM,SAAC,GACL,GAAA,GAAA,EAAA,CAAA,IAAG,EAAE,iBAAkB,YAAvB,CACE,SAAA,IAAA,UACE,EAAA,KAAA,KAAC,IAAI,EAAQ,EAAO,uBAEtB,KAAU,IAAA,OAAM,4CAExB,OAAO,QAAU,EACd,mBAAA,SAAA,OAAA,SACM,MAAA,OAAA,IACL,OAAO,MACT,OAAO,EAAE,UAAY","sourcesContent":["\njson_types_uninitialized = require \"../Types/JsonTypes\"\nHistoryBuffer = require \"../HistoryBuffer\"\nEngine = require \"../Engine\"\n\n#\n# Framework for Json data-structures.\n# Known values that are supported:\n# * String\n# * Integer\n# * Array\n#\nclass JsonYatta\n\n #\n # @param {String} user_id Unique id of the peer.\n # @param {Connector} Connector the connector class.\n #\n constructor: (user_id, Connector)->\n @HB = new HistoryBuffer user_id\n type_manager = json_types_uninitialized @HB\n @types = type_manager.types\n @engine = new Engine @HB, type_manager.parser\n @connector = new Connector @engine, @HB, type_manager.execution_listener, @\n\n first_word = new @types.JsonType @HB.getReservedUniqueIdentifier()\n @HB.addOperation(first_word).execute()\n @root_element = first_word\n\n #\n # @result JsonType\n #\n getSharedObject: ()->\n @root_element\n\n #\n # @see Engine\n #\n getEngine: ()->\n @engine\n\n #\n # Get the initialized connector.\n #\n getConnector: ()->\n @connector\n\n #\n # @see HistoryBuffer\n #\n getHistoryBuffer: ()->\n @HB\n\n #\n # @see JsonType.setMutableDefault\n #\n setMutableDefault: (mutable)->\n @root_element.setMutableDefault(mutable)\n\n #\n # Get the UserId from the HistoryBuffer object.\n # In most cases this will be the same as the user_id value with which\n # JsonYatta was initialized (Depending on the HistoryBuffer implementation).\n #\n getUserId: ()->\n @HB.getUserId()\n\n #\n # @see JsonType.toJson\n #\n toJson : ()->\n @root_element.toJson()\n\n #\n # @see JsonType.val\n #\n val : (name, content, mutable)->\n @root_element.val(name, content, mutable)\n\n on: ()->\n @root_element.on arguments...\n\n deleteListener: ()->\n @root_element.deleteListener arguments...\n\n #\n # @see JsonType.value\n #\n Object.defineProperty JsonYatta.prototype, 'value',\n get : -> @root_element.value\n set : (o)->\n if o.constructor is {}.constructor\n for o_name,o_obj of o\n @val(o_name, o_obj, 'immutable')\n else\n throw new Error \"You must only set Object values!\"\n\nmodule.exports = JsonYatta\nif window?\n if not window.Y?\n window.Y = {}\n window.Y.JsonYatta = JsonYatta\n"],"sourceRoot":"/source/"}

View File

@@ -0,0 +1,111 @@
(function() {
var Engine, HistoryBuffer, TextFramework, text_types_uninitialized;
text_types_uninitialized = require("../Types/TextTypes");
HistoryBuffer = require("../HistoryBuffer");
Engine = require("../Engine");
TextFramework = (function() {
function TextFramework(user_id, Connector) {
var beg, beginning, end, first_word, text_types, uid_beg, uid_end, uid_r;
this.HB = new HistoryBuffer(user_id);
text_types = text_types_uninitialized(this.HB);
this.types = text_types.types;
this.engine = new Engine(this.HB, text_types.parser);
this.connector = new Connector(this.engine, this.HB, text_types.execution_listener, this);
beginning = this.HB.addOperation(new this.types.Delimiter({
creator: '_',
op_number: '_beginning'
}, void 0, void 0));
end = this.HB.addOperation(new this.types.Delimiter({
creator: '_',
op_number: '_end'
}, beginning, void 0));
beginning.next_cl = end;
beginning.execute();
end.execute();
first_word = new this.types.WordType({
creator: '_',
op_number: '_'
}, beginning, end);
this.HB.addOperation(first_word).execute();
uid_r = {
creator: '_',
op_number: "RM"
};
uid_beg = {
creator: '_',
op_number: "_RM_beginning"
};
uid_end = {
creator: '_',
op_number: "_RM_end"
};
beg = this.HB.addOperation(new this.types.Delimiter(uid_beg, void 0, uid_end)).execute();
end = this.HB.addOperation(new this.types.Delimiter(uid_end, beg, void 0)).execute();
this.root_element = this.HB.addOperation(new this.types.ReplaceManager(void 0, uid_r, beg, end)).execute();
this.root_element.replace(first_word, {
creator: '_',
op_number: 'Replaceable'
});
}
TextFramework.prototype.getSharedObject = function() {
return this.root_element.val();
};
TextFramework.prototype.getConnector = function() {
return this.connector;
};
TextFramework.prototype.getHistoryBuffer = function() {
return this.HB;
};
TextFramework.prototype.getUserId = function() {
return this.HB.getUserId();
};
TextFramework.prototype.val = function() {
return this.getSharedObject().val();
};
TextFramework.prototype.insertText = function(pos, content) {
return this.getSharedObject().insertText(pos, content);
};
TextFramework.prototype.deleteText = function(pos, length) {
return this.getSharedObject().deleteText(pos, length);
};
TextFramework.prototype.bind = function(textarea) {
return this.getSharedObject().bind(textarea);
};
TextFramework.prototype.replaceText = function(text) {
return this.getSharedObject().replaceText(text);
};
TextFramework.prototype.on = function() {
var _ref;
return (_ref = this.root_element).on.apply(_ref, arguments);
};
return TextFramework;
})();
module.exports = TextFramework;
if (typeof window !== "undefined" && window !== null) {
if (window.Y == null) {
window.Y = {};
}
window.Y.TextFramework = TextFramework;
}
}).call(this);
//# sourceMappingURL=../Frameworks/TextFramework.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,82 +0,0 @@
text_types_uninitialized = require "../Types/TextTypes"
HistoryBuffer = require "../HistoryBuffer"
Engine = require "../Engine"
#
# Framework for Text Datastructures.
#
class TextYatta
#
# @param {String} user_id Uniqe user id that defines this peer.
# @param {Connector} Connector The connector defines how you connect to the other peers.
#
constructor: (user_id, Connector)->
@HB = new HistoryBuffer user_id
text_types = text_types_uninitialized @HB
@engine = new Engine @HB, text_types.parser
@connector = new Connector @engine, @HB, text_types.execution_listener
first_word = new text_types.types.Word undefined
@HB.addOperation(first_word).execute()
@root_element = first_word
#
# @result Word
#
getSharedObject: ()->
@root_element
#
# @see Engine
#
getEngine: ()->
@engine
#
# Get the initialized connector.
#
getConnector: ()->
@connector
#
# @see HistoryBuffer
#
getHistoryBuffer: ()->
@HB
#
# Get the UserId from the HistoryBuffer object.
# In most cases this will be the same as the user_id value with which
# JsonYatta was initialized (Depending on the HistoryBuffer implementation).
#
getUserId: ()->
@HB.getUserId()
#
# @see JsonType.val
#
val: ()->
@root_element.val()
#
# @see Word.insertText
#
insertText: (pos, content)->
@root_element.insertText pos, content
#
# @see Word.deleteText
#
deleteText: (pos, length)->
@root_element.deleteText pos, length
#
# @see Word.replaceText
#
replaceText: (text)->
@root_element.replaceText text
module.exports = TextYatta

View File

@@ -1,2 +0,0 @@
(function(){var e,t,n,r;r=require("../Types/TextTypes"),t=require("../HistoryBuffer"),e=require("../Engine"),n=function(){function n(n,i){var o,p,s,u,c,a,d,h;this.HB=new t(n),c=r(this.HB),this.types=c.types,this.engine=new e(this.HB,c.parser),this.connector=new i(this.engine,this.HB,c.execution_listener,this),p=this.HB.addOperation(new this.types.Delimiter({creator:"_",op_number:"_beginning"},void 0,void 0)),s=this.HB.addOperation(new this.types.Delimiter({creator:"_",op_number:"_end"},p,void 0)),p.next_cl=s,p.execute(),s.execute(),u=new this.types.Word({creator:"_",op_number:"_"},p,s),this.HB.addOperation(u).execute(),h={creator:"_",op_number:"RM"},a={creator:"_",op_number:"_RM_beginning"},d={creator:"_",op_number:"_RM_end"},o=this.HB.addOperation(new this.types.Delimiter(a,void 0,d)).execute(),s=this.HB.addOperation(new this.types.Delimiter(d,o,void 0)).execute(),this.root_element=this.HB.addOperation(new this.types.ReplaceManager(void 0,h,o,s)).execute(),this.root_element.replace(u,{creator:"_",op_number:"Replaceable"})}return n.prototype.getSharedObject=function(){return this.root_element.val()},n.prototype.getEngine=function(){return this.engine},n.prototype.getConnector=function(){return this.connector},n.prototype.getHistoryBuffer=function(){return this.HB},n.prototype.getUserId=function(){return this.HB.getUserId()},n.prototype.val=function(){return this.getSharedObject().val()},n.prototype.insertText=function(e,t){return this.getSharedObject().insertText(e,t)},n.prototype.deleteText=function(e,t){return this.getSharedObject().deleteText(e,t)},n.prototype.bind=function(e){return this.getSharedObject().bind(e)},n.prototype.replaceText=function(e){return this.getSharedObject().replaceText(e)},n.prototype.on=function(){var e;return(e=this.root_element).on.apply(e,arguments)},n}(),module.exports=n,"undefined"!=typeof window&&null!==window&&(null==window.Y&&(window.Y={}),window.Y.TextYatta=n)}).call(this);
//# sourceMappingURL=../Frameworks/TextYatta.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Frameworks/TextYatta.js","sources":["Frameworks/TextYatta.coffee"],"names":[],"mappings":"CACA,WAAA,GAAA,GAAA,EAAA,EAAA,CAAA,GAA2B,QAAQ,sBACnC,EAAgB,QAAQ,oBACxB,EAAS,QAAQ,aAKX,EAAA,WAMS,QAAA,GAAC,EAAS,GACrB,GAAA,GAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAA,MAAC,GAAS,GAAA,GAAc,GACxB,EAAa,EAAyB,KAAC,IACvC,KAAC,MAAQ,EAAW,MACpB,KAAC,OAAa,GAAA,GAAO,KAAC,GAAI,EAAW,QACrC,KAAC,UAAgB,GAAA,GAAU,KAAC,OAAQ,KAAC,GAAI,EAAW,mBAAoB,MAExE,EAAY,KAAC,GAAG,aAAiB,GAAA,MAAC,MAAM,WAAW,QAAS,IAAK,UAAW,cAAgB,OAAW,SACvG,EAAY,KAAC,GAAG,aAAiB,GAAA,MAAC,MAAM,WAAW,QAAS,IAAK,UAAW,QAAgB,EAAW,SACvG,EAAU,QAAU,EACpB,EAAU,UACV,EAAI,UACJ,EAAiB,GAAA,MAAC,MAAM,MAAM,QAAS,IAAK,UAAW,KAAM,EAAW,GACxE,KAAC,GAAG,aAAa,GAAY,UAE7B,GAAU,QAAS,IAAK,UAAW,MACnC,GAAY,QAAS,IAAK,UAAW,iBACrC,GAAY,QAAS,IAAK,UAAW,WACrC,EAAM,KAAC,GAAG,aAAiB,GAAA,MAAC,MAAM,UAAU,EAAS,OAAW,IAAS,UACzE,EAAM,KAAC,GAAG,aAAiB,GAAA,MAAC,MAAM,UAAU,EAAS,EAAK,SAAW,UACrE,KAAC,aAAe,KAAC,GAAG,aAAiB,GAAA,MAAC,MAAM,eAAe,OAAW,EAAO,EAAK,IAAK,UACvF,KAAC,aAAa,QAAQ,GAAc,QAAS,IAAK,UAAW,sBArB/D,GAAA,UA2BA,gBAAiB,iBACf,MAAC,aAAa,OA5BhB,EAAA,UAiCA,UAAW,iBACT,MAAC,QAlCH,EAAA,UAuCA,aAAc,iBACZ,MAAC,WAxCH,EAAA,UA6CA,iBAAkB,iBAChB,MAAC,IA9CH,EAAA,UAqDA,UAAW,iBACT,MAAC,GAAG,aAtDN,EAAA,UA2DA,IAAK,iBACH,MAAC,kBAAkB,OA5DrB,EAAA,UAiEA,WAAY,SAAC,EAAK,SAChB,MAAC,kBAAkB,WAAW,EAAK,IAlErC,EAAA,UAuEA,WAAY,SAAC,EAAK,SAChB,MAAC,kBAAkB,WAAW,EAAK,IAxErC,EAAA,UA6EA,KAAM,SAAC,SACL,MAAC,kBAAkB,KAAK,IA9E1B,EAAA,UAmFA,YAAa,SAAC,SACZ,MAAC,kBAAkB,YAAY,IApFjC,EAAA,UAsFA,GAAI,WACF,GAAA,UAAA,EAAA,KAAC,cAAa,GAAd,MAAA,EAAiB,iBAGrB,OAAO,QAAU,EACd,mBAAA,SAAA,OAAA,SACM,MAAA,OAAA,IACL,OAAO,MACT,OAAO,EAAE,UAAY","sourcesContent":["\ntext_types_uninitialized = require \"../Types/TextTypes\"\nHistoryBuffer = require \"../HistoryBuffer\"\nEngine = require \"../Engine\"\n\n#\n# Framework for Text Datastructures.\n#\nclass TextYatta\n\n #\n # @param {String} user_id Uniqe user id that defines this peer.\n # @param {Connector} Connector The connector defines how you connect to the other peers.\n #\n constructor: (user_id, Connector)->\n @HB = new HistoryBuffer user_id\n text_types = text_types_uninitialized @HB\n @types = text_types.types\n @engine = new Engine @HB, text_types.parser\n @connector = new Connector @engine, @HB, text_types.execution_listener, @\n\n beginning = @HB.addOperation new @types.Delimiter {creator: '_', op_number: '_beginning'} , undefined, undefined\n end = @HB.addOperation new @types.Delimiter {creator: '_', op_number: '_end'} , beginning, undefined\n beginning.next_cl = end\n beginning.execute()\n end.execute()\n first_word = new @types.Word {creator: '_', op_number: '_'}, beginning, end\n @HB.addOperation(first_word).execute()\n\n uid_r = { creator: '_', op_number: \"RM\" }\n uid_beg = { creator: '_', op_number: \"_RM_beginning\" }\n uid_end = { creator: '_', op_number: \"_RM_end\" }\n beg = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()\n end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()\n @root_element = @HB.addOperation(new @types.ReplaceManager undefined, uid_r, beg, end).execute()\n @root_element.replace first_word, { creator: '_', op_number: 'Replaceable'}\n\n\n #\n # @result Word\n #\n getSharedObject: ()->\n @root_element.val()\n\n #\n # @see Engine\n #\n getEngine: ()->\n @engine\n\n #\n # Get the initialized connector.\n #\n getConnector: ()->\n @connector\n\n #\n # @see HistoryBuffer\n #\n getHistoryBuffer: ()->\n @HB\n\n #\n # Get the UserId from the HistoryBuffer object.\n # In most cases this will be the same as the user_id value with which\n # JsonYatta was initialized (Depending on the HistoryBuffer implementation).\n #\n getUserId: ()->\n @HB.getUserId()\n\n #\n # @see JsonType.val\n #\n val: ()->\n @getSharedObject().val()\n\n #\n # @see Word.insertText\n #\n insertText: (pos, content)->\n @getSharedObject().insertText pos, content\n\n #\n # @see Word.deleteText\n #\n deleteText: (pos, length)->\n @getSharedObject().deleteText pos, length\n\n #\n # @see Word.bind\n #\n bind: (textarea)->\n @getSharedObject().bind textarea\n\n #\n # @see Word.replaceText\n #\n replaceText: (text)->\n @getSharedObject().replaceText text\n\n on: ()->\n @root_element.on arguments...\n\n\nmodule.exports = TextYatta\nif window?\n if not window.Y?\n window.Y = {}\n window.Y.TextYatta = TextYatta\n"],"sourceRoot":"/source/"}

View File

@@ -1,123 +0,0 @@
#
# An object that holds all applied operations.
#
# @note The HistoryBuffer is commonly abbreviated to HB.
#
class HistoryBuffer
#
# Creates an empty HB.
# @param {Object} user_id Creator of the HB.
#
constructor: (@user_id)->
@operation_counter = {}
@buffer = {}
@change_listeners = []
#
# Get the user id with wich the History Buffer was initialized.
#
getUserId: ()->
@user_id
#
# There is only one reserved unique identifier (uid), so use it wisely.
# I propose to use it in your Framework, to create something like a root element.
# An operation with this identifier is not propagated to other clients.
# This is why everybode must create the same operation with this uid.
#
getReservedUniqueIdentifier: ()->
{
creator : '_'
op_number : '_'
}
#
# Get the operation counter that describes the current state of the document.
#
getOperationCounter: ()->
res = {}
for user,ctn of @operation_counter
res[user] = ctn
res
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: (state_vector={})->
json = []
unknown = (user, o_number)->
if (not user?) or (not o_number?)
throw new Error "dah!"
not state_vector[user]? or state_vector[user] <= o_number
for u_name,user of @buffer
for o_number,o of user
if not isNaN(parseInt(o_number)) and unknown(u_name, o_number)
o_json = o._encode()
if o.next_cl?
o_next = o.next_cl
while o_next.next_cl? and unknown(o_next.creator, o_next.op_number)
o_next = o_next.next_cl
o_json.next = o_next.getUid()
else if o.prev_cl?
o_prev = o.prev_cl
while o_prev.prev_cl? and unknown(o_next.creator, o_next.op_number)
o_prev = o_prev.prev_cl
o_json.prev = o_prev.getUid()
json.push o_json
json
#
# Get the number of operations that were created by a user.
# Accordingly you will get the next operation number that is expected from that user.
# This will increment the operation counter.
#
getNextOperationIdentifier: (user_id)->
if not user_id?
user_id = @user_id
if not @operation_counter[user_id]?
@operation_counter[user_id] = 0
uid =
'creator' : user_id
'op_number' : @operation_counter[user_id]
@operation_counter[user_id]++
uid
#
# Retrieve an operation from a unique id.
#
getOperation: (uid)->
if uid instanceof Object
@buffer[uid.creator]?[uid.op_number]
else if not uid?
else
throw new Error "This type of uid is not defined!"
#
# Add an operation to the HB. Note that this will not link it against
# other operations (it wont executed)
#
addOperation: (o)->
if not @buffer[o.creator]?
@buffer[o.creator] = {}
if @buffer[o.creator][o.op_number]?
throw new Error "You must not overwrite operations!"
@buffer[o.creator][o.op_number] = o
o
#
# Increment the operation_counter that defines the current state of the Engine.
#
addToCounter: (o)->
if not @operation_counter[o.creator]?
@operation_counter[o.creator] = 0
if typeof o.op_number is 'number' and o.creator isnt @getUserId()
@operation_counter[o.creator]++
#if @operation_counter[o.creator] isnt (o.op_number + 1)
#console.log (@operation_counter[o.creator] - (o.op_number + 1))
#console.log o
#throw new Error "You don't receive operations in the proper order. Try counting like this 0,1,2,3,4,.. ;)"
module.exports = HistoryBuffer

View File

@@ -1,2 +1,139 @@
(function(){var r;r=function(){function r(r){this.user_id=r,this.operation_counter={},this.buffer={},this.change_listeners=[]}return r.prototype.getUserId=function(){return this.user_id},r.prototype.getReservedUniqueIdentifier=function(){return{creator:"_",op_number:"_"}},r.prototype.getOperationCounter=function(){var r,t,e,o;t={},o=this.operation_counter;for(e in o)r=o[e],t[e]=r;return t},r.prototype._encode=function(r){var t,e,o,n,i,u,c,p,a,f;null==r&&(r={}),t=[],p=function(t,e){if(null==t||null==e)throw new Error("dah!");return null==r[t]||r[t]<=e},f=this.buffer;for(c in f){a=f[c];for(i in a)if(e=a[i],!isNaN(parseInt(i))&&p(c,i)){if(o=e._encode(),null!=e.next_cl){for(n=e.next_cl;null!=n.next_cl&&p(n.creator,n.op_number);)n=n.next_cl;o.next=n.getUid()}else if(null!=e.prev_cl){for(u=e.prev_cl;null!=u.prev_cl&&p(u.creator,u.op_number);)u=u.prev_cl;o.prev=u.getUid()}t.push(o)}}return t},r.prototype.getNextOperationIdentifier=function(r){var t;return null==r&&(r=this.user_id),null==this.operation_counter[r]&&(this.operation_counter[r]=0),t={creator:r,op_number:this.operation_counter[r]},this.operation_counter[r]++,t},r.prototype.getOperation=function(r){var t;if(r instanceof Object)return null!=(t=this.buffer[r.creator])?t[r.op_number]:void 0;if(null!=r)throw new Error("This type of uid is not defined!")},r.prototype.addOperation=function(r){if(null==this.buffer[r.creator]&&(this.buffer[r.creator]={}),null!=this.buffer[r.creator][r.op_number])throw new Error("You must not overwrite operations!");return this.buffer[r.creator][r.op_number]=r,r},r.prototype.addToCounter=function(r){var t;if(null==this.operation_counter[r.creator]&&(this.operation_counter[r.creator]=0),"number"==typeof r.op_number&&r.creator!==this.getUserId()&&r.op_number===this.operation_counter[r.creator]){for(this.operation_counter[r.creator]++,t=[];null!=this.getOperation({creator:r.creator,op_number:this.operation_counter[r.creator]});)t.push(this.operation_counter[r.creator]++);return t}},r}(),module.exports=r}).call(this);
(function() {
var HistoryBuffer;
HistoryBuffer = (function() {
function HistoryBuffer(user_id) {
this.user_id = user_id;
this.operation_counter = {};
this.buffer = {};
this.change_listeners = [];
}
HistoryBuffer.prototype.getUserId = function() {
return this.user_id;
};
HistoryBuffer.prototype.getReservedUniqueIdentifier = function() {
return {
creator: '_',
op_number: '_'
};
};
HistoryBuffer.prototype.getOperationCounter = function() {
var ctn, res, user, _ref;
res = {};
_ref = this.operation_counter;
for (user in _ref) {
ctn = _ref[user];
res[user] = ctn;
}
return res;
};
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 ((!isNaN(parseInt(o_number))) && 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.creator, o_next.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.creator, o_prev.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]
};
this.operation_counter[user_id]++;
return uid;
};
HistoryBuffer.prototype.getOperation = function(uid) {
var _ref;
if (uid instanceof Object) {
return (_ref = this.buffer[uid.creator]) != null ? _ref[uid.op_number] : void 0;
} else if (uid == null) {
} else {
throw new Error("This type of uid is not defined!");
}
};
HistoryBuffer.prototype.addOperation = function(o) {
if (this.buffer[o.creator] == null) {
this.buffer[o.creator] = {};
}
if (this.buffer[o.creator][o.op_number] != null) {
throw new Error("You must not overwrite operations!");
}
this.buffer[o.creator][o.op_number] = o;
return o;
};
HistoryBuffer.prototype.addToCounter = function(o) {
var _results;
if (this.operation_counter[o.creator] == null) {
this.operation_counter[o.creator] = 0;
}
if (typeof o.op_number === 'number' && o.creator !== this.getUserId()) {
if (o.op_number === this.operation_counter[o.creator]) {
this.operation_counter[o.creator]++;
_results = [];
while (this.getOperation({
creator: o.creator,
op_number: this.operation_counter[o.creator]
}) != null) {
_results.push(this.operation_counter[o.creator]++);
}
return _results;
}
}
};
return HistoryBuffer;
})();
module.exports = HistoryBuffer;
}).call(this);
//# sourceMappingURL=HistoryBuffer.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,439 +0,0 @@
module.exports = (HB)->
# @see Engine.parse
parser = {}
execution_listener = []
#
# A generic interface to operations.
#
# An operation has the following methods:
# _encode: encodes an operation (needed only if instance of this operation is sent).
# execute: execute the effects of this operations. Good examples are Insert-type and AddName-type
# val: in the case that the operation holds a value
#
# Furthermore an encodable operation has a parser.
#
class Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @see HistoryBuffer.getNextOperationIdentifier
#
constructor: (uid)->
if not uid?
uid = HB.getNextOperationIdentifier()
{
'creator': @creator
'op_number' : @op_number
} = uid
#
# Add an event listener. It depends on the operation which events are supported.
# @param {String} event Name of the event.
# @param {Function} f f is executed in case the event fires.
#
on: (event, f)->
@event_listeners ?= {}
@event_listeners[event] ?= []
@event_listeners[event].push f
#
# Fire an event.
# TODO: Do something with timeouts. You don't want this to fire for every operation (e.g. insert).
#
callEvent: (event, args)->
if @event_listeners[event]?
for f in @event_listeners[event]
f.call @, event, args
#
# Set the parent of this operation.
#
setParent: (o)->
@parent = o
#
# Computes a unique identifier (uid) that identifies this operation.
#
getUid: ()->
{ 'creator': @creator, 'op_number': @op_number }
#
# @private
# Notify the all the listeners.
#
execute: ()->
@is_executed = true
for l in execution_listener
l @_encode()
@
#
# @private
# Operations may depend on other operations (linked lists, etc.).
# The saveOperation and validateSavedOperations methods provide
# an easy way to refer to these operations via an uid or object reference.
#
# For example: We can create a new Delete operation that deletes the operation $o like this
# - var d = new Delete(uid, $o); or
# - var d = new Delete(uid, $o.getUid());
# Either way we want to access $o via d.deletes. In the second case validateSavedOperations must be called first.
#
# @overload saveOperation(name, op_uid)
# @param {String} name The name of the operation. After validating (with validateSavedOperations) the instantiated operation will be accessible via this[name].
# @param {Object} op_uid A uid that refers to an operation
# @overload saveOperation(name, op)
# @param {String} name The name of the operation. After calling this function op is accessible via this[name].
# @param {Operation} op An Operation object
#
saveOperation: (name, op)->
#
# Every instance of $Operation must have an $execute function.
# We use duck-typing to check if op is instantiated since there
# could exist multiple classes of $Operation
#
if op?.execute?
# is instantiated
@[name] = op
else if op?
# not initialized. Do it when calling $validateSavedOperations()
@unchecked ?= {}
@unchecked[name] = op
#
# @private
# After calling this function all not instantiated operations will be accessible.
# @see Operation.saveOperation
#
# @return [Boolean] Whether it was possible to instantiate all operations.
#
validateSavedOperations: ()->
uninstantiated = {}
success = @
for name, op_uid of @unchecked
op = HB.getOperation op_uid
if op
@[name] = op
else
uninstantiated[name] = op_uid
success = false
delete @unchecked
if not success
@unchecked = uninstantiated
success
#
# A simple Delete-type operation that deletes an Insert-type operation.
#
class Delete extends Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Object} deletes UID or reference of the operation that this to be deleted.
#
constructor: (uid, deletes)->
@saveOperation 'deletes', deletes
super uid
#
# @private
# Convert all relevant information of this operation to the json-format.
# This result can be sent to other clients.
#
_encode: ()->
{
'type': "Delete"
'uid': @getUid()
'deletes': @deletes.getUid()
}
#
# @private
# Apply the deletion.
#
execute: ()->
if @validateSavedOperations()
@deletes.applyDelete @
super
@
else
false
#
# Define how to parse Delete operations.
#
parser['Delete'] = (o)->
{
'uid' : uid
'deletes': deletes_uid
} = o
new Delete uid, deletes_uid
#
# A simple insert-type operation.
#
# An insert operation is always positioned between two other insert operations.
# Internally this is realized as associative lists, whereby each insert operation has a predecessor and a successor.
# For the sake of efficiency we maintain two lists:
# - The short-list (abbrev. sl) maintains only the operations that are not deleted
# - The complete-list (abbrev. cl) maintains all operations
#
class Insert extends Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Operation} prev_cl The predecessor of this operation in the complete-list (cl)
# @param {Operation} next_cl The successor of this operation in the complete-list (cl)
#
# @see HistoryBuffer.getNextOperationIdentifier
#
constructor: (uid, prev_cl, next_cl, origin)->
@saveOperation 'prev_cl', prev_cl
@saveOperation 'next_cl', next_cl
if origin?
@saveOperation 'origin', origin
else
@saveOperation 'origin', prev_cl
super uid
#
# @private
#
applyDelete: (o)->
@deleted_by ?= []
@deleted_by.push o
#
# If isDeleted() is true this operation won't be maintained in the sl
#
isDeleted: ()->
@deleted_by?.length > 0
#
# @private
# The amount of positions that $this operation was moved to the right.
#
getDistanceToOrigin: ()->
d = 0
o = @prev_cl
while true
if @origin is o
break
d++
#TODO: delete this
if @ is @prev_cl
throw new Error "this should not happen ;) "
o = o.prev_cl
d
#
# @private
# Update the short list
# TODO (Unused)
update_sl: ()->
o = @prev_cl
update: (dest_cl,dest_sl)->
while true
if o.isDeleted()
o = o[dest_cl]
else
@[dest_sl] = o
break
update "prev_cl", "prev_sl"
update "next_cl", "prev_sl"
#
# @private
# Include this operation in the associative lists.
#
execute: ()->
if @is_executed?
return @
if not @validateSavedOperations()
return false
else
if @prev_cl?.validateSavedOperations() and @next_cl?.validateSavedOperations() and @prev_cl.next_cl isnt @
distance_to_origin = 0
o = @prev_cl.next_cl
i = 0
# $this has to find a unique position between origin and the next known character
# case 1: $origin equals $o.origin: the $creator parameter decides if left or right
# let $OL= [o1,o2,o3,o4], whereby $this is to be inserted between o1 and o4
# o2,o3 and o4 origin is 1 (the position of o2)
# there is the case that $this.creator < o2.creator, but o3.creator < $this.creator
# then o2 knows o3. Since on another client $OL could be [o1,o3,o4] the problem is complex
# 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)
# case 3: $origin > $o.origin
# $this insert_position is to the left of $o (forever!)
while true
if not o?
# TODO: Debugging
console.log JSON.stringify @prev_cl.getUid()
console.log JSON.stringify @next_cl.getUid()
if o isnt @next_cl
# $o happened concurrently
if o.getDistanceToOrigin() is i
# case 1
if o.creator < @creator
@prev_cl = o
distance_to_origin = i + 1
else
# nop
else if o.getDistanceToOrigin() < i
# case 2
if i - distance_to_origin <= o.getDistanceToOrigin()
@prev_cl = o
distance_to_origin = i + 1
else
#nop
else
# case 3
break
i++
o = o.next_cl
else
# $this knows that $o exists,
break
# now reconnect everything
@next_cl = @prev_cl.next_cl
@prev_cl.next_cl = @
@next_cl.prev_cl = @
super # notify the execution_listeners
@
#
# Defines an object that is cannot be changed. You can use this to set an immutable string, or a number.
#
class ImmutableObject extends Insert
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Object} content
#
constructor: (uid, @content, prev, next, origin)->
super uid, prev, next, origin
#
# @return [String] The content of this operation.
#
val : ()->
@content
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: ()->
json = {
'type': "ImmutableObject"
'uid' : @getUid()
'content' : @content
}
if @prev_cl?
json['prev'] = @prev_cl.getUid()
if @next_cl?
json['next'] = @next_cl.getUid()
if @origin? and @origin isnt @prev_cl
json["origin"] = @origin.getUid()
json
parser['ImmutableObject'] = (json)->
{
'uid' : uid
'content' : content
'prev': prev
'next': next
'origin' : origin
} = json
new ImmutableObject uid, content, prev, next, origin
#
# A delimiter is placed at the end and at the beginning of the associative lists.
# This is necessary in order to have a beginning and an end even if the content
# of the Engine is empty.
#
class Delimiter extends Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Operation} prev_cl The predecessor of this operation in the complete-list (cl)
# @param {Operation} next_cl The successor of this operation in the complete-list (cl)
#
# @see HistoryBuffer.getNextOperationIdentifier
#
constructor: (uid, prev_cl, next_cl, origin)->
@saveOperation 'prev_cl', prev_cl
@saveOperation 'next_cl', next_cl
@saveOperation 'origin', prev_cl
super uid
#
# If isDeleted() is true this operation won't be maintained in the sl
#
isDeleted: ()->
false
#
# @private
#
execute: ()->
if @unchecked?['next_cl']?
super
else if @unchecked?['prev_cl']
if @validateSavedOperations()
if @prev_cl.next_cl?
throw new Error "Probably duplicated operations"
@prev_cl.next_cl = @
delete @prev_cl.unchecked.next_cl
super
else
false
else if @prev_cl? and not @prev_cl.next_cl?
delete @prev_cl.unchecked.next_cl
@prev_cl.next_cl = @
else if @prev_cl? or @next_cl?
super
else
throw new Error "Delimiter is unsufficient defined!"
#
# @private
#
_encode: ()->
{
'type' : "Delimiter"
'uid' : @getUid()
'prev' : @prev_cl?.getUid()
'next' : @next_cl?.getUid()
}
parser['Delimiter'] = (json)->
{
'uid' : uid
'prev' : prev
'next' : next
} = json
new Delimiter uid, prev, next
# This is what this module exports after initializing it with the HistoryBuffer
{
'types' :
'Delete' : Delete
'Insert' : Insert
'Delimiter': Delimiter
'Operation': Operation
'ImmutableObject' : ImmutableObject
'parser' : parser
'execution_listener' : execution_listener
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,210 +0,0 @@
text_types_uninitialized = require "./TextTypes"
module.exports = (HB)->
text_types = text_types_uninitialized HB
types = text_types.types
parser = text_types.parser
createJsonWrapper = (_jsonType)->
#
# A JsonWrapper was intended to be a convenient wrapper for the JsonType.
# But it can make things more difficult than they are.
# @see JsonType
#
# @example create a JsonWrapper
# # You get a JsonWrapper from a JsonType by calling
# w = yatta.value
#
# It creates Javascripts -getter and -setter methods for each property that JsonType maintains.
# @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
#
# @example Getter Example
# # you can access the x property of yatta by calling
# w.x
# # instead of
# yatta.val('x')
#
# @note You can only overwrite existing values! Setting a new property won't have any effect!
#
# @example Setter Example
# # you can set an existing x property of yatta by calling
# w.x = "text"
# # instead of
# yatta.val('x', "text")
#
# In order to set a new property you have to overwrite an existing property.
# Therefore the JsonWrapper supports a special feature that should make things more convenient
# (we can argue about that, use the JsonType if you don't like it ;).
# If you overwrite an object property of the JsonWrapper with a new object, it will result in a merged version of the objects.
# Let w.p the property that is to be overwritten and o the new value. E.g. w.p = o
# * The result has all properties of o
# * The result has all properties of w.p if they don't occur under the same property-name in o.
#
# @example Conflict Example
# yatta.value = {a : "string"}
# w = yatta.value
# console.log(w) # {a : "string"}
# w.a = {a : {b : "string"}}
# console.log(w) # {a : {b : "String"}}
# w.a = {a : {c : 4}}
# console.log(w) # {a : {b : "String", c : 4}}
#
# @example Common Pitfalls
# w = yatta.value
# # Setting a new property
# w.newProperty = "Awesome"
# console.log(w.newProperty == "Awesome") # false, w.newProperty is undefined
# # overwrite the w object
# w = {newProperty : "Awesome"}
# console.log(w.newProperty == "Awesome") # true!, but ..
# console.log(yatta.value.newProperty == "Awesome") # false, you are only allowed to set properties!
# # The solution
# yatta.value = {newProperty : "Awesome"}
# console.log(w.newProperty == "Awesome") # true!
#
class JsonWrapper
#
# @param {JsonType} jsonType Instance of the JsonType that this class wrappes.
#
constructor: (jsonType)->
for name, obj of jsonType.map
do (name, obj)->
Object.defineProperty JsonWrapper.prototype, name,
get : ->
x = obj.val()
if x instanceof JsonType
createJsonWrapper x
else if x instanceof types.ImmutableObject
x.val()
else
x
set : (o)->
if o.constructor is {}.constructor
overwrite = jsonType.val(name)
for o_name,o_obj of o
overwrite.val(o_name, o_obj, 'immutable')
else
jsonType.val(name, o, 'immutable')
enumerable: true
configurable: false
new JsonWrapper _jsonType
#
# Manages Object-like values.
#
class JsonType extends types.MapManager
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Object} initial_value Create this operation with an initial value.
# @param {String|Boolean} Whether the initial_value should be created as mutable. (Optional - see setMutableDefault)
#
constructor: (uid, initial_value, mutable)->
super uid
if initial_value?
if typeof initial_value isnt "object"
throw new Error "The initial value of JsonTypes must be of type Object! (current type: #{typeof initial_value})"
for name,o of initial_value
@val name, o, mutable
#
# Whether the default is 'mutable' (true) or 'immutable' (false)
#
mutable_default:
true
#
# Set if the default is 'mutable' or 'immutable'
# @param {String|Boolean} mutable Set either 'mutable' / true or 'immutable' / false
setMutableDefault: (mutable)->
if mutable is true or mutable is 'mutable'
JsonType.prototype.mutable_default = true
else if mutable is false or mutable is 'immutable'
JsonType.prototype.mutable_default = false
else
throw new Error 'Set mutable either "mutable" or "immutable"!'
'OK'
#
# @overload val()
# Get this as a Json object.
# @return [Json]
#
# @overload val(name)
# Get value of a property.
# @param {String} name Name of the object property.
# @return [JsonType|Word|String|Object] Depending on the value of the property. If mutable it will return a Operation-type object, if immutable it will return String/Object.
#
# @overload val(name, content)
# Set a new property.
# @param {String} name Name of the object property.
# @param {Object|String} content Content of the object property.
# @return [JsonType] This object. (supports chaining)
#
val: (name, content, mutable)->
if typeof name is 'object'
# Special case. First argument is an object. Then the second arg is mutable.
# Keep that in mind when reading the following..
for o_name,o of name
@val(o_name,o,content)
@
else if name? and content?
if mutable?
if mutable is true or mutable is 'mutable'
mutable = true
else
mutable = false
else
mutable = @mutable_default
if typeof content is 'function'
@ # Just do nothing
else if ((not mutable) or typeof content is 'number') and content.constructor isnt Object
obj = HB.addOperation(new types.ImmutableObject undefined, content).execute()
super name, obj
else
if typeof content is 'string'
word = HB.addOperation(new types.Word undefined).execute()
word.insertText 0, content
super name, word
else if content.constructor is Object
json = HB.addOperation(new JsonType undefined, content, mutable).execute()
super name, json
else
throw new Error "You must not set #{typeof content}-types in collaborative Json-objects!"
else
super name, content
Object.defineProperty JsonType.prototype, 'value',
get : -> createJsonWrapper @
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!"
#
# @private
#
_encode: ()->
{
'type' : "JsonType"
'uid' : @getUid()
}
parser['JsonType'] = (json)->
{
'uid' : uid
} = json
new JsonType uid
types['JsonType'] = JsonType
text_types

View File

@@ -1,2 +1,206 @@
(function(){var t,e={}.hasOwnProperty,r=function(t,r){function n(){this.constructor=t}for(var o in r)e.call(r,o)&&(t[o]=r[o]);return n.prototype=r.prototype,t.prototype=new n,t.__super__=r.prototype,t},n=[].slice;t=require("./TextTypes"),module.exports=function(e){var o,u,a,i,c;return i=t(e),c=i.types,a=i.parser,u=function(t){var e;return new(e=function(){function t(e){var r,n,a,i;i=e.map,a=function(r,n){return Object.defineProperty(t.prototype,r,{get:function(){var t;return t=n.val(),t instanceof o?u(t):t instanceof c.ImmutableObject?t.val():t},set:function(t){var n,o,u,a;if(u=e.val(r),t.constructor==={}.constructor&&u instanceof c.Operation){a=[];for(n in t)o=t[n],a.push(u.val(n,o,"immutable"));return a}return e.val(r,t,"immutable")},enumerable:!0,configurable:!1})};for(r in i)n=i[r],a(r,n)}return t}())(t)},o=function(t){function o(t,e,r){var n,u;if(o.__super__.constructor.call(this,t),null!=e){if("object"!=typeof e)throw new Error("The initial value of JsonTypes must be of type Object! (current type: "+typeof e+")");for(n in e)u=e[n],this.val(n,u,r)}}return r(o,t),o.prototype.toJson=function(){var t,e,r,n;n=this.val(),t={};for(e in n)if(r=n[e],r.constructor==={}.constructor)t[e]=this.val(e).toJson();else if(r instanceof c.Operation){for(;r instanceof c.Operation;)r=r.val();t[e]=r}else t[e]=r;return t},o.prototype.setReplaceManager=function(t){return this.parent=t.parent,this.on(["change","addProperty"],function(){var e;return(e=t.parent).forwardEvent.apply(e,[this].concat(n.call(arguments)))})},o.prototype.getParent=function(){return this.parent},o.prototype.mutable_default=!0,o.prototype.setMutableDefault=function(t){if(t===!0||"mutable"===t)o.prototype.mutable_default=!0;else{if(t!==!1&&"immutable"!==t)throw new Error('Set mutable either "mutable" or "immutable"!');o.prototype.mutable_default=!1}return"OK"},o.prototype.val=function(t,r,n){var u,a,i,l,p;if("object"==typeof t){for(i in t)a=t[i],this.val(i,a,r);return this}if(null!=t&&null!=r){if(n=null!=n?n===!0||"mutable"===n?!0:!1:this.mutable_default,"function"==typeof r)return this;if(n&&"number"!=typeof r||r.constructor===Object){if("string"==typeof r)return p=e.addOperation(new c.Word(void 0)).execute(),p.insertText(0,r),o.__super__.val.call(this,t,p);if(r.constructor===Object)return u=e.addOperation(new o(void 0,r,n)).execute(),o.__super__.val.call(this,t,u);throw new Error("You must not set "+typeof r+"-types in collaborative Json-objects!")}return l=e.addOperation(new c.ImmutableObject(void 0,r)).execute(),o.__super__.val.call(this,t,l)}return o.__super__.val.call(this,t,r)},Object.defineProperty(o.prototype,"value",{get:function(){return u(this)},set:function(t){var e,r,n;if(t.constructor==={}.constructor){n=[];for(e in t)r=t[e],n.push(this.val(e,r,"immutable"));return n}throw new Error("You must only set Object values!")}}),o.prototype._encode=function(){return{type:"JsonType",uid:this.getUid()}},o}(c.MapManager),a.JsonType=function(t){var e;return e=t.uid,new o(e)},c.JsonType=o,i}}).call(this);
(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; },
__slice = [].slice;
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(uid, initial_value, mutable) {
var name, o;
JsonType.__super__.constructor.call(this, uid);
if (initial_value != null) {
if (typeof initial_value !== "object") {
throw new Error("The initial value of JsonTypes must be of type Object! (current type: " + (typeof initial_value) + ")");
}
for (name in initial_value) {
o = initial_value[name];
this.val(name, o, mutable);
}
}
}
JsonType.prototype.type = "JsonType";
JsonType.prototype.toJson = function() {
var json, name, o, val;
val = this.val();
json = {};
for (name in val) {
o = val[name];
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;
}
}
return json;
};
JsonType.prototype.setReplaceManager = function(rm) {
this.parent = rm.parent;
return this.on(['change', 'addProperty'], function() {
var _ref;
return (_ref = rm.parent).forwardEvent.apply(_ref, [this].concat(__slice.call(arguments)));
});
};
JsonType.prototype.getParent = function() {
return this.parent;
};
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, o, o_name, obj, word;
if (typeof name === 'object') {
for (o_name in name) {
o = name[o_name];
this.val(o_name, o, content);
}
return this;
} else if ((name != null) && (content != null)) {
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 (((!mutable) || typeof content === 'number') && content.constructor !== Object) {
obj = HB.addOperation(new types.ImmutableObject(void 0, content)).execute();
return JsonType.__super__.val.call(this, name, obj);
} else {
if (typeof content === 'string') {
word = HB.addOperation(new types.WordType(void 0)).execute();
word.insertText(0, content);
return JsonType.__super__.val.call(this, name, word);
} else if (content.constructor === Object) {
json = HB.addOperation(new JsonType(void 0, content, mutable)).execute();
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

@@ -1,310 +0,0 @@
basic_types_uninitialized = require "./BasicTypes"
module.exports = (HB)->
basic_types = basic_types_uninitialized HB
types = basic_types.types
parser = basic_types.parser
#
# Manages map like objects. E.g. Json-Type and XML attributes.
#
class MapManager extends types.Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
#
constructor: (uid)->
@map = {}
super uid
#
# @see JsonTypes.val
#
val: (name, content)->
if content?
if not @map[name]?
HB.addOperation(new AddName undefined, @, name).execute()
@map[name].replace content
@
else if name?
obj = @map[name]?.val()
if obj instanceof types.ImmutableObject
obj.val()
else
obj
else
result = {}
for name,o of @map
obj = o.val()
if obj instanceof types.ImmutableObject or obj instanceof MapManager
obj = obj.val()
result[name] = obj
result
#
# When a new property in a map manager is created, then the uids of the inserted Operations
# must be unique (think about concurrent operations). Therefore only an AddName operation is allowed to
# add a property in a MapManager. If two AddName operations on the same MapManager name happen concurrently
# only one will AddName operation will be executed.
#
class AddName extends types.Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Object} map_manager Uid or reference to the MapManager.
# @param {String} name Name of the property that will be added.
#
constructor: (uid, map_manager, @name)->
@saveOperation 'map_manager', map_manager
super uid
#
# If map_manager doesn't have the property name, then add it.
# The ReplaceManager that is being written on the property is unique
# in such a way that if AddName is executed (from another peer) it will
# always have the same result (ReplaceManager, and its beginning and end are the same)
#
execute: ()->
if not @validateSavedOperations()
return false
else
uid_r = @map_manager.getUid()
uid_r.op_number = "_#{uid_r.op_number}_RM_#{@name}"
if not HB.getOperation(uid_r)?
uid_beg = @map_manager.getUid()
uid_beg.op_number = "_#{uid_beg.op_number}_RM_#{@name}_beginning"
uid_end = @map_manager.getUid()
uid_end.op_number = "_#{uid_end.op_number}_RM_#{@name}_end"
beg = HB.addOperation(new types.Delimiter uid_beg, undefined, uid_end).execute()
end = HB.addOperation(new types.Delimiter uid_end, beg, undefined).execute()
#beg.execute()
@map_manager.map[@name] = HB.addOperation(new ReplaceManager undefined, uid_r, beg, end).execute()
super
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: ()->
{
'type' : "AddName"
'uid' : @getUid()
'map_manager' : @map_manager.getUid()
'name' : @name
}
parser['AddName'] = (json)->
{
'map_manager' : map_manager
'uid' : uid
'name' : name
} = json
new AddName uid, map_manager, name
#
# Manages a list of Insert-type operations.
#
class ListManager extends types.Insert
#
# A ListManager maintains a non-empty list that has a beginning and an end (both Delimiters!)
# @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)->
if beginning? and end?
@saveOperation 'beginning', beginning
@saveOperation 'end', end
else
@beginning = HB.addOperation new types.Delimiter undefined, undefined, undefined
@end = HB.addOperation new types.Delimiter undefined, @beginning, undefined
@beginning.next_cl = @end
@beginning.execute()
@end.execute()
super uid, prev, next, origin
# Get the element previous to the delemiter at the end
getLastOperation: ()->
@end.prev_cl
# similar to the above
getFirstOperation: ()->
@beginning.next_cl
# Transforms the the list to an array
# Doesn't return left-right delimiter.
toArray: ()->
o = @beginning.next_cl
result = []
while o isnt @end
result.push o
o = o.next_cl
result
#
# Retrieves the x-th not deleted element.
#
getOperationByPosition: (position)->
o = @beginning.next_cl
if position > 0
while true
o = o.next_cl
if not o.isDeleted()
position -= 1
if position is 0
break
if o instanceof types.Delimiter
throw new Error "position parameter exceeded the length of the document!"
o
#
# Adds support for replace. The ReplaceManager manages Replaceable operations.
# Each Replaceable holds a value that is now replaceable.
#
# The Word-type has implemented support for replace
# @see Word
#
class ReplaceManager extends ListManager
#
# @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: (initial_content, uid, beginning, end, prev, next, origin)->
super uid, beginning, end, prev, next, origin
if initial_content?
@replace initial_content
#
# Replace the existing word with a new word.
#
replace: (content)->
o = @getLastOperation()
op = new Replaceable content, @, undefined, o, o.next_cl
HB.addOperation(op).execute()
#
# Get the value of this Word
# @return {String}
#
val: ()->
o = @getLastOperation()
if o instanceof types.Delimiter
throw new Error "dtrn"
o.val()
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: ()->
json =
{
'type': "ReplaceManager"
'uid' : @getUid()
'beginning' : @beginning.getUid()
'end' : @end.getUid()
}
if @prev_cl? and @next_cl?
json['prev'] = @prev_cl.getUid()
json['next'] = @next_cl.getUid()
if @origin? and @origin isnt @prev_cl
json["origin"] = @origin.getUid()
json
parser["ReplaceManager"] = (json)->
{
'content' : content
'uid' : uid
'prev': prev
'next': next
'origin' : origin
'beginning' : beginning
'end' : end
} = json
new ReplaceManager content, uid, beginning, end, prev, next, origin
#
# The ReplaceManager manages Replaceables.
# @see ReplaceManager
#
class Replaceable extends types.Insert
#
# @param {Operation} content The value that this Replaceable holds.
# @param {ReplaceManager} parent Used to replace this Replaceable with another one.
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
#
constructor: (content, parent, uid, prev, next, origin)->
@saveOperation 'content', content
@saveOperation 'parent', parent
if not (prev? and next? and content?)
throw new Error "You must define content, prev, and next for Replaceable-types!"
super uid, prev, next, origin
#
# Return the content that this operation holds.
#
val: ()->
@content
#
# Replace the content of this replaceable with new content.
#
replace: (content)->
@parent.replace content
#
# If possible set the replace manager in the content.
# @see Word.setReplaceManager
#
execute: ()->
if not @validateSavedOperations()
return false
else
@content.setReplaceManager?(@parent)
super
@
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: ()->
json =
{
'type': "Replaceable"
'content': @content.getUid()
'ReplaceManager' : @parent.getUid()
'prev': @prev_cl.getUid()
'next': @next_cl.getUid()
'uid' : @getUid()
}
if @origin? and @origin isnt @prev_cl
json["origin"] = @origin.getUid()
json
parser["Replaceable"] = (json)->
{
'content' : content
'ReplaceManager' : parent
'uid' : uid
'prev': prev
'next': next
'origin' : origin
} = json
new Replaceable content, parent, uid, prev, next, origin
types['ListManager'] = ListManager
types['MapManager'] = MapManager
types['ReplaceManager'] = ReplaceManager
types['Replaceable'] = Replaceable
basic_types

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,177 +0,0 @@
structured_types_uninitialized = require "./StructuredTypes"
module.exports = (HB)->
structured_types = structured_types_uninitialized HB
types = structured_types.types
parser = structured_types.parser
#
# At the moment TextDelete type equals the Delete type in BasicTypes.
# @see BasicTypes.Delete
#
class TextDelete extends types.Delete
parser["TextDelete"] = parser["Delete"]
#
# Extends the basic Insert type to an operation that holds a text value
#
class TextInsert extends types.Insert
#
# @param {String} content The content of this Insert-type Operation. Usually you restrict the length of content to size 1
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
#
constructor: (@content, uid, prev, next, origin)->
if not (prev? and next?)
throw new Error "You must define prev, and next for TextInsert-types!"
super uid, prev, next, origin
#
# Retrieve the effective length of the $content of this operation.
#
getLength: ()->
if @isDeleted()
0
else
@content.length
#
# The result will be concatenated with the results from the other insert operations
# in order to retrieve the content of the engine.
# @see HistoryBuffer.toExecutedArray
#
val: (current_position)->
if @isDeleted()
""
else
@content
#
# Convert all relevant information of this operation to the json-format.
# This result can be send to other clients.
#
_encode: ()->
json =
{
'type': "TextInsert"
'content': @content
'uid' : @getUid()
'prev': @prev_cl.getUid()
'next': @next_cl.getUid()
}
if @origin? and @origin isnt @prev_cl
json["origin"] = @origin.getUid()
json
parser["TextInsert"] = (json)->
{
'content' : content
'uid' : uid
'prev': prev
'next': next
'origin' : origin
} = json
new TextInsert content, uid, prev, next, origin
#
# Handles a Text-like data structures with support for insertText/deleteText at a word-position.
#
class Word extends types.ListManager
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
#
constructor: (uid, beginning, end, prev, next, origin)->
super uid, beginning, end, prev, next, origin
#
# Inserts a string into the word
#
insertText: (position, content)->
o = @getOperationByPosition position
for c in content
op = new TextInsert c, undefined, o.prev_cl, o
HB.addOperation(op).execute()
#
# Deletes a part of the word.
#
deleteText: (position, length)->
o = @getOperationByPosition position
for i in [0...length]
d = HB.addOperation(new TextDelete undefined, o).execute()
o = o.next_cl
while o.isDeleted()
if o instanceof types.Delimiter
throw new Error "You can't delete more than there is.."
o = o.next_cl
d._encode()
#
# Replace the content of this word with another one. Concurrent replacements are not merged!
# Only one of the replacements will be used.
#
# Can only be used if the ReplaceManager was set!
# @see Word.setReplaceManager
#
replaceText: (text)->
if @replace_manager?
word = HB.addOperation(new Word undefined).execute()
word.insertText 0, text
@replace_manager.replace(word)
else
throw new Error "This type is currently not maintained by a ReplaceManager!"
#
# @returns [Json] A Json object.
#
val: ()->
c = for o in @toArray()
if o.val?
o.val()
else
""
c.join('')
#
# In most cases you would embed a Word in a Replaceable, wich is handled by the ReplaceManager in order
# to provide replace functionality.
#
setReplaceManager: (op)->
@saveOperation 'replace_manager', op
@validateSavedOperations
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: ()->
json = {
'type': "Word"
'uid' : @getUid()
'beginning' : @beginning.getUid()
'end' : @end.getUid()
}
if @prev_cl?
json['prev'] = @prev_cl.getUid()
if @next_cl?
json['next'] = @next_cl.getUid()
if @origin? and @origin isnt @prev_cl
json["origin"] = @origin.getUid()
json
parser['Word'] = (json)->
{
'uid' : uid
'beginning' : beginning
'end' : end
'prev': prev
'next': next
'origin' : origin
} = json
new Word uid, beginning, end, prev, next, origin
types['TextInsert'] = TextInsert
types['TextDelete'] = TextDelete
types['Word'] = Word
structured_types

View File

@@ -1,2 +1,303 @@
(function(){var e,t={}.hasOwnProperty,n=function(e,n){function r(){this.constructor=e}for(var i in n)t.call(n,i)&&(e[i]=n[i]);return r.prototype=n.prototype,e.prototype=new r,e.__super__=n.prototype,e};e=require("./StructuredTypes"),module.exports=function(t){var r,i,o,l,u,s;return u=e(t),s=u.types,l=u.parser,r=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return n(t,e),t}(s.Delete),l.TextDelete=l.Delete,i=function(e){function t(e,n,r,i,o){if(this.content=e,null==r||null==i)throw new Error("You must define prev, and next for TextInsert-types!");t.__super__.constructor.call(this,n,r,i,o)}return n(t,e),t.prototype.getLength=function(){return this.isDeleted()?0:this.content.length},t.prototype.val=function(){return this.isDeleted()?"":this.content},t.prototype._encode=function(){var e;return e={type:"TextInsert",content:this.content,uid:this.getUid(),prev:this.prev_cl.getUid(),next:this.next_cl.getUid()},null!=this.origin&&this.origin!==this.prev_cl&&(e.origin=this.origin.getUid()),e},t}(s.Insert),l.TextInsert=function(e){var t,n,r,o,l;return t=e.content,l=e.uid,o=e.prev,n=e.next,r=e.origin,new i(t,l,o,n,r)},o=function(e){function o(e,t,n,r,i,l){o.__super__.constructor.call(this,e,t,n,r,i,l)}return n(o,e),o.prototype.insertText=function(e,n){var r,o,l,u,s,a;for(o=this.getOperationByPosition(e),a=[],u=0,s=n.length;s>u;u++)r=n[u],l=new i(r,void 0,o.prev_cl,o),a.push(t.addOperation(l).execute());return a},o.prototype.deleteText=function(e,n){var i,o,l,u,a;for(u=this.getOperationByPosition(e),o=[],l=a=0;(n>=0?n>a:a>n)&&!(u instanceof s.Delimiter);l=n>=0?++a:--a){for(i=t.addOperation(new r(void 0,u)).execute(),u=u.next_cl;!(u instanceof s.Delimiter)&&u.isDeleted();)u=u.next_cl;o.push(i._encode())}return o},o.prototype.replaceText=function(e){var n;if(null!=this.replace_manager)return n=t.addOperation(new o(void 0)).execute(),n.insertText(0,e),this.replace_manager.replace(n);throw new Error("This type is currently not maintained by a ReplaceManager!")},o.prototype.val=function(){var e,t;return e=function(){var e,n,r,i;for(r=this.toArray(),i=[],e=0,n=r.length;n>e;e++)t=r[e],i.push(null!=t.val?t.val():"");return i}.call(this),e.join("")},o.prototype.setReplaceManager=function(e){return this.saveOperation("replace_manager",e),this.validateSavedOperations(),this.on(["insert","delete"],function(e){return function(){var t;return null!=(t=e.replace_manager)?t.callEvent("change"):void 0}}(this))},o.prototype.bind=function(e){var t;return t=this,e.value=this.val(),this.on("insert",function(n,r){var i,o,l,u;return l=r.getPosition(),i=function(e){return l>=e?e:e+=1},o=i(e.selectionStart),u=i(e.selectionEnd),e.value=t.val(),e.setSelectionRange(o,u)}),this.on("delete",function(n,r){var i,o,l,u;return l=r.getPosition(),i=function(e){return l>e?e:e-=1},o=i(e.selectionStart),u=i(e.selectionEnd),e.value=t.val(),e.setSelectionRange(o,u)}),e.onkeypress=function(n){var r,i,o,l;return r=null,r=null!=n.key?32===n.charCode?" ":13===n.keyCode?"\n":n.key:String.fromCharCode(n.keyCode),r.length>0?(l=Math.min(e.selectionStart,e.selectionEnd),i=Math.abs(e.selectionEnd-e.selectionStart),t.deleteText(l,i),t.insertText(l,r),o=l+r.length,e.setSelectionRange(o,o),n.preventDefault()):n.preventDefault()},e.onpaste=function(e){return e.preventDefault()},e.oncut=function(e){return e.preventDefault()},e.onkeydown=function(n){var r,i,o,l,u;if(l=Math.min(e.selectionStart,e.selectionEnd),i=Math.abs(e.selectionEnd-e.selectionStart),null!=n.keyCode&&8===n.keyCode){if(i>0)t.deleteText(l,i),e.setSelectionRange(l,l);else if(null!=n.ctrlKey&&n.ctrlKey){for(u=e.value,o=l,r=0,l>0&&(o--,r++);o>0&&" "!==u[o]&&"\n"!==u[o];)o--,r++;t.deleteText(o,l-o),e.setSelectionRange(o,o)}else t.deleteText(l-1,1);return n.preventDefault()}return null!=n.keyCode&&46===n.keyCode?(i>0?(t.deleteText(l,i),e.setSelectionRange(l,l)):(t.deleteText(l,1),e.setSelectionRange(l,l)),n.preventDefault()):void 0}},o.prototype._encode=function(){var e;return e={type:"Word",uid:this.getUid(),beginning:this.beginning.getUid(),end:this.end.getUid()},null!=this.prev_cl&&(e.prev=this.prev_cl.getUid()),null!=this.next_cl&&(e.next=this.next_cl.getUid()),null!=this.origin&&this.origin!==this.prev_cl&&(e.origin=this.origin.getUid()),e},o}(s.ListManager),l.Word=function(e){var t,n,r,i,l,u;return u=e.uid,t=e.beginning,n=e.end,l=e.prev,r=e.next,i=e.origin,new o(u,t,n,l,r,i)},s.TextInsert=i,s.TextDelete=r,s.Word=o,u}}).call(this);
(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) {
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.getLength = function() {
if (this.isDeleted()) {
return 0;
} else {
return this.content.length;
}
};
TextInsert.prototype.val = function(current_position) {
if (this.isDeleted()) {
return "";
} else {
return this.content;
}
};
TextInsert.prototype._encode = function() {
var json;
json = {
'type': "TextInsert",
'content': this.content,
'uid': this.getUid(),
'prev': this.prev_cl.getUid(),
'next': this.next_cl.getUid()
};
if ((this.origin != null) && 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.insertText = function(position, content) {
var c, o, op, _i, _len;
o = this.getOperationByPosition(position);
for (_i = 0, _len = content.length; _i < _len; _i++) {
c = content[_i];
op = new TextInsert(c, void 0, o.prev_cl, o);
HB.addOperation(op).execute();
}
return this;
};
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 = HB.addOperation(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.replaceText = function(text) {
var word;
if (this.replace_manager != null) {
word = HB.addOperation(new WordType(void 0)).execute();
word.insertText(0, text);
this.replace_manager.replace(word);
return word;
} else {
throw new Error("This type is currently not maintained by a ReplaceManager!");
}
};
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.setReplaceManager = function(op) {
this.saveOperation('replace_manager', op);
this.validateSavedOperations();
return this.on(['insert', 'delete'], (function(_this) {
return function() {
var _ref;
return (_ref = _this.replace_manager) != null ? _ref.callEvent('change') : void 0;
};
})(this));
};
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) && this.origin !== this.prev_cl) {
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

@@ -1,2 +1,6 @@
(function(){}).call(this);
(function() {
}).call(this);
//# sourceMappingURL=../Types/XmlTypes.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"Types/XmlTypes.js","sources":["Types/XmlTypes.coffee"],"names":[],"mappings":"CA4GgC","sourcesContent":[""],"sourceRoot":"/source/"}
{"version":3,"sources":["Types/XmlTypes.coffee"],"names":[],"mappings":"AAoGwC;AAAA;AAAA","file":"Types/XmlTypes.js","sourceRoot":"/source/","sourcesContent":[""]}

View File

@@ -1,10 +0,0 @@
exports['IwcConnector'] =
require './Connectors/IwcConnector'
exports['TestConnector'] =
require './Connectors/TestConnector'
exports['JsonYatta'] =
require './Frameworks/JsonYatta'
exports['TextYatta'] =
require './Frameworks/TextYatta'

View File

@@ -1,2 +1,12 @@
(function(){exports.IwcConnector=require("./Connectors/IwcConnector"),exports.TestConnector=require("./Connectors/TestConnector"),exports.JsonYatta=require("./Frameworks/JsonYatta"),exports.TextYatta=require("./Frameworks/TextYatta")}).call(this);
(function() {
exports['IwcConnector'] = require('./Connectors/IwcConnector');
exports['TestConnector'] = require('./Connectors/TestConnector');
exports['JsonFramework'] = require('./Frameworks/JsonFramework');
exports['TextFramework'] = require('./Frameworks/TextFramework');
}).call(this);
//# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sources":["index.coffee"],"names":[],"mappings":"CACA,WAAA,QAAQ,aACN,QAAQ,6BACV,QAAQ,cACN,QAAQ,8BACV,QAAQ,UACN,QAAQ,0BACV,QAAQ,UACN,QAAQ","sourcesContent":["\nexports['IwcConnector'] =\n require './Connectors/IwcConnector'\nexports['TestConnector'] =\n require './Connectors/TestConnector'\nexports['JsonYatta'] =\n require './Frameworks/JsonYatta'\nexports['TextYatta'] =\n require './Frameworks/TextYatta'\n\n"],"sourceRoot":"/source/"}
{"version":3,"sources":["index.coffee"],"names":[],"mappings":"AAEA;AAAA,EAAA,OAAQ,CAAA,cAAA,CAAR,GACE,OAAA,CAAQ,2BAAR,CADF,CAAA;;AAAA,EAEA,OAAQ,CAAA,eAAA,CAAR,GACE,OAAA,CAAQ,4BAAR,CAHF,CAAA;;AAAA,EAIA,OAAQ,CAAA,eAAA,CAAR,GACE,OAAA,CAAQ,4BAAR,CALF,CAAA;;AAAA,EAMA,OAAQ,CAAA,eAAA,CAAR,GACE,OAAA,CAAQ,4BAAR,CAPF,CAAA;AAAA","file":"index.js","sourceRoot":"/source/","sourcesContent":["\n\nexports['IwcConnector'] =\n require './Connectors/IwcConnector'\nexports['TestConnector'] =\n require './Connectors/TestConnector'\nexports['JsonFramework'] =\n require './Frameworks/JsonFramework'\nexports['TextFramework'] =\n require './Frameworks/TextFramework'\n\n"]}