added tests for observer types

This commit is contained in:
DadaMonad 2014-12-24 11:35:06 +00:00
parent 2f47ad9e3a
commit fd1128d456
33 changed files with 607 additions and 240 deletions

View File

@ -1,11 +1,11 @@
# ![Yatta!](https://dadamonad.github.io/files/layout/Yatta_logo.png)
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),
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/)
* 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.
@ -27,6 +27,9 @@ Either clone this git repository, install it with [bower](http://bower.io/), or
bower install Yatta
```
Then you include the libraries directly from the installation folder.
```
<script src="./bower_components/yatta.js"></script>
```
### Npm
```
@ -35,9 +38,7 @@ npm install yatta --save
And use it like this with *npm*:
```
Y = require("yatta");
Y.createPeerJsConnector({key: 'xxx'}, function(Connector, user_id){
yatta = new Y.JsonFramework(user_id, Connector);
Yatta = require("yatta");
```

File diff suppressed because one or more lines are too long

View File

@ -24,7 +24,7 @@
};
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;
});
};
@ -156,9 +156,13 @@
};
Delete.prototype.execute = function() {
var res;
if (this.validateSavedOperations()) {
this.deletes.applyDelete(this);
return Delete.__super__.execute.apply(this, arguments);
res = Delete.__super__.execute.apply(this, arguments);
if (res) {
this.deletes.applyDelete(this);
}
return res;
} else {
return false;
}
@ -307,7 +311,8 @@
type: "insert",
position: this.getPosition(),
object: this.parent,
changed_by: this.uid.creator
changed_by: this.uid.creator,
value: this.content
}
]) : void 0;
};

File diff suppressed because one or more lines are too long

View File

