Adding to HB is now handled by Operation.execute. engine changed. Currently fixing errors and working on memory menagement for large HB tables

This commit is contained in:
DadaMonad 2014-12-16 11:21:57 +00:00
parent 7696864841
commit 2cf899418a
64 changed files with 3013 additions and 10106 deletions

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 +0,0 @@
!function t(n,e,r){function i(u,a){if(!e[u]){if(!n[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(o)return o(u,!0);throw new Error("Cannot find module '"+u+"'")}var c=e[u]={exports:{}};n[u][0].call(c.exports,function(t){var e=n[u][1][t];return i(e?e:t)},c,c.exports,t,n,e,r)}return e[u].exports}for(var o="function"==typeof require&&require,u=0;u<r.length;u++)i(r[u]);return i}({1:[function(t,n){var e;e=function(t,n){var e,r,i,o,u,a;return a=null,null!=n&&(a=n.iwcHandler),o={},r=new DUIClient,r.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}),r.initOK(),u=null,e=function(){function t(t,n,e,i){var a,s,c,l;this.engine=t,this.HB=n,this.execution_listener=e,this.yatta=i,this.duiClient=r,this.iwcHandler=o,l=function(t){return function(n){return 0!==Object.getOwnPropertyNames(t.initialized).length?t.send(n):void 0}}(this),this.execution_listener.push(l),this.initialized={},a=function(t){return function(e){var r;return n=e.extras.HB,r=e.extras.user,t.engine.applyOpsCheckDouble(n),t.initialized[r]=!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),c=function(t){return function(n){var e,r;return r=n.extras,console.log(r),e={HB:t.yatta.getHistoryBuffer()._encode(r),user:t.yatta.getUserId()},t.sendIwcIntent("Yatta_push_HB_element",e)}}(this),this.iwcHandler.Yatta_get_HB_element=[c]}return t.prototype.setIwcHandler=function(t){return a=t},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.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}(),i=function(){var n;return n=Math.floor(1e6*Math.random()),t(e,n)},setTimeout(i,5e3),void 0},n.exports=e,"undefined"!=typeof window&&null!==window&&(null==window.Y&&(window.Y={}),window.Y.createIwcConnector=e)},{}]},{},[1]);

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
!function n(e,t,r){function o(s,u){if(!t[s]){if(!e[s]){var c="function"==typeof require&&require;if(!u&&c)return c(s,!0);if(i)return i(s,!0);throw new Error("Cannot find module '"+s+"'")}var a=t[s]={exports:{}};e[s][0].call(a.exports,function(n){var t=e[s][1][n];return o(t?t:n)},a,a.exports,n,e,t,r)}return t[s].exports}for(var i="function"==typeof require&&require,s=0;s<r.length;s++)o(r[s]);return o}({1:[function(n,e){var t;t=function(){var n,e,t;return t=null,2===arguments.length?(t=new Peer(arguments[0]),e=arguments[1]):(t=new Peer(arguments[0],arguments[1]),t.on("error",function(n){throw new Error("Peerjs connector: "+n)}),t.on("disconnected",function(){throw new Error("Peerjs connector disconnected from signalling server. Cannot accept new connections. Not fatal, but not so good either..")}),e=arguments[2]),n=function(){function n(n,e,r,o){var i,s;this.engine=n,this.HB=e,this.execution_listener=r,this.yatta=o,this.peer=t,this.connections={},this.new_connection_listeners=[],this.peer.on("connection",function(n){return function(e){return n.addConnection(e)}}(this)),s=function(n){return function(){var e,t,r,o;r=n.connections,o=[];for(t in r)e=r[t],o.push(e.send({sync_state_vector:n.HB.getOperationCounter()}));return o}}(this),setInterval(s,4e3),i=function(n){return function(e){var t,r,o,i;if(e.uid.creator===n.HB.getUserId()&&"string"!=typeof e.uid.op_number){o=n.connections,i=[];for(r in o)t=o[r],i.push(t.send({op:e}));return i}}}(this),this.execution_listener.push(i)}return n.prototype.connectToPeer=function(n){return null==this.connections[n]&&n!==this.yatta.getUserId()?this.addConnection(t.connect(n)):void 0},n.prototype.getAllConnectionIds=function(){var n,e;e=[];for(n in this.connections)e.push(n);return e},n.prototype.onNewConnection=function(n){return this.new_connection_listeners.push(n)},n.prototype.addConnection=function(n){var e,t,r;return this.connections[n.peer]=n,t=!1,e=!1,n.on("data",function(r){return function(o){var i,s,u,c,a;if("empty_message"===o);else if(null!=o.HB){if(t=!0,r.engine.applyOpsCheckDouble(o.HB),!o.initialized)return n.send({conns:r.getAllConnectionIds()}),r.new_connection_listeners.map(function(e){return e(n)})}else{if(null!=o.op)return r.engine.applyOp(o.op);if(null!=o.conns){for(c=o.conns,a=[],s=0,u=c.length;u>s;s++)i=c[s],a.push(r.connectToPeer(i));return a}if(null!=o.sync_state_vector)return n.send({HB:r.yatta.getHistoryBuffer()._encode(o.sync_state_vector),initialized:!0});if(null==o.state_vector)throw new Error("Can't parse this operation: "+o);if(!e)return n.send({HB:r.yatta.getHistoryBuffer()._encode(o.state_vector),initialized:!1}),e=!0}}}(this)),r=function(e){return function(){return n.send({state_vector:e.HB.getOperationCounter()}),t?void 0:setTimeout(r,100)}}(this),r()},n}(),t.on("open",function(t){return e(n,t)})},e.exports=t,"undefined"!=typeof window&&null!==window&&(null==window.Y&&(window.Y={}),window.Y.createPeerJsConnector=t)},{}]},{},[1]);

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

1950
build/browser/yatta.js Normal file

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

@ -13,7 +13,7 @@
mocha.ui('bdd');
mocha.reporter('html');
</script>
<script src="TextYatta_test.js"></script>
<!--script src="TextYatta_test.js"></script-->
<script src="JsonYatta_test.js"></script>
<!--script src="XmlYatta_test_browser.js"></script-->
<script>

View File

