# # An object that holds all applied operations. # # @note The HistoryBuffer is commonly abbreviated to HB. # class HistoryBuffer # # Creates an empty HB. # @param {Object} user_id Creator of the HB. # constructor: (@user_id)-> @operation_counter = {} @buffer = {} @change_listeners = [] # # Get the user id with wich the History Buffer was initialized. # getUserId: ()-> @user_id # # There is only one reserved unique identifier (uid), so use it wisely. # I propose to use it in your Framework, to create something like a root element. # An operation with this identifier is not propagated to other clients. # This is why everybode must create the same operation with this uid. # getReservedUniqueIdentifier: ()-> { creator : '_' op_number : '_' } # # Get the operation counter that describes the current state of the document. # getOperationCounter: ()-> res = {} for user,ctn of @operation_counter res[user] = ctn res # # Encode this operation in such a way that it can be parsed by remote peers. # _encode: (state_vector={})-> json = [] unknown = (user, o_number)-> if (not user?) or (not o_number?) throw new Error "dah!" not state_vector[user]? or state_vector[user] <= o_number for u_name,user of @buffer for o_number,o of user if not isNaN(parseInt(o_number)) and unknown(u_name, o_number) o_json = o._encode() if o.next_cl? o_next = o.next_cl while o_next.next_cl? and unknown(o_next.creator, o_next.op_number) o_next = o_next.next_cl o_json.next = o_next.getUid() else if o.prev_cl? o_prev = o.prev_cl while o_prev.prev_cl? and unknown(o_next.creator, o_next.op_number) o_prev = o_prev.prev_cl o_json.prev = o_prev.getUid() json.push o_json json # # Get the number of operations that were created by a user. # Accordingly you will get the next operation number that is expected from that user. # This will increment the operation counter. # getNextOperationIdentifier: (user_id)-> if not user_id? user_id = @user_id if not @operation_counter[user_id]? @operation_counter[user_id] = 0 uid = 'creator' : user_id 'op_number' : @operation_counter[user_id] @operation_counter[user_id]++ uid # # Retrieve an operation from a unique id. # getOperation: (uid)-> if uid instanceof Object @buffer[uid.creator]?[uid.op_number] else if not uid? else throw new Error "This type of uid is not defined!" # # Add an operation to the HB. Note that this will not link it against # other operations (it wont executed) # addOperation: (o)-> if not @buffer[o.creator]? @buffer[o.creator] = {} if @buffer[o.creator][o.op_number]? throw new Error "You must not overwrite operations!" @buffer[o.creator][o.op_number] = o o # # 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() @operation_counter[o.creator]++ #if @operation_counter[o.creator] isnt (o.op_number + 1) #console.log (@operation_counter[o.creator] - (o.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,.. ;)" module.exports = HistoryBuffer