fixes issue #1 and #2

This commit is contained in:
Kevin Jahns 2014-08-21 04:19:55 +02:00
parent 465a2f18e6
commit ad5898a77a
29 changed files with 323 additions and 77 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,4 +3,4 @@
},{}]},{},[1])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL2Rtb25hZC9Ecm9wYm94L1lhdHRhIS9ub2RlX21vZHVsZXMvZ3VscC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvaG9tZS9kbW9uYWQvRHJvcGJveC9ZYXR0YSEvbGliL1R5cGVzL1htbFR5cGVzLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpfXZhciBmPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChmLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGYsZi5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJcblxuLy8jIHNvdXJjZU1hcHBpbmdVUkw9ZGF0YTphcHBsaWNhdGlvbi9qc29uO2Jhc2U2NCxleUoyWlhKemFXOXVJam96TENKbWFXeGxJam9pTDJodmJXVXZaRzF2Ym1Ga0wwUnliM0JpYjNndldXRjBkR0VoTDJ4cFlpOVVlWEJsY3k5WWJXeFVlWEJsY3k1amIyWm1aV1VpTENKemIzVnlZMlZTYjI5MElqb2lJaXdpYzI5MWNtTmxjeUk2V3lJdmFHOXRaUzlrYlc5dVlXUXZSSEp2Y0dKdmVDOVpZWFIwWVNFdmJHbGlMMVI1Y0dWekwxaHRiRlI1Y0dWekxtTnZabVpsWlNKZExDSnVZVzFsY3lJNlcxMHNJbTFoY0hCcGJtZHpJam9pUVVGdlpFY2lMQ0p6YjNWeVkyVnpRMjl1ZEdWdWRDSTZXeUlpWFgwPSJdfQ==
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL2Rtb25hZC9Ecm9wYm94L1lhdHRhIS9ub2RlX21vZHVsZXMvZ3VscC1icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvaG9tZS9kbW9uYWQvRHJvcGJveC9ZYXR0YSEvbGliL1R5cGVzL1htbFR5cGVzLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpfXZhciBmPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChmLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGYsZi5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJcblxuLy8jIHNvdXJjZU1hcHBpbmdVUkw9ZGF0YTphcHBsaWNhdGlvbi9qc29uO2Jhc2U2NCxleUoyWlhKemFXOXVJam96TENKbWFXeGxJam9pTDJodmJXVXZaRzF2Ym1Ga0wwUnliM0JpYjNndldXRjBkR0VoTDJ4cFlpOVVlWEJsY3k5WWJXeFVlWEJsY3k1amIyWm1aV1VpTENKemIzVnlZMlZTYjI5MElqb2lJaXdpYzI5MWNtTmxjeUk2V3lJdmFHOXRaUzlrYlc5dVlXUXZSSEp2Y0dKdmVDOVpZWFIwWVNFdmJHbGlMMVI1Y0dWekwxaHRiRlI1Y0dWekxtTnZabVpsWlNKZExDSnVZVzFsY3lJNlcxMHNJbTFoY0hCcGJtZHpJam9pUVVFd1pFY2lMQ0p6YjNWeVkyVnpRMjl1ZEdWdWRDSTZXeUlpWFgwPSJdfQ==

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
(function(){var t,e={}.hasOwnProperty,r=function(t,r){function o(){this.constructor=t}for(var n in r)e.call(r,n)&&(t[n]=r[n]);return o.prototype=r.prototype,t.prototype=new o,t.__super__=r.prototype,t};t=require("./TextTypes"),module.exports=function(e){var o,n,u,i,a;return i=t(e),a=i.types,u=i.parser,n=function(t){var e;return new(e=function(){function t(e){var r,u,i,l;l=e.map,i=function(r,u){return Object.defineProperty(t.prototype,r,{get:function(){var t;return t=u.val(),t instanceof o?n(t):t instanceof a.ImmutableObject?t.val():t},set:function(t){var o,n,u,i;if(u=e.val(r),t.constructor==={}.constructor&&u instanceof a.Operation){i=[];for(o in t)n=t[o],i.push(u.val(o,n,"immutable"));return i}return e.val(r,t,"immutable")},enumerable:!0,configurable:!1})};for(r in l)u=l[r],i(r,u)}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,o;o=this.val(),t={};for(e in o)if(r=o[e],r.constructor==={}.constructor)t[e]=this.val(e).toJson();else if(r instanceof a.Operation){for(;r instanceof a.Operation;)r=r.val();t[e]=r}else t[e]=r;return t},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,i,l,c,s;if("object"==typeof t){for(l in t)i=t[l],this.val(l,i,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 s=e.addOperation(new a.Word(void 0)).execute(),s.insertText(0,r),o.__super__.val.call(this,t,s);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 c=e.addOperation(new a.ImmutableObject(void 0,r)).execute(),o.__super__.val.call(this,t,c)}return o.__super__.val.call(this,t,r)},Object.defineProperty(o.prototype,"value",{get:function(){return n(this)},set:function(t){var e,r,o;if(t.constructor==={}.constructor){o=[];for(e in t)r=t[e],o.push(this.val(e,r,"immutable"));return o}throw new Error("You must only set Object values!")}}),o.prototype._encode=function(){return{type:"JsonType",uid:this.getUid()}},o}(a.MapManager),u.JsonType=function(t){var e;return e=t.uid,new o(e)},a.JsonType=o,i}}).call(this);
(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);
//# sourceMappingURL=../Types/JsonTypes.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -125,6 +125,29 @@ Lists are always immutable.
```
### Check Types
Certainly you want to check types!
Here, we create a function that parses an Yatta type to a string.
You find all the types that Yatta provides in `yatta.types`.
```js
function show(o){
var t = yatta.types
if (o instanceof t.JsonType){
return JSON.stringify(o.toJson());
} else if (o instanceof t.Word) {
return o.val();
} else if (o.constructor === {}.constructor) { // It's an Object
return JSON.stringify(o);
} else { // It's a primitive data type (E.g. string, int)
return o;
}
}
```
### Add listeners
Apply a 'addProperty' - listener to a JsonType.
@ -132,6 +155,7 @@ Apply a 'addProperty' - listener to a JsonType.
```js
function addProperty(event_name, property_name){
console.log("Property '" + property_name + "' was created!");
console.log("Value: " + show(this.val(property_name))); // 'this' is the object on which the property was created.
};
yatta.on('addProperty', addProperty);
yatta.val('new', {z: 7}); // Property 'new' was created!
@ -143,19 +167,20 @@ Apply a 'change' - listener to a JsonType.
```js
function change(event_name, property_name){
console.log("Property '" + property_name + "' was replaced or changed!");
console.log("New value: \"" + this.val(property_name).val() + "\""); // 'this' is the new/created value
console.log("Value of property '" + property_name + "' changed!");
console.log("New value: " + show(this.val(property_name)) + ""); // 'this' is the object on which the property changed.
};
yatta.on('change', change);
yatta.val('mutable_string', "text", 'mutable'); // Property 'mutable_string' was replaced or changed!
```
Does not fire for nested properties.
'change' and 'addProperty' do also fire for nested properties.
```js
yatta.val('new').val('z', 8); // No output!
yatta.val('new').val('z', {'replace' : "x"}); // Property 'z' was replaced or changed!
yatta.val('new').val('z').val('new', {"true": true}); // Property 'z' was replaced or changed! + Property 'new' was created!
```

View File

@ -10,12 +10,12 @@
</head>
<body>
<h1> Text Editing Demo</h1>
<p> Collaborative text editing with <a href="https://github.com/DadaMonad/Yatta/">Yatta</a>
<p> Collaborative Json editing with <a href="https://github.com/DadaMonad/Yatta/">Yatta</a>
and <a href="http://peerjs.com/">PeerJs</a> (WebRTC). </p>
<p> <a href="https://github.com/DadaMonad/Yatta/">Yatta</a> is a Framework for Real-Time collaboration on arbitrary data structures.
You can find the code for this example <a href="https://github.com/DadaMonad/Yatta/tree/master/examples/TextEditing">here</a>.
You can find the code for this example <a href="https://github.com/DadaMonad/Yatta/tree/master/examples/PeerJs-Json">here</a>.
</p>
</body>
</html>

View File

@ -94,12 +94,33 @@ You can also specify your own user_id with peerjs. But you have to make sure tha
yatta.val('list', [1,2,3]);
console.log(yatta.val('list')[2] === 3); // true
/**
### Check Types
Certainly you want to check types!
Here, we create a function that parses an Yatta type to a string.
You find all the types that Yatta provides in `yatta.types`.
*/
function show(o){
var t = yatta.types
if (o instanceof t.JsonType){
return JSON.stringify(o.toJson());
} else if (o instanceof t.Word) {
return o.val();
} else if (o.constructor === {}.constructor) { // It's an Object
return JSON.stringify(o);
} else { // It's a primitive data type (E.g. string, int)
return o;
}
}
/**
### Add listeners
Apply a 'addProperty' - listener to a JsonType.
*/
function addProperty(event_name, property_name){
console.log("Property '" + property_name + "' was created!");
console.log("Value: " + show(this.val(property_name))); // 'this' is the object on which the property was created.
};
yatta.on('addProperty', addProperty);
yatta.val('new', {z: 7}); // Property 'new' was created!
@ -108,16 +129,17 @@ You can also specify your own user_id with peerjs. But you have to make sure tha
Apply a 'change' - listener to a JsonType.
*/
function change(event_name, property_name){
console.log("Property '" + property_name + "' was replaced or changed!");
console.log("New value: \"" + this.val(property_name).val() + "\""); // 'this' is the new/created value
console.log("Value of property '" + property_name + "' changed!");
console.log("New value: " + show(this.val(property_name)) + ""); // 'this' is the object on which the property changed.
};
yatta.on('change', change);
yatta.val('mutable_string', "text", 'mutable'); // Property 'mutable_string' was replaced or changed!
/**
Does not fire for nested properties.
'change' and 'addProperty' do also fire for nested properties.
*/
yatta.val('new').val('z', 8); // No output!
yatta.val('new').val('z', {'replace' : "x"}); // Property 'z' was replaced or changed!
yatta.val('new').val('z').val('new', {"true": true}); // Property 'z' was replaced or changed! + Property 'new' was created!
/**
Apply 'insert' and 'delete' - listeners to Words.

View File

@ -52,10 +52,16 @@ module.exports = (HB)->
# Fire an event.
# TODO: Do something with timeouts. You don't want this to fire for every operation (e.g. insert).
#
callEvent: (event, args...)->
callEvent: ()->
@forwardEvent @, arguments...
#
# Fire an event and specify in which context the listener is called (set 'this').
#
forwardEvent: (op, event, args...)->
if @event_listeners?[event]?
for f in @event_listeners[event]
f.call @, event, args...
f.call op, event, args...
#
# Set the parent of this operation.

View File

@ -127,6 +127,21 @@ module.exports = (HB)->
json[name] = o
json
#
# @see Word.setReplaceManager
# Sets the parent of this JsonType object.
#
setReplaceManager: (rm)->
@parent = rm.parent
@on ['change','addProperty'], ()->
rm.parent.forwardEvent this, arguments...
#
# Get the parent of this JsonType.
# @return {JsonType}
#
getParent: ()->
@parent
#
# Whether the default is 'mutable' (true) or 'immutable' (false)
#

View File

@ -80,7 +80,6 @@ module.exports = (HB)->
@map_manager.map[@name] = HB.addOperation(new ReplaceManager undefined, uid_r, beg, end)
@map_manager.map[@name].setParent @map_manager, @name
@map_manager.map[@name].execute()
@map_manager.callEvent 'addProperty', @name
super
#
@ -208,6 +207,12 @@ module.exports = (HB)->
@parent.callEvent 'change', property_name
@on 'change', (event)=>
@parent.callEvent 'change', property_name
# Call this, when the first element is inserted. Then delete the listener.
addPropertyListener = (event, op)=>
if op.next_cl instanceof types.Delimiter and op.prev_cl instanceof types.Delimiter
@parent.callEvent 'addProperty', property_name
@deleteListener 'addProperty', addPropertyListener
@on 'insert', addPropertyListener
super parent
#
# Get the value of this Word