@ -195,22 +195,21 @@
ListManager.prototype.getOperationByPosition = function(position) {
var o;
o = this.beginning.next_cl;
if ((position > 0 || o.isDeleted()) && !(o instanceof types.Delimiter)) {
while (o.isDeleted() && !(o instanceof types.Delimiter)) {
o = o.next_cl;
o = this.beginning;
while (true) {
if (o instanceof types.Delimiter && (o.prev_cl != null)) {
o = o.prev_cl;
while (o.isDeleted() || !(o instanceof types.Delimiter)) {
o = o.prev_cl;
}
break;
}
while (true) {
if (o instanceof types.Delimiter) {
break;
}
if (position <= 0 && !o.isDeleted()) {
break;
}
o = o.next_cl;
if (!o.isDeleted()) {
position -= 1;
}
if (position <= 0 && !o.isDeleted()) {
break;
}
o = o.next_cl;
if (!o.isDeleted()) {
position -= 1;
}
}
return o;

File diff suppressed because one or more lines are too long

View File

@ -147,15 +147,14 @@
};
WordType.prototype.insertText = function(position, content) {
var ith, left;
var ith;
ith = this.getOperationByPosition(position);
left = ith.prev_cl;
return this.insertAfter(left, content);
return this.insertAfter(ith, content);
};
WordType.prototype.deleteText = function(position, length) {
var d, delete_ops, i, o, _i;
o = this.getOperationByPosition(position);
o = this.getOperationByPosition(position + 1);
delete_ops = [];
for (i = _i = 0; 0 <= length ? _i < length : _i > length; i = 0 <= length ? ++_i : --_i) {
if (o instanceof types.Delimiter) {

File diff suppressed because one or more lines are too long

View File

@ -42,7 +42,7 @@
module.exports = createYatta;
if ((typeof window !== "undefined" && window !== null) && (window.Yatta == null)) {
window.Yatta = Yatta;
window.Yatta = createYatta;
}
}).call(this);

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

@ -115,7 +115,7 @@ Known values that are supported:</p><ul>
</div>
</div>
<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'>
Codo
</a>

View File

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

View File

@ -76,7 +76,7 @@ But I would become really motivated if you gave me some feedback :) (<a href="ht
</ul>
<h2 id="support">Support</h2><p>Please report <em>any</em> issues to the <a href="https://github.com/DadaMonad/Yatta/issues">Github issue page</a>!
I would appreciate if developers gave me feedback on how <em>convenient</em> the framework is, and if it is easy to use. Particularly the XML-support may not support every DOM-methods - if you encounter a method that does not cause any change on other peers,
please state function name, and sample parameters. However, there are browser-specific features, that Yatta won&#39;t support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="&#x6d;&#97;&#x69;&#108;&#116;&#111;&#58;&#107;&#101;&#118;&#105;&#110;&#46;&#x6a;&#x61;&#x68;&#x6e;&#115;&#x40;&#x72;&#119;&#116;&#x68;&#45;&#x61;&#97;&#x63;&#104;&#x65;&#110;&#x2e;&#x64;&#x65;">&#107;&#101;&#118;&#105;&#110;&#46;&#x6a;&#x61;&#x68;&#x6e;&#115;&#x40;&#x72;&#119;&#116;&#x68;&#45;&#x61;&#97;&#x63;&#104;&#x65;&#110;&#x2e;&#x64;&#x65;</a>
please state function name, and sample parameters. However, there are browser-specific features, that Yatta won&#39;t support.</p><h2 id="license">License</h2><p>Yatta! is licensed under the <a href="./LICENSE.txt">MIT License</a>.</p><a href="&#109;&#97;&#x69;&#108;&#116;&#111;&#x3a;&#107;&#101;&#118;&#105;&#x6e;&#46;&#x6a;&#x61;&#104;&#110;&#115;&#64;&#114;&#119;&#x74;&#104;&#45;&#97;&#97;&#99;&#104;&#x65;&#x6e;&#x2e;&#x64;&#x65;">&#107;&#101;&#118;&#105;&#x6e;&#46;&#x6a;&#x61;&#104;&#110;&#115;&#64;&#114;&#119;&#x74;&#104;&#45;&#97;&#97;&#99;&#104;&#x65;&#x6e;&#x2e;&#x64;&#x65;</a>
@ -85,7 +85,7 @@ please state function name, and sample parameters. However, there are browser-sp
</div>
</div>
<div id='footer'>
December 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'>
Codo
</a>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -277,12 +277,7 @@ module.exports = (HB)->
garbagecollect = true
super garbagecollect
if callLater
@parent.callEvent [
type: "insert"
position: @getPosition()
object: @parent # TODO: You can combine getPosition + getParent in a more efficient manner! (only left Delimiter will hold @parent)
changed_by: o.uid.creator
]
@callOperationSpecificDeleteEvents(o)
if @next_cl?.isDeleted()
# garbage collect next_cl
@next_cl.applyDelete()
@ -378,18 +373,27 @@ module.exports = (HB)->
@setParent @prev_cl.getParent() # do Insertions always have a parent?
super # notify the execution_listeners
@callOperationSpecificEvents()
@callOperationSpecificInsertEvents()
@
callOperationSpecificEvents: ()->
callOperationSpecificInsertEvents: ()->
@parent?.callEvent [
type: "insert"
position: @getPosition()
object: @parent
changed_by: @uid.creator
changedBy: @uid.creator
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.
#

View File

@ -145,7 +145,7 @@ module.exports = (HB)->
that = @
Object.observe @bound_json, (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.
that.val(event.name, event.object[event.name])
@observe (events)->
@ -162,7 +162,7 @@ module.exports = (HB)->
type: 'update'
name: event.name
oldValue: oldVal
changed_by: event.changed_by
changedBy: event.changedBy
else
notifier.performChange 'add', ()->
that.bound_json[event.name] = that.val(event.name)
@ -172,7 +172,7 @@ module.exports = (HB)->
type: 'add'
name: event.name
oldValue: oldVal
changed_by:event.changed_by
changedBy:event.changedBy
@bound_json
#

View File

@ -35,29 +35,31 @@ module.exports = (HB)->
if content?
if not @map[name]?
(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?
obj = @map[name]?.val()
if obj instanceof types.ImmutableObject
obj.val()
prop = @map[name]
if prop? and not prop.isContentDeleted()
obj = prop.val()
if obj instanceof types.ImmutableObject
obj.val()
else
obj
else
obj
undefined
else
result = {}
for name,o of @map
obj = o.val()
if obj instanceof types.ImmutableObject or obj instanceof MapManager
obj = obj.val()
result[name] = obj
if not o.isContentDeleted()
obj = o.val()
if obj instanceof types.ImmutableObject or obj instanceof MapManager
obj = obj.val()
result[name] = obj
result
delete: (name)->
@map[name]?.deleteContent()
@
#
# @nodoc
# 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 {Delimiter} beginning 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
type: "ReplaceManager"
@ -262,8 +266,8 @@ module.exports = (HB)->
#
callEventDecorator: (events)->
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_this.callEvent events
undefined
@ -276,7 +280,15 @@ module.exports = (HB)->
#
replace: (content, replaceable_uid)->
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
#
@ -347,13 +359,14 @@ module.exports = (HB)->
@content
applyDelete: ()->
res = super
if @content?
if @next_cl.type isnt "Delimiter"
@content.deleteAllObservers()
@content.applyDelete()
@content.dontSync()
@content = null
super
res
cleanup: ()->
super
@ -363,27 +376,35 @@ module.exports = (HB)->
# 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.
#
callOperationSpecificEvents: ()->
callOperationSpecificInsertEvents: ()->
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
# this replaces another Replaceable
old_value = @prev_cl.content
@prev_cl.applyDelete()
@parent.callEventDecorator [
type: "update"
changed_by: @uid.creator
changedBy: @uid.creator
oldValue: old_value
]
@prev_cl.applyDelete()
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
@applyDelete()
else # prev _and_ next are Delimiters. This is the first created Replaceable in the RM
@parent.callEventDecorator [
type: "add"
changed_by: @uid.creator
changedBy: @uid.creator
]
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.
#

View File

@ -161,3 +161,106 @@ describe "JsonFramework", ->
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

View File

@ -56,7 +56,7 @@ describe "TextFramework", ->
expect(change.object).to.equal(u)
expect(change.value).to.equal("a")
expect(change.position).to.equal(1)
expect(change.changed_by).to.equal('0')
expect(change.changedBy).to.equal('0')
last_task = "observer1"
u.observe observer1
u.insertText 1, "a"
@ -70,7 +70,7 @@ describe "TextFramework", ->
expect(change.object).to.equal(u)
expect(change.value).to.equal("x")
expect(change.position).to.equal(0)
expect(change.changed_by).to.equal('1')
expect(change.changedBy).to.equal('1')
last_task = "observer2"
u.observe observer2
v = @yTest.users[1].val("TextTest")
@ -90,10 +90,10 @@ describe "TextFramework", ->
expect(change.object).to.equal(u)
expect(change.position).to.equal(1)
expect(change.length).to.equal(1)
expect(change.changed_by).to.equal('0')
expect(change.changedBy).to.equal('0')
last_task = "observer1"
u.observe observer1
u.deleteText 1
u.deleteText 1, 1
expect(last_task).to.equal("observer1")
u.unobserve observer1
@ -103,12 +103,12 @@ describe "TextFramework", ->
expect(change.type).to.equal("delete")
expect(change.object).to.equal(u)
expect(change.position).to.equal(0)
expect(change.length).to.equal(0)
expect(change.changed_by).to.equal('1')
expect(change.length).to.equal(1)
expect(change.changedBy).to.equal('1')
last_task = "observer2"
u.observe observer2
v = @yTest.users[1].val("TextTest")
v.deleteText 0
v.deleteText 0, 1
@yTest.flushAll()
expect(last_task).to.equal("observer2")
u.unobserve observer2

File diff suppressed because one or more lines are too long