added tests for observer types
This commit is contained in:
parent
2f47ad9e3a
commit
fd1128d456
README.md
build
doc
lib/Types
test
yatta.js
13
README.md
13
README.md
@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
# 
|
# 
|
||||||
|
|
||||||
A Real-Time web framework that manages concurrency control for arbitrary data structures.
|
A Real-Time web framework that manages concurrency control for arbitrary data types.
|
||||||
Yatta! provides similar functionality as [ShareJs](https://github.com/share/ShareJS) and [OpenCoweb](https://github.com/opencoweb/coweb),
|
Yatta! provides similar functionality as [ShareJs](https://github.com/share/ShareJS) and [OpenCoweb](https://github.com/opencoweb/coweb),
|
||||||
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.
|
but does not require you to understand how the internals work. The predefined data types provide a simple API to access your shared data types.
|
||||||
|
|
||||||
Predefined data structures:
|
Predefined data types:
|
||||||
* Text - [Collaborative Text Editing Example](http://dadamonad.github.io/Yatta/examples/TextEditing/)
|
* Text - [Collaborative Text Editing Example](http://dadamonad.github.io/Yatta/examples/TextEditing/)
|
||||||
* Json - [Tutorial](http://dadamonad.github.io/Yatta/examples/PeerJs-Json/)
|
* Json - [Tutorial](http://dadamonad.github.io/Yatta/examples/PeerJs-Json/)
|
||||||
* XML - [XML Example](http://dadamonad.github.io/Yatta/examples/XmlExample/) Collaboratively manipulate the dom with native dom-features and jQuery.
|
* XML - [XML Example](http://dadamonad.github.io/Yatta/examples/XmlExample/) Collaboratively manipulate the dom with native dom-features and jQuery.
|
||||||
@ -27,6 +27,9 @@ Either clone this git repository, install it with [bower](http://bower.io/), or
|
|||||||
bower install Yatta
|
bower install Yatta
|
||||||
```
|
```
|
||||||
Then you include the libraries directly from the installation folder.
|
Then you include the libraries directly from the installation folder.
|
||||||
|
```
|
||||||
|
<script src="./bower_components/yatta.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
### Npm
|
### Npm
|
||||||
```
|
```
|
||||||
@ -35,9 +38,7 @@ npm install yatta --save
|
|||||||
|
|
||||||
And use it like this with *npm*:
|
And use it like this with *npm*:
|
||||||
```
|
```
|
||||||
Y = require("yatta");
|
Yatta = require("yatta");
|
||||||
Y.createPeerJsConnector({key: 'xxx'}, function(Connector, user_id){
|
|
||||||
yatta = new Y.JsonFramework(user_id, Connector);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -24,7 +24,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Operation.prototype.unobserve = function(f) {
|
Operation.prototype.unobserve = function(f) {
|
||||||
return this.event_listeners.filter(function(g) {
|
return this.event_listeners = this.event_listeners.filter(function(g) {
|
||||||
return f !== g;
|
return f !== g;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -156,9 +156,13 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Delete.prototype.execute = function() {
|
Delete.prototype.execute = function() {
|
||||||
|
var res;
|
||||||
if (this.validateSavedOperations()) {
|
if (this.validateSavedOperations()) {
|
||||||
this.deletes.applyDelete(this);
|
res = Delete.__super__.execute.apply(this, arguments);
|
||||||
return Delete.__super__.execute.apply(this, arguments);
|
if (res) {
|
||||||
|
this.deletes.applyDelete(this);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -307,7 +311,8 @@
|
|||||||
type: "insert",
|
type: "insert",
|
||||||
position: this.getPosition(),
|
position: this.getPosition(),
|
||||||
object: this.parent,
|
object: this.parent,
|
||||||
changed_by: this.uid.creator
|
changed_by: this.uid.creator,
|
||||||
|
value: this.content
|
||||||
}
|
}
|
||||||
]) : void 0;
|
]) : void 0;
|
||||||
};
|
};
|
||||||
|
File diff suppressed because one or more lines are too long
@ -195,22 +195,21 @@
|
|||||||
|
|
||||||
ListManager.prototype.getOperationByPosition = function(position) {
|
ListManager.prototype.getOperationByPosition = function(position) {
|
||||||
var o;
|
var o;
|
||||||
o = this.beginning.next_cl;
|
o = this.beginning;
|
||||||
if ((position > 0 || o.isDeleted()) && !(o instanceof types.Delimiter)) {
|
while (true) {
|
||||||
while (o.isDeleted() && !(o instanceof types.Delimiter)) {
|
if (o instanceof types.Delimiter && (o.prev_cl != null)) {
|
||||||
o = o.next_cl;
|
o = o.prev_cl;
|
||||||
|
while (o.isDeleted() || !(o instanceof types.Delimiter)) {
|
||||||
|
o = o.prev_cl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
while (true) {
|
if (position <= 0 && !o.isDeleted()) {
|
||||||
if (o instanceof types.Delimiter) {
|
break;
|
||||||
break;
|
}
|
||||||
}
|
o = o.next_cl;
|
||||||
if (position <= 0 && !o.isDeleted()) {
|
if (!o.isDeleted()) {
|
||||||
break;
|
position -= 1;
|
||||||
}
|
|
||||||
o = o.next_cl;
|
|
||||||
if (!o.isDeleted()) {
|
|
||||||
position -= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -147,15 +147,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
WordType.prototype.insertText = function(position, content) {
|
WordType.prototype.insertText = function(position, content) {
|
||||||
var ith, left;
|
var ith;
|
||||||
ith = this.getOperationByPosition(position);
|
ith = this.getOperationByPosition(position);
|
||||||
left = ith.prev_cl;
|
return this.insertAfter(ith, content);
|
||||||
return this.insertAfter(left, content);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WordType.prototype.deleteText = function(position, length) {
|
WordType.prototype.deleteText = function(position, length) {
|
||||||
var d, delete_ops, i, o, _i;
|
var d, delete_ops, i, o, _i;
|
||||||
o = this.getOperationByPosition(position);
|
o = this.getOperationByPosition(position + 1);
|
||||||
delete_ops = [];
|
delete_ops = [];
|
||||||
for (i = _i = 0; 0 <= length ? _i < length : _i > length; i = 0 <= length ? ++_i : --_i) {
|
for (i = _i = 0; 0 <= length ? _i < length : _i > length; i = 0 <= length ? ++_i : --_i) {
|
||||||
if (o instanceof types.Delimiter) {
|
if (o instanceof types.Delimiter) {
|
||||||
|
File diff suppressed because one or more lines are too long
@ -42,7 +42,7 @@
|
|||||||
module.exports = createYatta;
|
module.exports = createYatta;
|
||||||
|
|
||||||
if ((typeof window !== "undefined" && window !== null) && (window.Yatta == null)) {
|
if ((typeof window !== "undefined" && window !== null) && (window.Yatta == null)) {
|
||||||
window.Yatta = Yatta;
|
window.Yatta = createYatta;
|
||||||
}
|
}
|
||||||
|
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
@ -1 +1 @@
|
|||||||
{"version":3,"sources":["Yatta.coffee"],"names":[],"mappings":"AACA;AAAA,MAAA,4EAAA;IAAA;mSAAA;;AAAA,EAAA,wBAAA,GAA2B,OAAA,CAAQ,mBAAR,CAA3B,CAAA;;AAAA,EACA,aAAA,GAAgB,OAAA,CAAQ,iBAAR,CADhB,CAAA;;AAAA,EAEA,MAAA,GAAS,OAAA,CAAQ,UAAR,CAFT,CAAA;;AAAA,EAGA,cAAA,GAAiB,OAAA,CAAQ,oBAAR,CAHjB,CAAA;;AAAA,EAKA,WAAA,GAAc,SAAC,SAAD,GAAA;AACZ,QAAA,uCAAA;AAAA,IAAA,OAAA,GAAU,SAAS,CAAC,EAApB,CAAA;AAAA,IACA,EAAA,GAAS,IAAA,aAAA,CAAc,OAAd,CADT,CAAA;AAAA,IAEA,YAAA,GAAe,wBAAA,CAAyB,EAAzB,CAFf,CAAA;AAAA,IAGA,KAAA,GAAQ,YAAY,CAAC,KAHrB,CAAA;AAAA,IAYM;AAMJ,8BAAA,CAAA;;AAAa,MAAA,eAAA,GAAA;AACX,QAAA,IAAC,CAAA,SAAD,GAAa,SAAb,CAAA;AAAA,QACA,IAAC,CAAA,EAAD,GAAM,EADN,CAAA;AAAA,QAEA,IAAC,CAAA,KAAD,GAAS,KAFT,CAAA;AAAA,QAGA,IAAC,CAAA,MAAD,GAAc,IAAA,MAAA,CAAO,IAAC,CAAA,EAAR,EAAY,YAAY,CAAC,MAAzB,CAHd,CAAA;AAAA,QAIA,cAAA,CAAe,IAAC,CAAA,SAAhB,EAA2B,IAAC,CAAA,MAA5B,EAAoC,IAAC,CAAA,EAArC,EAAyC,YAAY,CAAC,kBAAtD,CAJA,CAAA;AAAA,QAKA,wCAAA,SAAA,CALA,CADW;MAAA,CAAb;;AAAA,sBAQA,YAAA,GAAc,SAAA,GAAA;eACZ,IAAC,CAAA,UADW;MAAA,CARd,CAAA;;mBAAA;;OANkB,KAAK,CAAC,SAZ1B,CAAA;AA6BA,WAAW,IAAA,KAAA,CAAM,EAAE,CAAC,2BAAH,CAAA,CAAN,CAAuC,CAAC,OAAxC,CAAA,CAAX,CA9BY;EAAA,CALd,CAAA;;AAAA,EAqCA,MAAM,CAAC,OAAP,GAAiB,WArCjB,CAAA;;AAsCA,EAAA,IAAG,kDAAA,IAAgB,sBAAnB;AACE,IAAA,MAAM,CAAC,KAAP,GAAe,KAAf,CADF;GAtCA;AAAA","file":"Yatta.js","sourceRoot":"/source/","sourcesContent":["\njson_types_uninitialized = require \"./Types/JsonTypes\"\nHistoryBuffer = require \"./HistoryBuffer\"\nEngine = require \"./Engine\"\nadaptConnector = require \"./ConnectorAdapter\"\n\ncreateYatta = (connector)->\n user_id = connector.id # TODO: change to getUniqueId()\n HB = new HistoryBuffer user_id\n type_manager = json_types_uninitialized HB\n types = type_manager.types\n\n #\n # Framework for Json data-structures.\n # Known values that are supported:\n # * String\n # * Integer\n # * Array\n #\n class Yatta extends types.JsonType\n\n #\n # @param {String} user_id Unique id of the peer.\n # @param {Connector} Connector the connector class.\n #\n constructor: ()->\n @connector = connector\n @HB = HB\n @types = types\n @engine = new Engine @HB, type_manager.parser\n adaptConnector @connector, @engine, @HB, type_manager.execution_listener\n super\n\n getConnector: ()->\n @connector\n\n return new Yatta(HB.getReservedUniqueIdentifier()).execute()\n\nmodule.exports = createYatta\nif window? and not window.Yatta?\n window.Yatta = Yatta\n"]}
|
{"version":3,"sources":["Yatta.coffee"],"names":[],"mappings":"AACA;AAAA,MAAA,4EAAA;IAAA;mSAAA;;AAAA,EAAA,wBAAA,GAA2B,OAAA,CAAQ,mBAAR,CAA3B,CAAA;;AAAA,EACA,aAAA,GAAgB,OAAA,CAAQ,iBAAR,CADhB,CAAA;;AAAA,EAEA,MAAA,GAAS,OAAA,CAAQ,UAAR,CAFT,CAAA;;AAAA,EAGA,cAAA,GAAiB,OAAA,CAAQ,oBAAR,CAHjB,CAAA;;AAAA,EAKA,WAAA,GAAc,SAAC,SAAD,GAAA;AACZ,QAAA,uCAAA;AAAA,IAAA,OAAA,GAAU,SAAS,CAAC,EAApB,CAAA;AAAA,IACA,EAAA,GAAS,IAAA,aAAA,CAAc,OAAd,CADT,CAAA;AAAA,IAEA,YAAA,GAAe,wBAAA,CAAyB,EAAzB,CAFf,CAAA;AAAA,IAGA,KAAA,GAAQ,YAAY,CAAC,KAHrB,CAAA;AAAA,IAYM;AAMJ,8BAAA,CAAA;;AAAa,MAAA,eAAA,GAAA;AACX,QAAA,IAAC,CAAA,SAAD,GAAa,SAAb,CAAA;AAAA,QACA,IAAC,CAAA,EAAD,GAAM,EADN,CAAA;AAAA,QAEA,IAAC,CAAA,KAAD,GAAS,KAFT,CAAA;AAAA,QAGA,IAAC,CAAA,MAAD,GAAc,IAAA,MAAA,CAAO,IAAC,CAAA,EAAR,EAAY,YAAY,CAAC,MAAzB,CAHd,CAAA;AAAA,QAIA,cAAA,CAAe,IAAC,CAAA,SAAhB,EAA2B,IAAC,CAAA,MAA5B,EAAoC,IAAC,CAAA,EAArC,EAAyC,YAAY,CAAC,kBAAtD,CAJA,CAAA;AAAA,QAKA,wCAAA,SAAA,CALA,CADW;MAAA,CAAb;;AAAA,sBAQA,YAAA,GAAc,SAAA,GAAA;eACZ,IAAC,CAAA,UADW;MAAA,CARd,CAAA;;mBAAA;;OANkB,KAAK,CAAC,SAZ1B,CAAA;AA6BA,WAAW,IAAA,KAAA,CAAM,EAAE,CAAC,2BAAH,CAAA,CAAN,CAAuC,CAAC,OAAxC,CAAA,CAAX,CA9BY;EAAA,CALd,CAAA;;AAAA,EAqCA,MAAM,CAAC,OAAP,GAAiB,WArCjB,CAAA;;AAsCA,EAAA,IAAG,kDAAA,IAAgB,sBAAnB;AACE,IAAA,MAAM,CAAC,KAAP,GAAe,WAAf,CADF;GAtCA;AAAA","file":"Yatta.js","sourceRoot":"/source/","sourcesContent":["\njson_types_uninitialized = require \"./Types/JsonTypes\"\nHistoryBuffer = require \"./HistoryBuffer\"\nEngine = require \"./Engine\"\nadaptConnector = require \"./ConnectorAdapter\"\n\ncreateYatta = (connector)->\n user_id = connector.id # TODO: change to getUniqueId()\n HB = new HistoryBuffer user_id\n type_manager = json_types_uninitialized HB\n types = type_manager.types\n\n #\n # Framework for Json data-structures.\n # Known values that are supported:\n # * String\n # * Integer\n # * Array\n #\n class Yatta extends types.JsonType\n\n #\n # @param {String} user_id Unique id of the peer.\n # @param {Connector} Connector the connector class.\n #\n constructor: ()->\n @connector = connector\n @HB = HB\n @types = types\n @engine = new Engine @HB, type_manager.parser\n adaptConnector @connector, @engine, @HB, type_manager.execution_listener\n super\n\n getConnector: ()->\n @connector\n\n return new Yatta(HB.getReservedUniqueIdentifier()).execute()\n\nmodule.exports = createYatta\nif window? and not window.Yatta?\n window.Yatta = createYatta\n"]}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -178,7 +178,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -359,7 +359,7 @@ E.g.: let x = {a:[]}. Then x.a.push 1 wouldn't change anything</p>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -139,7 +139,7 @@ console.log(w.newProperty == "Awesome") # true!</code></pre>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -389,7 +389,7 @@ yatta.bind(textbox);</code></pre>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -115,7 +115,7 @@ Known values that are supported:</p><ul>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -76,7 +76,7 @@ But I would become really motivated if you gave me some feedback :) (<a href="ht
|
|||||||
</ul>
|
</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>!
|
<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,
|
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't support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="mailto:kevin.jahns@rwth-aachen.de">kevin.jahns@rwth-aachen.de</a>
|
please state function name, and sample parameters. However, there are browser-specific features, that Yatta won't support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="mailto:kevin.jahns@rwth-aachen.de">kevin.jahns@rwth-aachen.de</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ please state function name, and sample parameters. However, there are browser-sp
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='footer'>
|
<div id='footer'>
|
||||||
December 22, 14 14:36:45 by
|
December 23, 14 11:09:09 by
|
||||||
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
<a href='https://github.com/coffeedoc/codo' title='CoffeeScript API documentation generator'>
|
||||||
Codo
|
Codo
|
||||||
</a>
|
</a>
|
||||||
|
@ -277,12 +277,7 @@ module.exports = (HB)->
|
|||||||
garbagecollect = true
|
garbagecollect = true
|
||||||
super garbagecollect
|
super garbagecollect
|
||||||
if callLater
|
if callLater
|
||||||
@parent.callEvent [
|
@callOperationSpecificDeleteEvents(o)
|
||||||
type: "insert"
|
|
||||||
position: @getPosition()
|
|
||||||
object: @parent # TODO: You can combine getPosition + getParent in a more efficient manner! (only left Delimiter will hold @parent)
|
|
||||||
changed_by: o.uid.creator
|
|
||||||
]
|
|
||||||
if @next_cl?.isDeleted()
|
if @next_cl?.isDeleted()
|
||||||
# garbage collect next_cl
|
# garbage collect next_cl
|
||||||
@next_cl.applyDelete()
|
@next_cl.applyDelete()
|
||||||
@ -378,18 +373,27 @@ module.exports = (HB)->
|
|||||||
|
|
||||||
@setParent @prev_cl.getParent() # do Insertions always have a parent?
|
@setParent @prev_cl.getParent() # do Insertions always have a parent?
|
||||||
super # notify the execution_listeners
|
super # notify the execution_listeners
|
||||||
@callOperationSpecificEvents()
|
@callOperationSpecificInsertEvents()
|
||||||
@
|
@
|
||||||
|
|
||||||
callOperationSpecificEvents: ()->
|
callOperationSpecificInsertEvents: ()->
|
||||||
@parent?.callEvent [
|
@parent?.callEvent [
|
||||||
type: "insert"
|
type: "insert"
|
||||||
position: @getPosition()
|
position: @getPosition()
|
||||||
object: @parent
|
object: @parent
|
||||||
changed_by: @uid.creator
|
changedBy: @uid.creator
|
||||||
value: @content
|
value: @content
|
||||||
]
|
]
|
||||||
|
|
||||||
|
callOperationSpecificDeleteEvents: (o)->
|
||||||
|
@parent.callEvent [
|
||||||
|
type: "delete"
|
||||||
|
position: @getPosition()
|
||||||
|
object: @parent # TODO: You can combine getPosition + getParent in a more efficient manner! (only left Delimiter will hold @parent)
|
||||||
|
length: 1
|
||||||
|
changedBy: o.uid.creator
|
||||||
|
]
|
||||||
|
|
||||||
#
|
#
|
||||||
# Compute the position of this operation.
|
# Compute the position of this operation.
|
||||||
#
|
#
|
||||||
|
@ -145,7 +145,7 @@ module.exports = (HB)->
|
|||||||
that = @
|
that = @
|
||||||
Object.observe @bound_json, (events)->
|
Object.observe @bound_json, (events)->
|
||||||
for event in events
|
for event in events
|
||||||
if not event.changed_by? and (event.type is "add" or event.type = "update")
|
if not event.changedBy? and (event.type is "add" or event.type = "update")
|
||||||
# this event is not created by Yatta.
|
# this event is not created by Yatta.
|
||||||
that.val(event.name, event.object[event.name])
|
that.val(event.name, event.object[event.name])
|
||||||
@observe (events)->
|
@observe (events)->
|
||||||
@ -162,7 +162,7 @@ module.exports = (HB)->
|
|||||||
type: 'update'
|
type: 'update'
|
||||||
name: event.name
|
name: event.name
|
||||||
oldValue: oldVal
|
oldValue: oldVal
|
||||||
changed_by: event.changed_by
|
changedBy: event.changedBy
|
||||||
else
|
else
|
||||||
notifier.performChange 'add', ()->
|
notifier.performChange 'add', ()->
|
||||||
that.bound_json[event.name] = that.val(event.name)
|
that.bound_json[event.name] = that.val(event.name)
|
||||||
@ -172,7 +172,7 @@ module.exports = (HB)->
|
|||||||
type: 'add'
|
type: 'add'
|
||||||
name: event.name
|
name: event.name
|
||||||
oldValue: oldVal
|
oldValue: oldVal
|
||||||
changed_by:event.changed_by
|
changedBy:event.changedBy
|
||||||
@bound_json
|
@bound_json
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -35,29 +35,31 @@ module.exports = (HB)->
|
|||||||
if content?
|
if content?
|
||||||
if not @map[name]?
|
if not @map[name]?
|
||||||
(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
|
@map[name].replace content
|
||||||
@
|
@
|
||||||
else if name?
|
else if name?
|
||||||
obj = @map[name]?.val()
|
prop = @map[name]
|
||||||
if obj instanceof types.ImmutableObject
|
if prop? and not prop.isContentDeleted()
|
||||||
obj.val()
|
obj = prop.val()
|
||||||
|
if obj instanceof types.ImmutableObject
|
||||||
|
obj.val()
|
||||||
|
else
|
||||||
|
obj
|
||||||
else
|
else
|
||||||
obj
|
undefined
|
||||||
else
|
else
|
||||||
result = {}
|
result = {}
|
||||||
for name,o of @map
|
for name,o of @map
|
||||||
obj = o.val()
|
if not o.isContentDeleted()
|
||||||
if obj instanceof types.ImmutableObject or obj instanceof MapManager
|
obj = o.val()
|
||||||
obj = obj.val()
|
if obj instanceof types.ImmutableObject or obj instanceof MapManager
|
||||||
result[name] = obj
|
obj = obj.val()
|
||||||
|
result[name] = obj
|
||||||
result
|
result
|
||||||
|
|
||||||
|
delete: (name)->
|
||||||
|
@map[name]?.deleteContent()
|
||||||
|
@
|
||||||
#
|
#
|
||||||
# @nodoc
|
# @nodoc
|
||||||
# When a new property in a map manager is created, then the uids of the inserted Operations
|
# When a new property in a map manager is created, then the uids of the inserted Operations
|
||||||
@ -234,7 +236,9 @@ module.exports = (HB)->
|
|||||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||||
# @param {Delimiter} beginning Reference or Object.
|
# @param {Delimiter} beginning Reference or Object.
|
||||||
# @param {Delimiter} end Reference or Object.
|
# @param {Delimiter} end Reference or Object.
|
||||||
constructor: (@event_porperties, @event_this, uid, beginning, end, prev, next, origin)->
|
constructor: (@event_properties, @event_this, uid, beginning, end, prev, next, origin)->
|
||||||
|
if not @event_properties['object']?
|
||||||
|
@event_properties['object'] = @event_this
|
||||||
super uid, beginning, end, prev, next, origin
|
super uid, beginning, end, prev, next, origin
|
||||||
|
|
||||||
type: "ReplaceManager"
|
type: "ReplaceManager"
|
||||||
@ -262,8 +266,8 @@ module.exports = (HB)->
|
|||||||
#
|
#
|
||||||
callEventDecorator: (events)->
|
callEventDecorator: (events)->
|
||||||
if not @isDeleted()
|
if not @isDeleted()
|
||||||
for name,prop of @event_porperties
|
for event in events
|
||||||
for event in events
|
for name,prop of @event_properties
|
||||||
event[name] = prop
|
event[name] = prop
|
||||||
@event_this.callEvent events
|
@event_this.callEvent events
|
||||||
undefined
|
undefined
|
||||||
@ -276,7 +280,15 @@ module.exports = (HB)->
|
|||||||
#
|
#
|
||||||
replace: (content, replaceable_uid)->
|
replace: (content, replaceable_uid)->
|
||||||
o = @getLastOperation()
|
o = @getLastOperation()
|
||||||
(new Replaceable content, @, replaceable_uid, o, o.next_cl).execute()
|
relp = (new Replaceable content, @, replaceable_uid, o, o.next_cl).execute()
|
||||||
|
# TODO: delete repl (for debugging)
|
||||||
|
undefined
|
||||||
|
|
||||||
|
isContentDeleted: ()->
|
||||||
|
@getLastOperation().isDeleted()
|
||||||
|
|
||||||
|
deleteContent: ()->
|
||||||
|
(new types.Delete undefined, @getLastOperation().uid).execute()
|
||||||
undefined
|
undefined
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -347,13 +359,14 @@ module.exports = (HB)->
|
|||||||
@content
|
@content
|
||||||
|
|
||||||
applyDelete: ()->
|
applyDelete: ()->
|
||||||
|
res = super
|
||||||
if @content?
|
if @content?
|
||||||
if @next_cl.type isnt "Delimiter"
|
if @next_cl.type isnt "Delimiter"
|
||||||
@content.deleteAllObservers()
|
@content.deleteAllObservers()
|
||||||
@content.applyDelete()
|
@content.applyDelete()
|
||||||
@content.dontSync()
|
@content.dontSync()
|
||||||
@content = null
|
@content = null
|
||||||
super
|
res
|
||||||
|
|
||||||
cleanup: ()->
|
cleanup: ()->
|
||||||
super
|
super
|
||||||
@ -363,27 +376,35 @@ module.exports = (HB)->
|
|||||||
# TODO: consider doing this in a more consistent manner. This could also be
|
# TODO: consider doing this in a more consistent manner. This could also be
|
||||||
# done with execute. But currently, there are no specital Insert-types for ListManager.
|
# done with execute. But currently, there are no specital Insert-types for ListManager.
|
||||||
#
|
#
|
||||||
callOperationSpecificEvents: ()->
|
callOperationSpecificInsertEvents: ()->
|
||||||
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
|
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
|
||||||
# this replaces another Replaceable
|
# this replaces another Replaceable
|
||||||
old_value = @prev_cl.content
|
old_value = @prev_cl.content
|
||||||
@prev_cl.applyDelete()
|
|
||||||
@parent.callEventDecorator [
|
@parent.callEventDecorator [
|
||||||
type: "update"
|
type: "update"
|
||||||
changed_by: @uid.creator
|
changedBy: @uid.creator
|
||||||
oldValue: old_value
|
oldValue: old_value
|
||||||
]
|
]
|
||||||
|
@prev_cl.applyDelete()
|
||||||
else if @next_cl.type isnt "Delimiter"
|
else if @next_cl.type isnt "Delimiter"
|
||||||
# This will never be recognized by the user, because another
|
# This won't be recognized by the user, because another
|
||||||
# concurrent operation is set as the current value of the RM
|
# concurrent operation is set as the current value of the RM
|
||||||
@applyDelete()
|
@applyDelete()
|
||||||
else # prev _and_ next are Delimiters. This is the first created Replaceable in the RM
|
else # prev _and_ next are Delimiters. This is the first created Replaceable in the RM
|
||||||
@parent.callEventDecorator [
|
@parent.callEventDecorator [
|
||||||
type: "add"
|
type: "add"
|
||||||
changed_by: @uid.creator
|
changedBy: @uid.creator
|
||||||
]
|
]
|
||||||
undefined
|
undefined
|
||||||
|
|
||||||
|
callOperationSpecificDeleteEvents: (o)->
|
||||||
|
if @next_cl.type is "Delimiter"
|
||||||
|
@parent.callEventDecorator [
|
||||||
|
type: "delete"
|
||||||
|
changedBy: o.uid.creator
|
||||||
|
oldValue: @content
|
||||||
|
]
|
||||||
|
|
||||||
#
|
#
|
||||||
# Encode this operation in such a way that it can be parsed by remote peers.
|
# Encode this operation in such a way that it can be parsed by remote peers.
|
||||||
#
|
#
|
||||||
|
@ -161,3 +161,106 @@ describe "JsonFramework", ->
|
|||||||
expect(@yTest.getSomeUser().val('null') is null).to.be.ok
|
expect(@yTest.getSomeUser().val('null') is null).to.be.ok
|
||||||
|
|
||||||
|
|
||||||
|
it "Observers work on JSON Types (add type observers, local and foreign)", ->
|
||||||
|
u = @yTest.users[0]
|
||||||
|
@yTest.flushAll()
|
||||||
|
last_task = null
|
||||||
|
observer1 = (changes)->
|
||||||
|
expect(changes.length).to.equal(1)
|
||||||
|
change = changes[0]
|
||||||
|
expect(change.type).to.equal("add")
|
||||||
|
expect(change.object).to.equal(u)
|
||||||
|
expect(change.changedBy).to.equal('0')
|
||||||
|
expect(change.name).to.equal("newStuff")
|
||||||
|
last_task = "observer1"
|
||||||
|
u.observe observer1
|
||||||
|
u.val("newStuff","someStuff")
|
||||||
|
expect(last_task).to.equal("observer1")
|
||||||
|
u.unobserve observer1
|
||||||
|
|
||||||
|
observer2 = (changes)->
|
||||||
|
expect(changes.length).to.equal(1)
|
||||||
|
change = changes[0]
|
||||||
|
expect(change.type).to.equal("add")
|
||||||
|
expect(change.object).to.equal(u)
|
||||||
|
expect(change.changedBy).to.equal('1')
|
||||||
|
expect(change.name).to.equal("moreStuff")
|
||||||
|
last_task = "observer2"
|
||||||
|
u.observe observer2
|
||||||
|
v = @yTest.users[1]
|
||||||
|
v.val("moreStuff","someMoreStuff")
|
||||||
|
@yTest.flushAll()
|
||||||
|
expect(last_task).to.equal("observer2")
|
||||||
|
u.unobserve observer2
|
||||||
|
|
||||||
|
it "Observers work on JSON Types (update type observers, local and foreign)", ->
|
||||||
|
u = @yTest.users[0].val("newStuff","oldStuff").val("moreStuff","moreOldStuff")
|
||||||
|
@yTest.flushAll()
|
||||||
|
last_task = null
|
||||||
|
observer1 = (changes)->
|
||||||
|
expect(changes.length).to.equal(1)
|
||||||
|
change = changes[0]
|
||||||
|
expect(change.type).to.equal("update")
|
||||||
|
expect(change.object).to.equal(u)
|
||||||
|
expect(change.changedBy).to.equal('0')
|
||||||
|
expect(change.name).to.equal("newStuff")
|
||||||
|
expect(change.oldValue.val()).to.equal("oldStuff")
|
||||||
|
last_task = "observer1"
|
||||||
|
u.observe observer1
|
||||||
|
u.val("newStuff","someStuff")
|
||||||
|
expect(last_task).to.equal("observer1")
|
||||||
|
u.unobserve observer1
|
||||||
|
|
||||||
|
observer2 = (changes)->
|
||||||
|
expect(changes.length).to.equal(1)
|
||||||
|
change = changes[0]
|
||||||
|
expect(change.type).to.equal("update")
|
||||||
|
expect(change.object).to.equal(u)
|
||||||
|
expect(change.changedBy).to.equal('1')
|
||||||
|
expect(change.name).to.equal("moreStuff")
|
||||||
|
expect(change.oldValue.val()).to.equal("moreOldStuff")
|
||||||
|
last_task = "observer2"
|
||||||
|
u.observe observer2
|
||||||
|
v = @yTest.users[1]
|
||||||
|
v.val("moreStuff","someMoreStuff")
|
||||||
|
@yTest.flushAll()
|
||||||
|
expect(last_task).to.equal("observer2")
|
||||||
|
u.unobserve observer2
|
||||||
|
|
||||||
|
|
||||||
|
it "Observers work on JSON Types (delete type observers, local and foreign)", ->
|
||||||
|
u = @yTest.users[0].val("newStuff","oldStuff").val("moreStuff","moreOldStuff")
|
||||||
|
@yTest.flushAll()
|
||||||
|
last_task = null
|
||||||
|
observer1 = (changes)->
|
||||||
|
expect(changes.length).to.equal(1)
|
||||||
|
change = changes[0]
|
||||||
|
expect(change.type).to.equal("delete")
|
||||||
|
expect(change.object).to.equal(u)
|
||||||
|
expect(change.changedBy).to.equal('0')
|
||||||
|
expect(change.name).to.equal("newStuff")
|
||||||
|
expect(change.oldValue.val()).to.equal("oldStuff")
|
||||||
|
last_task = "observer1"
|
||||||
|
u.observe observer1
|
||||||
|
u.delete("newStuff")
|
||||||
|
expect(last_task).to.equal("observer1")
|
||||||
|
u.unobserve observer1
|
||||||
|
|
||||||
|
observer2 = (changes)->
|
||||||
|
expect(changes.length).to.equal(1)
|
||||||
|
change = changes[0]
|
||||||
|
expect(change.type).to.equal("delete")
|
||||||
|
expect(change.object).to.equal(u)
|
||||||
|
expect(change.changedBy).to.equal('1')
|
||||||
|
expect(change.name).to.equal("moreStuff")
|
||||||
|
expect(change.oldValue.val()).to.equal("moreOldStuff")
|
||||||
|
last_task = "observer2"
|
||||||
|
u.observe observer2
|
||||||
|
v = @yTest.users[1]
|
||||||
|
v.delete("moreStuff")
|
||||||
|
@yTest.flushAll()
|
||||||
|
expect(last_task).to.equal("observer2")
|
||||||
|
u.unobserve observer2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ describe "TextFramework", ->
|
|||||||
expect(change.object).to.equal(u)
|
expect(change.object).to.equal(u)
|
||||||
expect(change.value).to.equal("a")
|
expect(change.value).to.equal("a")
|
||||||
expect(change.position).to.equal(1)
|
expect(change.position).to.equal(1)
|
||||||
expect(change.changed_by).to.equal('0')
|
expect(change.changedBy).to.equal('0')
|
||||||
last_task = "observer1"
|
last_task = "observer1"
|
||||||
u.observe observer1
|
u.observe observer1
|
||||||
u.insertText 1, "a"
|
u.insertText 1, "a"
|
||||||
@ -70,7 +70,7 @@ describe "TextFramework", ->
|
|||||||
expect(change.object).to.equal(u)
|
expect(change.object).to.equal(u)
|
||||||
expect(change.value).to.equal("x")
|
expect(change.value).to.equal("x")
|
||||||
expect(change.position).to.equal(0)
|
expect(change.position).to.equal(0)
|
||||||
expect(change.changed_by).to.equal('1')
|
expect(change.changedBy).to.equal('1')
|
||||||
last_task = "observer2"
|
last_task = "observer2"
|
||||||
u.observe observer2
|
u.observe observer2
|
||||||
v = @yTest.users[1].val("TextTest")
|
v = @yTest.users[1].val("TextTest")
|
||||||
@ -90,10 +90,10 @@ describe "TextFramework", ->
|
|||||||
expect(change.object).to.equal(u)
|
expect(change.object).to.equal(u)
|
||||||
expect(change.position).to.equal(1)
|
expect(change.position).to.equal(1)
|
||||||
expect(change.length).to.equal(1)
|
expect(change.length).to.equal(1)
|
||||||
expect(change.changed_by).to.equal('0')
|
expect(change.changedBy).to.equal('0')
|
||||||
last_task = "observer1"
|
last_task = "observer1"
|
||||||
u.observe observer1
|
u.observe observer1
|
||||||
u.deleteText 1
|
u.deleteText 1, 1
|
||||||
expect(last_task).to.equal("observer1")
|
expect(last_task).to.equal("observer1")
|
||||||
u.unobserve observer1
|
u.unobserve observer1
|
||||||
|
|
||||||
@ -103,12 +103,12 @@ describe "TextFramework", ->
|
|||||||
expect(change.type).to.equal("delete")
|
expect(change.type).to.equal("delete")
|
||||||
expect(change.object).to.equal(u)
|
expect(change.object).to.equal(u)
|
||||||
expect(change.position).to.equal(0)
|
expect(change.position).to.equal(0)
|
||||||
expect(change.length).to.equal(0)
|
expect(change.length).to.equal(1)
|
||||||
expect(change.changed_by).to.equal('1')
|
expect(change.changedBy).to.equal('1')
|
||||||
last_task = "observer2"
|
last_task = "observer2"
|
||||||
u.observe observer2
|
u.observe observer2
|
||||||
v = @yTest.users[1].val("TextTest")
|
v = @yTest.users[1].val("TextTest")
|
||||||
v.deleteText 0
|
v.deleteText 0, 1
|
||||||
@yTest.flushAll()
|
@yTest.flushAll()
|
||||||
expect(last_task).to.equal("observer2")
|
expect(last_task).to.equal("observer2")
|
||||||
u.unobserve observer2
|
u.unobserve observer2
|
||||||
|
2
yatta.js
2
yatta.js
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user