@ -35,11 +35,6 @@
<ul>
<li class='letter'>j</li>
<ul>
<li>
<a href='class/JsonFramework.html'>
JsonFramework
</a>
</li>
<li>
<a href='class/JsonTypeWrapper.html'>
JsonTypeWrapper
@ -52,16 +47,6 @@
</li>
</ul>
</ul>
<ul>
<li class='letter'>t</li>
<ul>
<li>
<a href='class/TextFramework.html'>
TextFramework
</a>
</li>
</ul>
</ul>
<ul>
<li class='letter'>w</li>
<ul>
@ -73,11 +58,11 @@
</ul>
</ul>
<ul>
<li class='letter'>x</li>
<li class='letter'>y</li>
<ul>
<li>
<a href='class/XmlFramework.html'>
XmlFramework
<a href='class/Yatta.html'>
Yatta
</a>
</li>
</ul>
@ -137,30 +122,9 @@
</li>
</ul>
</ul>
<ul>
<li class='letter'>i</li>
<ul>
<li>
<a href='file/lib/index.coffee.html'>
index.coffee
</a>
<small>
(lib)
</small>
</li>
</ul>
</ul>
<ul>
<li class='letter'>j</li>
<ul>
<li>
<a href='file/lib/Frameworks/JsonFramework.coffee.html'>
JsonFramework.coffee
</a>
<small>
(lib&#47;Frameworks)
</small>
</li>
<li>
<a href='file/lib/Types/JsonTypes.coffee.html'>
JsonTypes.coffee
@ -187,14 +151,6 @@
<ul>
<li class='letter'>t</li>
<ul>
<li>
<a href='file/lib/Frameworks/TextFramework.coffee.html'>
TextFramework.coffee
</a>
<small>
(lib&#47;Frameworks)
</small>
</li>
<li>
<a href='file/lib/Types/TextTypes.coffee.html'>
TextTypes.coffee
@ -206,14 +162,14 @@
</ul>
</ul>
<ul>
<li class='letter'>x</li>
<li class='letter'>y</li>
<ul>
<li>
<a href='file/lib/Frameworks/XmlFramework.coffee.html'>
XmlFramework.coffee
<a href='file/lib/Yatta.coffee.html'>
Yatta.coffee
</a>
<small>
(lib&#47;Frameworks)
(lib)
</small>
</li>
</ul>
@ -222,7 +178,7 @@
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -155,7 +155,7 @@ Known values that are supported:</p><ul>
<p class='signature' id='constructor-dynamic'>
#
(void)
<b>constructor</b><span>(user_id, connector)</span>
<b>constructor</b><span>(connector)</span>
<br>
</p>
<div class='tags'>
@ -335,7 +335,7 @@ JsonFramework was initialized (Depending on the HistoryBuffer implementation).</
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -467,7 +467,7 @@ Otherwise you will loose all the sharing-abilities (the new object will be a dee
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -139,7 +139,7 @@ console.log(w.newProperty == &quot;Awesome&quot;) # true!</code></pre>
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -356,7 +356,7 @@ JsonFramework was initialized (Depending on the HistoryBuffer implementation).</
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -455,7 +455,7 @@ yatta.bind(textbox);</code></pre>
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -303,7 +303,7 @@ JsonFramework was initialized (Depending on the HistoryBuffer implementation).</
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

409
doc/class/Yatta.html Normal file
View File

@ -0,0 +1,409 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Yatta! API</title>
<script src='../javascript/application.js'></script>
<script src='../javascript/search.js'></script>
<link rel='stylesheet' href='../stylesheets/application.css' type='text/css'>
</head>
<body>
<div id='base' data-path='../'></div>
<div id='header'>
<div id='menu'>
<a href='../extra/README.md.html' title='Yatta!'>
Yatta!
</a>
&raquo;
<a href='../alphabetical_index.html' title='Index'>
Index
</a>
&raquo;
<span class='title'>Yatta</span>
</div>
</div>
<div id='content'>
<h1>
Class:
Yatta
</h1>
<table class='box'>
<tr>
<td>Defined in:</td>
<td>lib&#47;Yatta.coffee</td>
</tr>
</table>
<h2>Overview</h2>
<div class='docstring'>
<p>Framework for Json data-structures.
Known values that are supported:</p><ul>
<li>String</li>
<li>Integer</li>
<li>Array</li>
</ul>
</div>
<div class='tags'>
</div>
<h2>Instance Method Summary</h2>
<ul class='summary'>
<li>
<span class='signature'>
<a href='#getSharedObject-dynamic'>
#
(?)
<b>getSharedObject</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#getConnector-dynamic'>
#
(void)
<b>getConnector</b><span>()</span>
</a>
</span>
<span class='desc'>
Get the initialized connector.
</span>
</li>
<li>
<span class='signature'>
<a href='#getHistoryBuffer-dynamic'>
#
(void)
<b>getHistoryBuffer</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#setMutableDefault-dynamic'>
#
(void)
<b>setMutableDefault</b><span>(mutable)</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#getUserId-dynamic'>
#
(void)
<b>getUserId</b><span>()</span>
</a>
</span>
<span class='desc'>
Get the UserId from the HistoryBuffer object.
</span>
</li>
<li>
<span class='signature'>
<a href='#toJson-dynamic'>
#
(void)
<b>toJson</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#val-dynamic'>
#
(void)
<b>val</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#on-dynamic'>
#
(void)
<b>on</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
<li>
<span class='signature'>
<a href='#deleteListener-dynamic'>
#
(void)
<b>deleteListener</b><span>()</span>
</a>
</span>
<span class='desc'>
</span>
</li>
</ul>
<h2>Constructor Details</h2>
<div class='methods'>
<div class='method_details'>
<p class='signature' id='constructor-dynamic'>
#
(void)
<b>constructor</b><span>(connector)</span>
<br>
</p>
<div class='tags'>
<h3>Parameters:</h3>
<ul class='param'>
<li>
<span class='name'>user_id</span>
<span class='type'>
(
<tt>String</tt>
)
</span>
&mdash;
<span class='desc'>Unique id of the peer. </span>
</li>
<li>
<span class='name'>Connector</span>
<span class='type'>
(
<tt>Connector</tt>
)
</span>
&mdash;
<span class='desc'>the connector class. </span>
</li>
</ul>
</div>
</div>
</div>
<h2>Instance Method Details</h2>
<div class='methods'>
<div class='method_details'>
<p class='signature' id='getSharedObject-dynamic'>
#
(?)
<b>getSharedObject</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>Returns:</h3>
<ul class='return'>
<li>
<span class='type'></span>
(
<tt>?</tt>
)
&mdash;
<span class='desc'>JsonType </span>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='getConnector-dynamic'>
#
(void)
<b>getConnector</b><span>()</span>
<br>
</p>
<div class='docstring'>
<p>Get the initialized connector.</p>
</div>
<div class='tags'>
</div>
</div>
<div class='method_details'>
<p class='signature' id='getHistoryBuffer-dynamic'>
#
(void)
<b>getHistoryBuffer</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='HistoryBuffer'>HistoryBuffer</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='setMutableDefault-dynamic'>
#
(void)
<b>setMutableDefault</b><span>(mutable)</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='JsonType.setMutableDefault'>JsonType.setMutableDefault</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='getUserId-dynamic'>
#
(void)
<b>getUserId</b><span>()</span>
<br>
</p>
<div class='docstring'>
<p>Get the UserId from the HistoryBuffer object.
In most cases this will be the same as the user_id value with which
Yatta was initialized (Depending on the HistoryBuffer implementation).</p>
</div>
<div class='tags'>
</div>
</div>
<div class='method_details'>
<p class='signature' id='toJson-dynamic'>
#
(void)
<b>toJson</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='JsonType.toJson'>JsonType.toJson</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='val-dynamic'>
#
(void)
<b>val</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='JsonType.val'>JsonType.val</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='on-dynamic'>
#
(void)
<b>on</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='Operation.on'>Operation.on</a>
</li>
</ul>
</div>
</div>
<div class='method_details'>
<p class='signature' id='deleteListener-dynamic'>
#
(void)
<b>deleteListener</b><span>()</span>
<br>
</p>
<div class='tags'>
<h3>See also:</h3>
<ul class='see'>
<li>
<a href='Operation.deleteListener'>Operation.deleteListener</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id='footer'>
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>
2.0.9
&#10034;
Press H to see the keyboard shortcuts
&#10034;
<a href='http://twitter.com/netzpirat' target='_parent'>@netzpirat</a>
&#10034;
<a href='http://twitter.com/_inossidabile' target='_parent'>@_inossidabile</a>
</div>
<iframe id='search_frame'></iframe>
<div id='fuzzySearch'>
<input type='text'>
<ol></ol>
</div>
<div id='help'>
<p>
Quickly fuzzy find classes, mixins, methods, file:
</p>
<ul>
<li>
<span>T</span>
Open fuzzy finder dialog
</li>
</ul>
<p>
Control the navigation frame:
</p>
<ul>
<li>
<span>L</span>
Toggle list view
</li>
<li>
<span>C</span>
Show class list
</li>
<li>
<span>I</span>
Show mixin list
</li>
<li>
<span>F</span>
Show file list
</li>
<li>
<span>M</span>
Show method list
</li>
<li>
<span>E</span>
Show extras list
</li>
</ul>
<p>
You can focus and blur the search input:
</p>
<ul>
<li>
<span>S</span>
Focus search input
</li>
<li>
<span>Esc</span>
Blur search input
</li>
</ul>
</div>
</body>
</html>

View File

@ -29,30 +29,6 @@
<input type='text'>
</div>
<ul>
<li>
<a href='class/JsonFramework.html' target='main'>
JsonFramework
</a>
<small class='namespace'>
</small>
</li>
<li>
<a href='class/TextFramework.html' target='main'>
TextFramework
</a>
<small class='namespace'>
</small>
</li>
<li>
<a href='class/XmlFramework.html' target='main'>
XmlFramework
</a>
<small class='namespace'>
</small>
</li>
<li>
<a href='class/JsonTypeWrapper.html' target='main'>
JsonTypeWrapper
@ -83,6 +59,14 @@
</small>
<small class='namespace'>
</small>
</li>
<li>
<a href='class/Yatta.html' target='main'>
Yatta
</a>
<small class='namespace'>
</small>
</li>
</ul>

View File

@ -38,7 +38,7 @@
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -34,7 +34,7 @@
</p>
</nav>
<div id='filecontents'>
<h1 id="-yatta-extras-imgs-yatta_logo-png-raw-true-"><img src="./extras/imgs/Yatta_logo.png?raw=true" alt="Yatta!"></h1><p>A Real-Time web framework that manages concurrency control for arbitrary data structures.
<h1 id="-yatta-https-dadamonad-github-io-files-layout-yatta_logo-png-"><img src="https://dadamonad.github.io/files/layout/Yatta_logo.png" alt="Yatta!"></h1><p>A Real-Time web framework that manages concurrency control for arbitrary data structures.
Yatta! provides similar functionality as <a href="https://github.com/share/ShareJS">ShareJs</a> and <a href="https://github.com/opencoweb/coweb">OpenCoweb</a>,
but does not require you to understand how the internals work. The predefined data structures provide a simple API to access your shared data structures.</p><p>Predefined data structures:</p><ul>
<li>Text - <a href="http://dadamonad.github.io/Yatta/examples/TextEditing/">Collaborative Text Editing Example</a></li>
@ -76,7 +76,7 @@ But I would become really motivated if you gave me some feedback :) (<a href="ht
</ul>
<h2 id="support">Support</h2><p>Please report <em>any</em> issues to the <a href="https://github.com/DadaMonad/Yatta/issues">Github issue page</a>!
I would appreciate if developers gave me feedback on how <em>convenient</em> the framework is, and if it is easy to use. Particularly the XML-support may not support every DOM-methods - if you encounter a method that does not cause any change on other peers,
please state function name, and sample parameters. However, there are browser-specific features, that Yatta won&#39;t support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="&#x6d;&#97;&#105;&#x6c;&#x74;&#x6f;&#58;&#x6b;&#x65;&#118;&#105;&#x6e;&#x2e;&#106;&#97;&#104;&#110;&#x73;&#x40;&#114;&#x77;&#116;&#x68;&#45;&#x61;&#97;&#x63;&#104;&#x65;&#110;&#46;&#100;&#x65;">&#x6b;&#x65;&#118;&#105;&#x6e;&#x2e;&#106;&#97;&#104;&#110;&#x73;&#x40;&#114;&#x77;&#116;&#x68;&#45;&#x61;&#97;&#x63;&#104;&#x65;&#110;&#46;&#100;&#x65;</a>
please state function name, and sample parameters. However, there are browser-specific features, that Yatta won&#39;t support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="&#109;&#x61;&#x69;&#108;&#x74;&#111;&#x3a;&#x6b;&#x65;&#118;&#x69;&#x6e;&#46;&#106;&#x61;&#104;&#x6e;&#x73;&#64;&#114;&#119;&#116;&#x68;&#x2d;&#x61;&#x61;&#99;&#x68;&#x65;&#110;&#x2e;&#100;&#101;">&#x6b;&#x65;&#118;&#x69;&#x6e;&#46;&#106;&#x61;&#104;&#x6e;&#x73;&#64;&#114;&#119;&#116;&#x68;&#x2d;&#x61;&#x61;&#99;&#x68;&#x65;&#110;&#x2e;&#100;&#101;</a>
@ -85,7 +85,7 @@ please state function name, and sample parameters. However, there are browser-sp
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -106,7 +106,7 @@
</div>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -48,7 +48,7 @@
</dl>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -60,7 +60,7 @@
</dl>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -60,7 +60,7 @@
</dl>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -60,7 +60,7 @@
</dl>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -48,7 +48,7 @@
</dl>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -39,7 +39,7 @@
</table>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -0,0 +1,132 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Yatta! API</title>
<script src='../../javascript/application.js'></script>
<script src='../../javascript/search.js'></script>
<link rel='stylesheet' href='../../stylesheets/application.css' type='text/css'>
</head>
<body>
<div id='base' data-path='../../'></div>
<div id='header'>
<div id='menu'>
<a href='../../extra/README.md.html' title='Yatta!'>
Yatta!
</a>
&raquo;
<a href='../../alphabetical_index.html' title='Index'>
Index
</a>
&raquo;
<span class='title'>lib</span>
&raquo;
<span class='title'>Yatta.coffee</span>
</div>
</div>
<div id='content'>
<h1>
File:
Yatta.coffee
</h1>
<table class='box'>
<tr>
<td>Defined in:</td>
<td>lib</td>
</tr>
<tr>
<td>
Classes:
</td>
<td>
<a href='../../class/Yatta.html'>
Yatta
</a>
</td>
</tr>
</table>
<h2>Variables Summary</h2>
<dl class='constants'>
<dt id='module.exports-variable'>
module.exports
=
</dt>
<dd>
<pre><code class='coffeescript'>Yatta</code></pre>
</dd>
</dl>
</div>
<div id='footer'>
December 16, 14 09:44:06 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>
2.0.9
&#10034;
Press H to see the keyboard shortcuts
&#10034;
<a href='http://twitter.com/netzpirat' target='_parent'>@netzpirat</a>
&#10034;
<a href='http://twitter.com/_inossidabile' target='_parent'>@_inossidabile</a>
</div>
<iframe id='search_frame'></iframe>
<div id='fuzzySearch'>
<input type='text'>
<ol></ol>
</div>
<div id='help'>
<p>
Quickly fuzzy find classes, mixins, methods, file:
</p>
<ul>
<li>
<span>T</span>
Open fuzzy finder dialog
</li>
</ul>
<p>
Control the navigation frame:
</p>
<ul>
<li>
<span>L</span>
Toggle list view
</li>
<li>
<span>C</span>
Show class list
</li>
<li>
<span>I</span>
Show mixin list
</li>
<li>
<span>F</span>
Show file list
</li>
<li>
<span>M</span>
Show method list
</li>
<li>
<span>E</span>
Show extras list
</li>
</ul>
<p>
You can focus and blur the search input:
</p>
<ul>
<li>
<span>S</span>
Focus search input
</li>
<li>
<span>Esc</span>
Blur search input
</li>
</ul>
</div>
</body>
</html>

View File

@ -37,7 +37,7 @@
</table>
</div>
<div id='footer'>
December 02, 14 09:37:37 by
December 16, 14 09:32:37 by
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
Codo
</a>

View File

@ -51,38 +51,6 @@
lib
</small>
</li>
<li>
<span>
Frameworks
</span>
</li>
<ul>
<li>
<a href='file/lib/Frameworks/JsonFramework.coffee.html' target='main'>
JsonFramework.coffee
</a>
<small class='namespace'>
lib&#47;Frameworks
</small>
</li>
<li>
<a href='file/lib/Frameworks/TextFramework.coffee.html' target='main'>
TextFramework.coffee
</a>
<small class='namespace'>
lib&#47;Frameworks
</small>
</li>
<li>
<a href='file/lib/Frameworks/XmlFramework.coffee.html' target='main'>
XmlFramework.coffee
</a>
<small class='namespace'>
lib&#47;Frameworks
</small>
</li>
</ul>
<li>
<a href='file/lib/HistoryBuffer.coffee.html' target='main'>
HistoryBuffer.coffee
@ -132,8 +100,8 @@
</ul>
<li>
<a href='file/lib/index.coffee.html' target='main'>
index.coffee
<a href='file/lib/Yatta.coffee.html' target='main'>
Yatta.coffee
</a>
<small class='namespace'>
lib

File diff suppressed because one or more lines are too long

View File

@ -29,14 +29,6 @@
<input type='text'>
</div>
<ul>
<li>
<a href='class/WordType.html#_encode-dynamic' target='main' title='_encode'>
#_encode
</a>
<small>
(WordType)
</small>
</li>
<li>
<a href='class/JsonType.html#_encode-dynamic' target='main' title='_encode'>
#_encode
@ -45,6 +37,14 @@
(JsonType)
</small>
</li>
<li>
<a href='class/WordType.html#_encode-dynamic' target='main' title='_encode'>
#_encode
</a>
<small>
(WordType)
</small>
</li>
<li>
<a href='file/lib/ConnectorAdapter.coffee.html#adaptConnector-' target='main' title='adaptConnector'>
~adaptConnector
@ -70,16 +70,16 @@
</small>
</li>
<li>
<a href='class/TextFramework.html#bind-dynamic' target='main' title='bind'>
<a href='class/WordType.html#bind-dynamic' target='main' title='bind'>
#bind
</a>
<small>
(TextFramework)
(WordType)
</small>
</li>
<li>
<a href='class/WordType.html#bind-dynamic' target='main' title='bind'>
#bind
<a href='class/WordType.html#cleanup-dynamic' target='main' title='cleanup'>
#cleanup
</a>
<small>
(WordType)
@ -94,43 +94,11 @@
</small>
</li>
<li>
<a href='class/WordType.html#cleanup-dynamic' target='main' title='cleanup'>
#cleanup
</a>
<small>
(WordType)
</small>
</li>
<li>
<a href='class/JsonTypeWrapper.html#constructor-dynamic' target='main' title='constructor'>
<a href='class/Yatta.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(JsonTypeWrapper)
</small>
</li>
<li>
<a href='class/TextFramework.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/WordType.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(WordType)
</small>
</li>
<li>
<a href='class/XmlFramework.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(XmlFramework)
(Yatta)
</small>
</li>
<li>
@ -142,27 +110,27 @@
</small>
</li>
<li>
<a href='class/JsonFramework.html#constructor-dynamic' target='main' title='constructor'>
<a href='class/JsonTypeWrapper.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(JsonFramework)
(JsonTypeWrapper)
</small>
</li>
<li>
<a href='class/JsonFramework.html#deleteListener-dynamic' target='main' title='deleteListener'>
<a href='class/WordType.html#constructor-dynamic' target='main' title='constructor'>
#constructor
</a>
<small>
(WordType)
</small>
</li>
<li>
<a href='class/Yatta.html#deleteListener-dynamic' target='main' title='deleteListener'>
#deleteListener
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/TextFramework.html#deleteText-dynamic' target='main' title='deleteText'>
#deleteText
</a>
<small>
(TextFramework)
(Yatta)
</small>
</li>
<li>
@ -174,51 +142,19 @@
</small>
</li>
<li>
<a href='class/XmlFramework.html#getConnector-dynamic' target='main' title='getConnector'>
<a href='class/Yatta.html#getConnector-dynamic' target='main' title='getConnector'>
#getConnector
</a>
<small>
(XmlFramework)
(Yatta)
</small>
</li>
<li>
<a href='class/TextFramework.html#getConnector-dynamic' target='main' title='getConnector'>
#getConnector
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/JsonFramework.html#getConnector-dynamic' target='main' title='getConnector'>
#getConnector
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/XmlFramework.html#getHistoryBuffer-dynamic' target='main' title='getHistoryBuffer'>
<a href='class/Yatta.html#getHistoryBuffer-dynamic' target='main' title='getHistoryBuffer'>
#getHistoryBuffer
</a>
<small>
(XmlFramework)
</small>
</li>
<li>
<a href='class/TextFramework.html#getHistoryBuffer-dynamic' target='main' title='getHistoryBuffer'>
#getHistoryBuffer
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/JsonFramework.html#getHistoryBuffer-dynamic' target='main' title='getHistoryBuffer'>
#getHistoryBuffer
</a>
<small>
(JsonFramework)
(Yatta)
</small>
</li>
<li>
@ -230,51 +166,19 @@
</small>
</li>
<li>
<a href='class/JsonFramework.html#getSharedObject-dynamic' target='main' title='getSharedObject'>
<a href='class/Yatta.html#getSharedObject-dynamic' target='main' title='getSharedObject'>
#getSharedObject
</a>
<small>
(JsonFramework)
(Yatta)
</small>
</li>
<li>
<a href='class/XmlFramework.html#getSharedObject-dynamic' target='main' title='getSharedObject'>
#getSharedObject
</a>
<small>
(XmlFramework)
</small>
</li>
<li>
<a href='class/TextFramework.html#getSharedObject-dynamic' target='main' title='getSharedObject'>
#getSharedObject
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/XmlFramework.html#getUserId-dynamic' target='main' title='getUserId'>
<a href='class/Yatta.html#getUserId-dynamic' target='main' title='getUserId'>
#getUserId
</a>
<small>
(XmlFramework)
</small>
</li>
<li>
<a href='class/JsonFramework.html#getUserId-dynamic' target='main' title='getUserId'>
#getUserId
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/TextFramework.html#getUserId-dynamic' target='main' title='getUserId'>
#getUserId
</a>
<small>
(TextFramework)
(Yatta)
</small>
</li>
<li>
@ -294,35 +198,11 @@
</small>
</li>
<li>
<a href='class/TextFramework.html#insertText-dynamic' target='main' title='insertText'>
#insertText
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/JsonFramework.html#on-dynamic' target='main' title='on'>
<a href='class/Yatta.html#on-dynamic' target='main' title='on'>
#on
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/XmlFramework.html#on-dynamic' target='main' title='on'>
#on
</a>
<small>
(XmlFramework)
</small>
</li>
<li>
<a href='class/TextFramework.html#on-dynamic' target='main' title='on'>
#on
</a>
<small>
(TextFramework)
(Yatta)
</small>
</li>
<li>
@ -333,14 +213,6 @@
(WordType)
</small>
</li>
<li>
<a href='class/TextFramework.html#replaceText-dynamic' target='main' title='replaceText'>
#replaceText
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/WordType.html#replaceText-dynamic' target='main' title='replaceText'>
#replaceText
@ -349,14 +221,6 @@
(WordType)
</small>
</li>
<li>
<a href='class/JsonFramework.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'>
#setMutableDefault
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/JsonType.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'>
#setMutableDefault
@ -366,11 +230,11 @@
</small>
</li>
<li>
<a href='class/XmlFramework.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'>
<a href='class/Yatta.html#setMutableDefault-dynamic' target='main' title='setMutableDefault'>
#setMutableDefault
</a>
<small>
(XmlFramework)
(Yatta)
</small>
</li>
<li>
@ -389,22 +253,6 @@
(WordType)
</small>
</li>
<li>
<a href='class/JsonFramework.html#toJson-dynamic' target='main' title='toJson'>
#toJson
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/XmlFramework.html#toJson-dynamic' target='main' title='toJson'>
#toJson
</a>
<small>
(XmlFramework)
</small>
</li>
<li>
<a href='class/JsonType.html#toJson-dynamic' target='main' title='toJson'>
#toJson
@ -413,6 +261,14 @@
(JsonType)
</small>
</li>
<li>
<a href='class/Yatta.html#toJson-dynamic' target='main' title='toJson'>
#toJson
</a>
<small>
(Yatta)
</small>
</li>
<li>
<a href='class/WordType.html#toString-dynamic' target='main' title='toString'>
#toString
@ -422,19 +278,11 @@
</small>
</li>
<li>
<a href='class/JsonFramework.html#val-dynamic' target='main' title='val'>
<a href='class/Yatta.html#val-dynamic' target='main' title='val'>
#val
</a>
<small>
(JsonFramework)
</small>
</li>
<li>
<a href='class/XmlFramework.html#val-dynamic' target='main' title='val'>
#val
</a>
<small>
(XmlFramework)
(Yatta)
</small>
</li>
<li>
@ -445,14 +293,6 @@
(WordType)
</small>
</li>
<li>
<a href='class/TextFramework.html#val-dynamic' target='main' title='val'>
#val
</a>
<small>
(TextFramework)
</small>
</li>
<li>
<a href='class/JsonType.html#val-dynamic' target='main' title='val'>
#val

View File

@ -1,333 +0,0 @@
## PeerJs + JSON Example
Here, I will give a short overview on how to enable collaborative json with the
[PeerJs](http://peerjs.com/) Connector and the Json Framework. Open
[index.html](http://dadamonad.github.io/Yatta/examples/PeerJs-Json/index.html) in your Browser and
use the console to explore Yatta!
[PeerJs](http://peerjs.com) is a Framework that enables you to connect to other peers. You just need the
user-id of the peer (browser/client). And then you can connect to it.
First you have to include the following libraries in your html file:
```
<script src="http://cdn.peerjs.com/0.3/peer.js"></script>
<script src="../../build/browser/Frameworks/JsonFramework.js"></script>
<script src="../../build/browser/Connectors/PeerJsConnector.js"></script>
<script src="./index.js"></script>
```
### Create Connector
The PeerJs Framework requires an API key, or you need to set up your own PeerJs server.
Get an API key from the [Website](http://peerjs.com/peerserver).
The first parameter of `createPeerJsConnector` is forwarded as the options object in PeerJs.
Therefore, you may also specify the server/port here, if you have set up your own server.
```js
var yatta, yattaHandler;
```
This will connect to the server owned by the peerjs team.
For now, you can use my API key.
```js
//var options = {key: 'h7nlefbgavh1tt9'};
```
This will connect to one of my peerjs instances.
I can't guaranty that this will be always up. This is why you should use the previous method with the api key,
or set up your own server.
```js
var options = {
host: "terrific-peerjs.herokuapp.com",
port: "", // this works because heroku can forward to the right port.
// debug: true,
};
var user_id = Math.ceil(Math.random()*100);
connector = new PeerJsConnector(user_id,options);
//var connector = new TestConnector(user_id);
```
### Yatta
yatta is the shared json object. If you change something on this object,
it will be instantly shared with all the other collaborators.
```js
yatta = new Y.JsonFramework(user_id, connector);
```
Next, you may want to connect to another peer. Therefore you have to receive his
user_id. If the other peer is connected to other peers, the PeerJsConnector
will automatically connect to them too.
Transmitting the user_id is your job.
See [TextEditing](../../examples/TextEditing/) for a nice example
on how to do that with urls.
```js
console.log("Copy your user-id: " + user_id);
// yatta.connector.connectToPeer(peer_user_id);
```
Add a integer-property like this
```js
yatta.val('x', 7);
```
Get the value of property x like this
```js
console.log(yatta.val('x') === 7); // true
```
A string property can be either mutable or immutable.
```js
yatta.val('mutable_string', "text", "mutable");
yatta.val('immutable_string', "text", "immutable");
console.log(yatta.val('immutable_string') === "text"); // true
yatta.val('mutable_string').insertText(2,"XXX"); // position, string
yatta.val('mutable_string').deleteText(0,1); // position, deletion length
console.log(yatta.val('mutable_string').val() === "eXXXxt"); // true
```
Did you recognize that we use anoter `.val()` for mutable strings?
Thats because `yatta.val('mutable_string')` is of type *WordType*.
Since WordType implements `toString`, you can use it like a string:
```js
console.log("" + yatta.val("mutable_string") === "eXXXxt") // true, concatenating it with a string will implicitly invoke toString()
```
You can omit the mutable - parameter. In that case the default will be used.
Initially the default is 'mutable'. You can set it like this:
```js
yatta.setMutableDefault('mutable');
// or
yatta.setMutableDefault('immutable');
yatta.val('new_string', "string");
console.log(yatta.val('new_string') === "string"); // true
```
Yatta is [chainable](http://schier.co/post/method-chaining-in-javascript):
```js
yatta.val('a', 4).val('b',5);
console.log(yatta.val('a') === 4); // true
console.log(yatta.val('b') === 5); // true
```
You can alse set objects.
```js
yatta.val('object', {a : {b : "b"}, c : { d : 5 }});
console.log(yatta.val('object').val('c').val('d') === 5); // true
```
Lists are always immutable.
```js
yatta.val('list', [0,1,2]);
console.log(yatta.val('list')[2] === 2); // true
```
### Check Types
Certainly you want to check types!
You get the type of an YattaType with the `.type` property.
Here, we create a function that parses a Yatta type to a string.
```js
function show(o){
if (o.type === "JsonType"){
return JSON.stringify(o.toJson());
} else if (o.type === "WordType") {
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.
```js
function addProperty(event_name, property_name, op){
// op is the operation that changed the objects value. In addProperty it is most likely to be a 'Replaceable' (see doc).
console.log("Property '" + property_name + "' was created by '"+op.creator+"'!");
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!
```
Apply a 'change' - listener to a JsonType.
```js
function change(event_name, property_name, op){
// Check who made this property change!
if(op.creator == yatta.getUserId()){
console.log("You changed the value of property '" + property_name + "'!");
}else{
console.log("User '"+op.creator+"' changed the value of property '" + property_name + "'!");
}
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'); // You changed the value of property 'mutable_string'!
```
'change' and 'addProperty' do also fire for nested properties.
```js
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!
```
Delete the listeners
```js
yatta.deleteListener('addProperty', addProperty);
yatta.deleteListener('change', change);
```
Apply 'insert' and 'delete' - listeners to Words.
```js
function insert_delete(event_name, op){
if (event_name === "insert"){
console.log("Inserted '" + op.content + "' at position " + op.getPosition());
} else if (event_name === "delete"){
console.log("Deleted character at position " + op.getPosition());
}
};
yatta.val('mutable_string').on(['insert', 'delete'], insert_delete);
yatta.val('mutable_string').insertText(0, 'a'); // Inserted 'a' at position 0
yatta.val('mutable_string').deleteText(0, 1); // Deleted character at position 0
yatta.val('mutable_string').deleteListener('insert_delete', insert_delete);
```
### Experimental method
Nah.. this is only for the cool kids.
```js
console.log(yatta.value.list[2] === 2) // true
yatta.value.list = [3,4,5]
console.log(yatta.val('list')[2] === 5) // true
yatta.value.object = {c : 4}
console.log(yatta.value.object.c === 4) // true
```
How did I do that? ^^
In Javascript it is possible set setter- and getter- for properties. This is
why this method feels much more natural.
The downside is that you are only allowed to overwrite existing properties.
```js
yatta.value.newProperty = "Awesome"
console.log(yatta.value.newProperty !== "Awesome") // true, yatta.value.newProperty is undefined.
```
So, how do we create new properties?
```js
yatta.value = {newProperty : "Awesome"}
console.log(yatta.value.newProperty === "Awesome") // true, it's awesome ;)
```
This is stupid! I don't want to overwrite all my existing properties!
Very well.. The solution is that we merge yatta.value with the new assignment.
For example: assuming we want to overwrite yatta.value with some object o.
Then these two rules apply:
* The result has all properties of o
* The result has all properties of yatta.value if they don't occur under the same property-name in o
```js
yatta.value = {newProperty : {Awesome : true }}
console.log(yatta.value.list[2] === 5) // true, old value list still exists.
console.log(yatta.value.newProperty.Awesome === true) // true, newProperty is overwritten.
```
Consider this case.
```js
yatta.value = {newProperty : { x : 4} }
console.log(yatta.value.newProperty.Awesome == null) // true, newProperty was replaced, therefore it is now undefined
```
Did you notice that you always set immutable objects if you set properties like this?
Even if the default is 'mutable'. If you want to work with mutable objects you have to work with .val().
One last thing. You are only allowed to set properties like this `yatta.value = o`.
Yatta can't observe if you overwrite object references `yatta = "Awesome"`.
```js
w = yatta.value.newProperty
w = "Awesome"
console.log(yatta.value.newProperty !== "Awesome") // true, still not awesome..
```
Please also read [JsonWrapper](https://rawgit.com/DadaMonad/Yatta/master/doc/class/JsonWrapper.html).
I really want to hear what you think about this method :)

View File

@ -6,7 +6,7 @@
<script src="../../bower_components/peerjs/peer.js"></script>
<script src="../../bower_components/connector/peerjs-connector/peerjs-connector.js"></script>
<script src="../../bower_components/connector/test-connector/test-connector.js"></script>
<script src="../../build/browser/Frameworks/JsonFramework.js"></script>
<script src="../../build/browser/yatta.js"></script>
<script src="./index.js"></script>
</head>
<body>

View File

@ -29,19 +29,20 @@ var yatta, yattaHandler;
This will connect to the server owned by the peerjs team.
For now, you can use my API key.
*/
//var options = {key: 'h7nlefbgavh1tt9'};
var options = {key: 'h7nlefbgavh1tt9'};
/**
This will connect to one of my peerjs instances.
I can't guaranty that this will be always up. This is why you should use the previous method with the api key,
or set up your own server.
*/
/*
var options = {
host: "terrific-peerjs.herokuapp.com",
port: "", // this works because heroku can forward to the right port.
// debug: true,
};
*/
var user_id = Math.ceil(Math.random()*100);
connector = new PeerJsConnector(user_id,options);
@ -52,7 +53,7 @@ connector = new PeerJsConnector(user_id,options);
yatta is the shared json object. If you change something on this object,
it will be instantly shared with all the other collaborators.
*/
yatta = new Y.JsonFramework(user_id, connector);
yatta = new Yatta(connector);
/**
Next, you may want to connect to another peer. Therefore you have to receive his

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -1,357 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="381.09735"
height="187.42168"
id="svg7976"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="Yatta_logo.svg">
<defs
id="defs7978">
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend"
style="overflow:visible">
<path
id="path4310"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible">
<path
id="path4316"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6,-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mstart"
style="overflow:visible">
<path
id="path4313"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(0.6,0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible">
<path
id="path4304"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Sstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Sstart"
style="overflow:visible">
<path
id="path4301"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(0.2,0,0,0.2,1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible">
<path
id="path4292"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path4289"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<inkscape:path-effect
effect="skeletal"
id="path-effect8752"
is_visible="true"
pattern="M 0,5 C 0,2.24 2.24,0 5,0 7.76,0 10,2.24 10,5 10,7.76 7.76,10 5,10 2.24,10 0,7.76 0,5 z"
copytype="single_stretched"
prop_scale="1"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="false"
vertical_pattern="false"
fuse_tolerance="0" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="158.87513"
inkscape:cy="178.66098"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:snap-grids="true"
inkscape:window-width="1280"
inkscape:window-height="979"
inkscape:window-x="-4"
inkscape:window-y="-3"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7981">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-67.225249,-76.895)">
<g
id="g8648"
transform="matrix(3.8957433,0,0,3.8957433,-180.76316,-209.47544)">
<rect
ry="6.0883365"
rx="0"
y="102.509"
x="63.834892"
height="12.488896"
width="9.4584417"
id="rect7986"
style="fill:#ffbd58;fill-opacity:1;stroke:#ffb8bd;stroke-width:0.38039941;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
id="text7988"
y="113.49197"
x="64.593651"
style="font-size:13px;font-style:normal;font-weight:normal;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="113.49197"
x="64.593651"
id="tspan7990"
sodipodi:role="line">Y</tspan></text>
</g>
<g
id="g8653"
transform="matrix(3.8957433,0,0,3.8957433,-189.0027,-263.0938)">
<rect
ry="6.0883365"
rx="0"
y="116.27232"
x="87.952286"
height="12.488896"
width="9.4584417"
id="rect7986-6"
style="fill:#ffbd58;fill-opacity:1;stroke:#ffb8bd;stroke-width:0.38039941;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
id="text7988-7"
y="127.25529"
x="88.238144"
style="font-size:13px;font-style:normal;font-weight:normal;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="127.25529"
x="88.238144"
id="tspan7990-9"
sodipodi:role="line">A</tspan></text>
</g>
<g
id="g8658"
transform="matrix(3.8957433,0,0,3.8957433,-183.96057,-337.86438)">
<rect
ry="6.0883365"
rx="0"
y="135.46521"
x="108.6604"
height="12.488896"
width="9.4584417"
id="rect7986-6-7"
style="fill:#ffbd58;fill-opacity:1;stroke:#ffb8bd;stroke-width:0.38039941;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
id="text7988-7-9"
y="146.44818"
x="109.41916"
style="font-size:13px;font-style:normal;font-weight:normal;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="146.44818"
x="109.41916"
id="tspan7990-9-0"
sodipodi:role="line">T</tspan></text>
</g>
<g
id="g8663"
transform="matrix(3.8957433,0,0,3.8957433,-266.47882,-397.87764)">
<rect
ry="6.0883365"
rx="0"
y="150.87004"
x="151.84442"
height="12.488896"
width="9.4584417"
id="rect7986-6-4"
style="fill:#ffbd58;fill-opacity:1;stroke:#ffb8bd;stroke-width:0.38039941;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
id="text7988-7-97"
y="161.85301"
x="152.13028"
style="font-size:13px;font-style:normal;font-weight:normal;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="161.85301"
x="152.13028"
id="tspan7990-9-4"
sodipodi:role="line">A</tspan></text>
</g>
<g
id="g8673"
transform="matrix(3.8957433,0,0,3.8957433,-624.46772,-357.54085)">
<rect
ry="6.0883365"
rx="0"
y="140.51598"
x="265.73914"
height="12.488896"
width="9.4584417"
id="rect7986-6-5"
style="fill:#ffbd58;fill-opacity:1;stroke:#ffb8bd;stroke-width:0.38039941;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
id="text7988-7-7"
y="151.49895"
x="267.86264"
style="font-size:13px;font-style:normal;font-weight:normal;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="151.49895"
x="267.86264"
id="tspan7990-9-5"
sodipodi:role="line">!</tspan></text>
</g>
<g
id="g8668"
transform="matrix(3.8957433,0,0,3.8957433,-712.02806,-577.9551)">
<rect
ry="6.0883365"
rx="0"
y="168.29517"
x="255.13252"
height="12.488896"
width="9.4584417"
id="rect7986-6-8"
style="fill:#ffbd58;fill-opacity:1;stroke:#ffb8bd;stroke-width:0.38039941;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
id="text7988-7-3"
y="179.27814"
x="255.89128"
style="font-size:13px;font-style:normal;font-weight:normal;line-height:0%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="179.27814"
x="255.89128"
id="tspan7990-9-00"
sodipodi:role="line">T</tspan></text>
</g>
<path
style="fill:none;stroke:#69ff00;stroke-width:1.94787169;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none"
d="m 96.675142,237.77416 c 16.915998,34.61882 42.117198,33.88572 61.980908,-0.98383"
id="path8783"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#69ff00;stroke-width:1.94787169;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none"
d="m 185.71118,237.28685 c 16.91602,34.61881 42.11721,33.88572 61.98091,-0.98384"
id="path8783-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#69ff00;stroke-width:1.94787169;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:none;marker-mid:none;marker-end:none"
d="m 356.89652,237.28685 c 16.916,34.61881 42.11719,33.88572 61.98093,-0.98384"
id="path8783-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:2.33744597;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:2.0999999;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
d="m 299.79777,126.3332 -1.43872,66.18503"
id="path10517"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g8668"
inkscape:connection-start-point="d4"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff4f00;stroke-width:1.55829763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 258.02225,189.56679 c -6.2228,-60.38318 2.94629,-87.18398 25.5794,-84.60886"
id="path11677"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff4f00;stroke-width:1.55829763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 345.28073,188.99654 c 6.2228,-60.38318 -2.94631,-87.18397 -25.57942,-84.60884"
id="path11677-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -24,10 +24,9 @@ gulp.task 'build', ['lint', 'browser']
files =
lib : ['./lib/**/*.coffee']
build : ['./build/**']
browser : ['./lib/{Connectors,Frameworks}/**/*']
test : ['./test/**/*_test.coffee']
#test : ['./test/TextYatta_test.coffee']
browser_test : ['./test/**/*_test_browser.coffee']
browser : './lib/Yatta.coffee'
#test : ['./test/**/*_test.coffee']
test : ['./test/JsonYatta_test.coffee']
gulp : ['./gulpfile.coffee']
examples : ['./examples/**/*.js']
@ -51,16 +50,13 @@ gulp.task 'browser', ->
extensions: ['.coffee']
debug : true
.pipe rename
basename: "yatta"
extname: ".js"
.pipe gulp.dest './build/browser'
.pipe gulp.dest './build/browser/'
.pipe uglify()
.pipe rename
extname: ".js"
basename: "index"
.pipe gulp.dest './'
.pipe gulpif '!**/', git.add({args : "-A"})
.pipe gulp.dest '.'
gulp.src (files.test.concat files.browser_test), {read: false}
gulp.src files.test, {read: false}
.pipe browserify
transform: ['coffeeify']
extensions: ['.coffee']

View File

@ -22,6 +22,7 @@ class Engine
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._encode().
# @note You must not use this method when you already have ops in your HB!
@ -30,8 +31,6 @@ class Engine
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
@ -64,8 +63,6 @@ class Engine
if @HB.getOperation(o)?
else if not o.execute()
@unprocessed_ops.push o
else
@HB.addOperation o
@tryUnprocessed()
#

View File

@ -1,107 +0,0 @@
text_types_uninitialized = require "../Types/TextTypes"
HistoryBuffer = require "../HistoryBuffer"
Engine = require "../Engine"
adaptConnector = require "../ConnectorAdapter"
#
# Framework for Text Datastructures.
#
class TextFramework
#
# @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
@types = text_types.types
@engine = new Engine @HB, text_types.parser
adaptConnector @connector, @engine, @HB, text_types.execution_listener
beginning = @HB.addOperation new @types.Delimiter {creator: '_', op_number: '_beginning'} , undefined, undefined
end = @HB.addOperation new @types.Delimiter {creator: '_', op_number: '_end'} , beginning, undefined
beginning.next_cl = end
beginning.execute()
end.execute()
first_word = new @types.WordType {creator: '_', op_number: '_'}, beginning, end
@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 = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()
end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()
@root_element = @HB.addOperation(new @types.ReplaceManager undefined, uid_r, beg, end).execute()
@root_element.replace first_word, { creator: '_', op_number: 'Replaceable'}
#
# @return WordType
#
getSharedObject: ()->
@root_element.val()
#
# 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
# JsonFramework was initialized (Depending on the HistoryBuffer implementation).
#
getUserId: ()->
@HB.getUserId()
#
# @see JsonType.val
#
val: ()->
@getSharedObject().val()
#
# @see WordType.insertText
#
insertText: (pos, content)->
@getSharedObject().insertText pos, content
#
# @see WordType.deleteText
#
deleteText: (pos, length)->
@getSharedObject().deleteText pos, length
#
# @see WordType.bind
#
bind: (textarea)->
@getSharedObject().bind textarea
#
# @see WordType.replaceText
#
replaceText: (text)->
@getSharedObject().replaceText text
#
# @see Operation.on
#
on: ()->
@root_element.on arguments...
module.exports = TextFramework
if window?
if not window.Y?
window.Y = {}
window.Y.TextFramework = TextFramework

View File

@ -1,101 +0,0 @@
json_types_uninitialized = require "../Types/XmlTypes"
HistoryBuffer = require "../HistoryBuffer"
Engine = require "../Engine"
adaptConnector = require "../ConnectorAdapter"
#
# Framework for Xml-like data-structures.
# Known values that are supported:
#
class XmlFramework
#
# @param {String} user_id Unique id of the peer.
# @param {Connector} Connector the connector class.
#
constructor: (user_id, @connector)->
@HB = new HistoryBuffer user_id
type_manager = json_types_uninitialized @HB
@types = type_manager.types
@engine = new Engine @HB, type_manager.parser
@HB.engine = @engine # TODO: !! only for debugging
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
#first_word = new @types.XmlType(undefined, undefined, undefined, undefined, document.createElement("shared"))
#@HB.addOperation(first_word).execute()
uid_beg = @HB.getReservedUniqueIdentifier()
uid_end = @HB.getReservedUniqueIdentifier()
beg = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()
end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()
@root_element = new @types.ReplaceManager undefined, @HB.getReservedUniqueIdentifier(), beg, end
@HB.addOperation(@root_element).execute()
#@root_element.replace first_word
#
# @return JsonType
#
getSharedObject: ()->
@root_element.val()
#
# Get the initialized connector.
#
getConnector: ()->
@connector
#
# @see HistoryBuffer
#
getHistoryBuffer: ()->
@HB
#
# @see JsonType.setMutableDefault
#
setMutableDefault: (mutable)->
@getSharedObject().setMutableDefault(mutable)
#
# Get the UserId from the HistoryBuffer object.
# In most cases this will be the same as the user_id value with which
# JsonFramework was initialized (Depending on the HistoryBuffer implementation).
#
getUserId: ()->
@HB.getUserId()
#
# @see JsonType.toJson
#
toJson : ()->
@getSharedObject().toJson()
#
# @see JsonType.val
#
val : ()->
if (arguments.length is 0) or (typeof arguments[0] is "boolean")
@getSharedObject().val(arguments[0])
else if arguments.length is 1
newXml = new @types.XmlType(undefined, undefined, undefined, undefined, arguments[0])
@HB.addOperation(newXml).execute()
@root_element.replace newXml
newXml
else
throw new Error "can only parse 0, or 1 parameter!"
#
# @see Operation.on
#
on: ()->
@getSharedObject().on arguments...
module.exports = XmlFramework
if window?
if not window.Y?
window.Y = {}
window.Y.XmlFramework = XmlFramework

View File

@ -26,7 +26,7 @@ class HistoryBuffer
emptyGarbage: ()=>
for o in @garbage
#if @getOperationCounter(o.creator) > o.op_number
#if @getOperationCounter(o.uid.creator) > o.uid.op_number
o.cleanup?()
@garbage = @trash
@ -104,13 +104,13 @@ class HistoryBuffer
if o.next_cl? # applies for all ops but the most right delimiter!
# search for the next _known_ operation. (When state_vector is {} then this is the Delimiter)
o_next = o.next_cl
while o_next.next_cl? and unknown(o_next.creator, o_next.op_number)
while o_next.next_cl? and unknown(o_next.uid.creator, o_next.uid.op_number)
o_next = o_next.next_cl
o_json.next = o_next.getUid()
else if o.prev_cl? # most right delimiter only!
# same as the above with prev.
o_prev = o.prev_cl
while o_prev.prev_cl? and unknown(o_prev.creator, o_prev.op_number)
while o_prev.prev_cl? and unknown(o_prev.uid.creator, o_prev.uid.op_number)
o_prev = o_prev.prev_cl
o_json.prev = o_prev.getUid()
json.push o_json
@ -130,6 +130,7 @@ class HistoryBuffer
uid =
'creator' : user_id
'op_number' : @operation_counter[user_id]
'doSync' : true
@operation_counter[user_id]++
uid
@ -147,35 +148,35 @@ class HistoryBuffer
# other operations (it wont executed)
#
addOperation: (o)->
if not @buffer[o.creator]?
@buffer[o.creator] = {}
if @buffer[o.creator][o.op_number]?
if not @buffer[o.uid.creator]?
@buffer[o.uid.creator] = {}
if @buffer[o.uid.creator][o.uid.op_number]?
throw new Error "You must not overwrite operations!"
@buffer[o.creator][o.op_number] = o
@buffer[o.uid.creator][o.uid.op_number] = o
@number_of_operations_added_to_HB ?= 0 # TODO: Debug, remove this
@number_of_operations_added_to_HB++
o
removeOperation: (o)->
delete @buffer[o.creator]?[o.op_number]
delete @buffer[o.uid.creator]?[o.uid.op_number]
#
# 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()
if not @operation_counter[o.uid.creator]?
@operation_counter[o.uid.creator] = 0
if typeof o.uid.op_number is 'number' and o.uid.creator isnt @getUserId()
# TODO: fix this issue better.
# Operations should income in order
# Then you don't have to do this..
if o.op_number is @operation_counter[o.creator]
@operation_counter[o.creator]++
while @getOperation({creator:o.creator, op_number: @operation_counter[o.creator]})?
@operation_counter[o.creator]++
if o.uid.op_number is @operation_counter[o.uid.creator]
@operation_counter[o.uid.creator]++
while @getOperation({creator:o.uid.creator, op_number: @operation_counter[o.uid.creator]})?
@operation_counter[o.uid.creator]++
#if @operation_counter[o.creator] isnt (o.op_number + 1)
#console.log (@operation_counter[o.creator] - (o.op_number + 1))
#if @operation_counter[o.uid.creator] isnt (o.uid.op_number + 1)
#console.log (@operation_counter[o.uid.creator] - (o.uid.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,.. ;)"

View File

@ -19,22 +19,14 @@ module.exports = (HB)->
class Operation
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @see HistoryBuffer.getNextOperationIdentifier
# @param {Object} uid A unique identifier.
# If uid is undefined, a new uid will be created before at the end of the execution sequence
#
constructor: (uid)->
@is_deleted = false
@doSync = true
@garbage_collected = false
if not uid?
uid = HB.getNextOperationIdentifier()
if not uid.doSync?
uid.doSync = not isNaN(parseInt(uid.op_number))
{
'creator': @creator
'op_number' : @op_number
'doSync' : @doSync
} = uid
if uid?
@uid = uid
type: "Insert"
@ -123,20 +115,28 @@ module.exports = (HB)->
# Computes a unique identifier (uid) that identifies this operation.
#
getUid: ()->
{ 'creator': @creator, 'op_number': @op_number , 'sync': @doSync}
@uid
dontSync: ()->
@doSync = false
#
# @private
# If not already done, set the uid
# Add this to the HB
# Notify the all the listeners.
#
execute: ()->
@is_executed = true
if not @uid?
# When this operation was created without a uid, then set it here.
# There is only one other place, where this can be done - before an Insertion
# is executed (because we need the creator_id)
@uid = HB.getNextOperationIdentifier()
HB.addOperation @
for l in execution_listener
l @_encode()
@
@
#
# @private
@ -261,8 +261,6 @@ module.exports = (HB)->
# @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
@ -360,7 +358,7 @@ module.exports = (HB)->
# $o happened concurrently
if o.getDistanceToOrigin() is i
# case 1
if o.creator < @creator
if o.uid.creator < @uid.creator
@prev_cl = o
distance_to_origin = i + 1
else
@ -465,8 +463,6 @@ module.exports = (HB)->
# @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
@ -504,10 +500,10 @@ module.exports = (HB)->
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?
else if @prev_cl? or @next_cl? or true # TODO: are you sure? This can happen right?
super
else
throw new Error "Delimiter is unsufficient defined!"
#else
# throw new Error "Delimiter is unsufficient defined!"
#
# @private

View File

@ -98,19 +98,6 @@ module.exports = (HB)->
#
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
#
# Identifies this class.
# Use it to check whether this is a json-type or something else.
@ -158,7 +145,7 @@ module.exports = (HB)->
# this event is not created by Yatta.
that.val(event.name, event.object[event.name])
that.on 'change', (event_name, property_name, op)->
if this is that and op.creator isnt HB.getUserId()
if this is that and op.uid.creator isnt HB.getUserId()
notifier = Object.getNotifier(that.bound_json)
oldVal = that.bound_json[property_name]
if oldVal?
@ -170,7 +157,7 @@ module.exports = (HB)->
type: 'update'
name: property_name
oldValue: oldVal
changed_by: op.creator
changed_by: op.uid.creator
else
notifier.performChange 'add', ()->
that.bound_json[property_name] = that.val(property_name)
@ -180,7 +167,7 @@ module.exports = (HB)->
type: 'add'
name: property_name
oldValue: oldVal
changed_by: op.creator
changed_by: op.uid.creator
@bound_json
#
@ -236,11 +223,13 @@ module.exports = (HB)->
#
val: (name, content, mutable)->
if typeof name is 'object'
# Special case. First argument is an object. Then the second arg is mutable.
# Special case. First argument is an object. Then the second arg is mutable.
# (I refer to var name and content here)
# Keep that in mind when reading the following..
json = new JsonType undefined, name, content
HB.addOperation(json).execute()
@replace_manager.replace json
jt = new JsonType()
@replace_manager.replace jt.execute()
for n,o of name
jt.val n, o, mutable
@
else if name? and arguments.length > 1
if mutable?
@ -253,15 +242,16 @@ module.exports = (HB)->
if typeof content is 'function'
@ # Just do nothing
else if (not content?) or (((not mutable) or typeof content is 'number') and content.constructor isnt Object)
obj = HB.addOperation(new types.ImmutableObject undefined, content).execute()
super name, obj
super name, (new types.ImmutableObject undefined, content).execute()
else
if typeof content is 'string'
word = HB.addOperation(new types.WordType undefined).execute()
word = (new types.WordType undefined).execute()
word.insertText 0, content
super name, word
else if content.constructor is Object
json = HB.addOperation(new JsonType undefined, content, mutable).execute()
json = new JsonType().execute()
for n,o of content
json.val n, o, mutable
super name, json
else
throw new Error "You must not set #{typeof content}-types in collaborative Json-objects!"

View File

@ -34,7 +34,13 @@ module.exports = (HB)->
val: (name, content)->
if content?
if not @map[name]?
HB.addOperation(new AddName undefined, @, name).execute()
(new AddName undefined, @, name).execute()
## TODO: del this
if @map[name] == null
qqq = @
x = new AddName undefined, @, name
x.execute()
## endtodo
@map[name].replace content
@
else if name?
@ -88,16 +94,23 @@ module.exports = (HB)->
if not @validateSavedOperations()
return false
else
uid_r = @map_manager.getUid()
# helper for cloning an object
clone = (o)->
p = {}
for name,value of o
p[name] = value
p
uid_r = clone(@map_manager.getUid())
uid_r.doSync = false
uid_r.op_number = "_#{uid_r.op_number}_RM_#{@name}"
if not HB.getOperation(uid_r)?
uid_beg = @map_manager.getUid()
uid_beg = clone(uid_r)
uid_beg.op_number = "_#{uid_beg.op_number}_RM_#{@name}_beginning"
uid_end = @map_manager.getUid()
uid_end = clone(uid_r)
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()
@map_manager.map[@name] = HB.addOperation(new ReplaceManager undefined, uid_r, beg, end)
beg = (new types.Delimiter uid_beg, undefined, uid_end).execute()
end = (new types.Delimiter uid_end, beg, undefined).execute()
@map_manager.map[@name] = new ReplaceManager undefined, uid_r, beg, end
@map_manager.map[@name].setParent @map_manager, @name
(@map_manager.map[@name].add_name_ops ?= []).push @
@map_manager.map[@name].execute()
@ -138,8 +151,8 @@ module.exports = (HB)->
@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 = new types.Delimiter undefined, undefined, undefined
@end = new types.Delimiter undefined, @beginning, undefined
@beginning.next_cl = @end
@beginning.execute()
@end.execute()
@ -240,8 +253,7 @@ module.exports = (HB)->
#
replace: (content, replaceable_uid)->
o = @getLastOperation()
op = new Replaceable content, @, replaceable_uid, o, o.next_cl
HB.addOperation(op).execute()
(new Replaceable content, @, replaceable_uid, o, o.next_cl).execute()
undefined
#

View File

@ -23,7 +23,7 @@ module.exports = (HB)->
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
#
constructor: (content, uid, prev, next, origin)->
if content?.creator?
if content?.uid?.creator
@saveOperation 'content', content
else
@content = content
@ -140,13 +140,10 @@ module.exports = (HB)->
left = left.prev_cl # find the first character to the left, that is not deleted. Case position is 0, its the Delimiter.
right = left.next_cl
if content.type?
op = new TextInsert content, undefined, left, right
HB.addOperation(op).execute()
(new TextInsert content, undefined, left, right).execute()
else
for c in content
op = new TextInsert c, undefined, left, right
HB.addOperation(op).execute()
left = op
left = (new TextInsert c, undefined, left, right).execute()
@
#
# Inserts a string into the word.
@ -171,7 +168,7 @@ module.exports = (HB)->
for i in [0...length]
if o instanceof types.Delimiter
break
d = HB.addOperation(new TextDelete undefined, o).execute()
d = (new TextDelete undefined, o).execute()
o = o.next_cl
while not (o instanceof types.Delimiter) and o.isDeleted()
o = o.next_cl
@ -188,7 +185,7 @@ module.exports = (HB)->
# Can only be used if the ReplaceManager was set!
# @see WordType.setReplaceManager
if @replace_manager?
word = HB.addOperation(new WordType undefined).execute()
word = (new WordType undefined).execute()
word.insertText 0, text
@replace_manager.replace(word)
word

View File

@ -1,8 +1,8 @@
json_types_uninitialized = require "../Types/JsonTypes"
HistoryBuffer = require "../HistoryBuffer"
Engine = require "../Engine"
adaptConnector = require "../ConnectorAdapter"
json_types_uninitialized = require "./Types/JsonTypes"
HistoryBuffer = require "./HistoryBuffer"
Engine = require "./Engine"
adaptConnector = require "./ConnectorAdapter"
#
@ -12,29 +12,28 @@ adaptConnector = require "../ConnectorAdapter"
# * Integer
# * Array
#
class JsonFramework
class Yatta
#
# @param {String} user_id Unique id of the peer.
# @param {Connector} Connector the connector class.
#
constructor: (user_id, @connector)->
constructor: (@connector)->
user_id = @connector.id # TODO: change to getUniqueId()
@HB = new HistoryBuffer user_id
type_manager = json_types_uninitialized @HB
@types = type_manager.types
@engine = new Engine @HB, type_manager.parser
@HB.engine = @engine # TODO: !! only for debugging
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
first_word = new @types.JsonType(@HB.getReservedUniqueIdentifier())
@HB.addOperation(first_word).execute()
first_word = new @types.JsonType(@HB.getReservedUniqueIdentifier()).execute()
uid_beg = @HB.getReservedUniqueIdentifier()
uid_end = @HB.getReservedUniqueIdentifier()
beg = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()
end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()
beg = (new @types.Delimiter uid_beg, undefined, uid_end).execute()
end = (new @types.Delimiter uid_end, beg, undefined).execute()
@root_element = new @types.ReplaceManager undefined, @HB.getReservedUniqueIdentifier(), beg, end
@HB.addOperation(@root_element).execute()
@root_element = (new @types.ReplaceManager undefined, @HB.getReservedUniqueIdentifier(), beg, end).execute()
@root_element.replace first_word, @HB.getReservedUniqueIdentifier()
#
@ -64,7 +63,7 @@ class JsonFramework
#
# Get the UserId from the HistoryBuffer object.
# In most cases this will be the same as the user_id value with which
# JsonFramework was initialized (Depending on the HistoryBuffer implementation).
# Yatta was initialized (Depending on the HistoryBuffer implementation).
#
getUserId: ()->
@HB.getUserId()
@ -96,7 +95,7 @@ class JsonFramework
#
# @see JsonType.value
#
Object.defineProperty JsonFramework.prototype, 'value',
Object.defineProperty Yatta.prototype, 'value',
get : -> @getSharedObject().value
set : (o)->
if o.constructor is {}.constructor
@ -105,8 +104,6 @@ class JsonFramework
else
throw new Error "You must only set Object values!"
module.exports = JsonFramework
if window?
if not window.Y?
window.Y = {}
window.Y.JsonFramework = JsonFramework
module.exports = Yatta
if window? and not window.Yatta?
window.Yatta = Yatta

View File

@ -1,8 +0,0 @@
exports['JsonFramework'] =
require './Frameworks/JsonFramework'
exports['TextFramework'] =
require './Frameworks/TextFramework'
exports['XmlFramework'] =
require './Frameworks/XmlFramework'

View File

@ -7,14 +7,14 @@ _ = require("underscore")
chai.use(sinonChai)
Y = require "../lib/index"
Connector = require "../bower_components/connector/lib/test-connector/test-connector.coffee"
Yatta = require "../lib/Yatta.coffee"
Test = require "./TestSuite"
class JsonTest extends Test
makeNewUser: (user, conn)->
super new Y.JsonFramework user, conn
super new Yatta conn
type: "JsonTest"

View File

@ -7,7 +7,6 @@ _ = require("underscore")
chai.use(sinonChai)
Y = require "../lib/index"
Connector = require "../bower_components/connector/lib/test-connector/test-connector.coffee"
module.exports = class Test

1
yatta.js Normal file

File diff suppressed because one or more lines are too long