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:
@@ -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
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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
|
||||
|
||||
#
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user