refs, complex saveOperation' and validateSavedOperations`

This commit is contained in:
Kevin Jahns
2015-04-17 20:11:05 +02:00
parent f44f463e9d
commit b02662c36e
14 changed files with 4396 additions and 1008 deletions

View File

@@ -182,7 +182,7 @@ module.exports = ()->
# @param {String} name The name of the operation. After calling this function op is accessible via this[name].
# @param {Operation} op An Operation object
#
saveOperation: (name, op)->
saveOperation: (name, op, base = "this")->
#
# Every instance of $Operation must have an $execute function.
@@ -194,11 +194,20 @@ module.exports = ()->
else if op.execute? or not (op.op_number? and op.creator?)
# is instantiated, or op is string. Currently "Delimiter" is saved as string
# (in combination with @parent you can retrieve the delimiter..)
@[name] = op
if base is "this"
@[name] = op
else
dest = @[base]
paths = name.split("/")
last_path = paths.pop()
for path in paths
dest = dest[path]
dest[last_path] = op
else
# not initialized. Do it when calling $validateSavedOperations()
@unchecked ?= {}
@unchecked[name] = op
@unchecked[base] ?= {}
@unchecked[base][name] = op
#
# @private
@@ -210,13 +219,23 @@ module.exports = ()->
validateSavedOperations: ()->
uninstantiated = {}
success = @
for name, op_uid of @unchecked
op = @HB.getOperation op_uid
if op
@[name] = op
else
uninstantiated[name] = op_uid
success = false
for base_name, base of @unchecked
for name, op_uid of base
op = @HB.getOperation op_uid
if op
if base_name is "this"
@[name] = op
else
dest = @[base_name]
paths = name.split("/")
last_path = paths.pop()
for path in paths
dest = dest[path]
dest[last_path] = op
else
uninstantiated[base_name] ?= {}
uninstantiated[base_name][name] = op_uid
success = false
delete @unchecked
if not success
@unchecked = uninstantiated
@@ -305,7 +324,7 @@ module.exports = ()->
# @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)
#
constructor: (custom_type, content, parent, uid, prev_cl, next_cl, origin)->
constructor: (custom_type, content, content_operations, parent, uid, prev_cl, next_cl, origin)->
# see encode to see, why we are doing it this way
if content is undefined
# nop
@@ -313,6 +332,10 @@ module.exports = ()->
@saveOperation 'content', content
else
@content = content
if content_operations?
@content_operations = {}
for name, op of content_operations
@saveOperation name, op, 'content_operations'
@saveOperation 'parent', parent
@saveOperation 'prev_cl', prev_cl
@saveOperation 'next_cl', next_cl
@@ -325,8 +348,19 @@ module.exports = ()->
type: "Insert"
val: ()->
if @content? and @content.getCustomType?
@content.getCustomType()
if @content?
if @content.getCustomType?
@content.getCustomType()
else if @content.constructor is Object
content = {}
for n,v of @content
content[n] = v
if @content_operations?
for n,v of @content_operations
content[n] = v
content
else
@content
else
@content
@@ -518,14 +552,20 @@ module.exports = ()->
json.parent = @parent.getUid()
if @content?.getUid?
json['content'] = @content.getUid()
json.content = @content.getUid()
else
json['content'] = JSON.stringify @content
json.content = JSON.stringify @content
if @content_operations?
operations = {}
for n,o of @content_operations
operations[n] = o.getUid()
json.content_operations = operations
super json
ops.Insert.parse = (json)->
{
'content' : content
'content_operations' : content_operations
'uid' : uid
'prev': prev
'next': next
@@ -534,7 +574,7 @@ module.exports = ()->
} = json
if typeof content is "string"
content = JSON.parse(content)
new this null, content, parent, uid, prev, next, origin
new this null, content, content_operations, parent, uid, prev, next, origin
#
# @nodoc

View File

@@ -238,12 +238,12 @@ module.exports = ()->
# TODO: always expect an array as content. Then you can combine this with the other option (else)
if contents instanceof ops.Operation
(new ops.Insert null, content, undefined, undefined, left, right).execute()
(new ops.Insert null, content, null, undefined, undefined, left, right).execute()
else
for c in contents
if c? and c._name? and c._getModel?
c = c._getModel(@custom_types, @operations)
tmp = (new ops.Insert null, c, undefined, undefined, left, right).execute()
tmp = (new ops.Insert null, c, null, undefined, undefined, left, right).execute()
left = tmp
@
@@ -290,7 +290,7 @@ module.exports = ()->
position: op.getPosition()
object: @getCustomType()
changedBy: op.uid.creator
value: getContentType op.content
value: getContentType op.val()
]
callOperationSpecificDeleteEvents: (op, del_op)->
@@ -316,31 +316,60 @@ module.exports = ()->
class ops.Composition extends ops.ListManager
constructor: (custom_type, @composition_value, uid, composition_ref)->
constructor: (custom_type, @_composition_value, composition_value_operations, uid, tmp_composition_ref)->
# we can't use @seveOperation 'composition_ref', tmp_composition_ref here,
# because then there is a "loop" (insertion refers to parant, refers to insertion..)
# This is why we have to check in @callOperationSpecificInsertEvents until we find it
console.log("delete this ...")
this.constructed_with = [custom_type, @_composition_value, composition_value_operations, uid, tmp_composition_ref] # debug!
super custom_type, uid
if composition_ref
@saveOperation 'composition_ref', composition_ref
if tmp_composition_ref?
@tmp_composition_ref = tmp_composition_ref
else
@composition_ref = @beginning
@composition_ref = @end.prev_cl
if composition_value_operations?
@composition_value_operations = {}
for n,o of composition_value_operations
@saveOperation n, o, '_composition_value'
type: "Composition"
val: ()->
@composition_value
#
# @private
# @see Operation.execute
#
execute: ()->
if @validateSavedOperations()
@getCustomType()._setCompositionValue @_composition_value
delete @_composition_value
super
else
false
#
# This is called, when the Insert-operation was successfully executed.
#
callOperationSpecificInsertEvents: (op)->
if @tmp_composition_ref?
if op.uid.creator is @tmp_composition_ref.creator and op.uid.op_number is @tmp_composition_ref.op_number
@composition_ref = op
delete @tmp_composition_ref
o = op.next_cl
while o.next_cl?
if not o.isDeleted()
@callOperationSpecificInsertEvents o
o = o.next_cl
return
if @composition_ref.next_cl is op
op.undo_delta = @getCustomType()._apply op.content
op.undo_delta = @getCustomType()._apply op.val()
else
o = @end.prev_cl
while o isnt op
@getCustomType()._unapply o.undo_delta
o = o.prev_cl
while o isnt @end
o.undo_delta = @getCustomType()._apply o.content
o.undo_delta = @getCustomType()._apply o.val()
o = o.next_cl
@composition_ref = @end.prev_cl
@@ -361,16 +390,24 @@ module.exports = ()->
#
# @param delta The delta that is applied to the composition_value
#
applyDelta: (delta)->
(new ops.Insert null, delta, @, null, @end.prev_cl, @end).execute()
applyDelta: (delta, operations)->
(new ops.Insert null, delta, operations, @, null, @end.prev_cl, @end).execute()
undefined
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: (json = {})->
json.composition_value = JSON.stringify @composition_value
json.composition_ref = @composition_ref.getUid()
custom = @getCustomType()._getCompositionValue()
json.composition_value = custom.composition_value
if custom.composition_value_operations?
json.composition_value_operations = {}
for n,o of custom.composition_value_operations
json.composition_value_operations[n] = o.getUid()
if @composition_ref?
json.composition_ref = @composition_ref.getUid()
else
json.composition_ref = @tmp_composition_ref
super json
ops.Composition.parse = (json)->
@@ -378,9 +415,10 @@ module.exports = ()->
'uid' : uid
'custom_type': custom_type
'composition_value' : composition_value
'composition_value_operations' : composition_value_operations
'composition_ref' : composition_ref
} = json
new this(custom_type, JSON.parse(composition_value), uid, composition_ref)
new this(custom_type, composition_value, composition_value_operations, uid, composition_ref)
#
@@ -465,7 +503,7 @@ module.exports = ()->
#
replace: (content, replaceable_uid)->
o = @getLastOperation()
relp = (new ops.Insert null, content, @, replaceable_uid, o, o.next_cl).execute()
relp = (new ops.Insert null, content, null, @, replaceable_uid, o, o.next_cl).execute()
# TODO: delete repl (for debugging)
undefined