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:
@@ -22,6 +22,7 @@ class Engine
|
||||
else
|
||||
throw new Error "You forgot to specify a parser for type #{json.type}. The message is #{JSON.stringify json}."
|
||||
|
||||
|
||||
#
|
||||
# Apply a set of operations. E.g. the operations you received from another users HB._encode().
|
||||
# @note You must not use this method when you already have ops in your HB!
|
||||
@@ -30,8 +31,6 @@ class Engine
|
||||
ops = []
|
||||
for o in ops_json
|
||||
ops.push @parseOperation o
|
||||
for o in ops
|
||||
@HB.addOperation o
|
||||
for o in ops
|
||||
if not o.execute()
|
||||
@unprocessed_ops.push o
|
||||
@@ -64,8 +63,6 @@ class Engine
|
||||
if @HB.getOperation(o)?
|
||||
else if not o.execute()
|
||||
@unprocessed_ops.push o
|
||||
else
|
||||
@HB.addOperation o
|
||||
@tryUnprocessed()
|
||||
|
||||
#
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
|
||||
text_types_uninitialized = require "../Types/TextTypes"
|
||||
HistoryBuffer = require "../HistoryBuffer"
|
||||
Engine = require "../Engine"
|
||||
adaptConnector = require "../ConnectorAdapter"
|
||||
|
||||
#
|
||||
# Framework for Text Datastructures.
|
||||
#
|
||||
class TextFramework
|
||||
|
||||
#
|
||||
# @param {String} user_id Uniqe user id that defines this peer.
|
||||
# @param {Connector} Connector The connector defines how you connect to the other peers.
|
||||
#
|
||||
constructor: (user_id, @connector)->
|
||||
@HB = new HistoryBuffer user_id
|
||||
text_types = text_types_uninitialized @HB
|
||||
@types = text_types.types
|
||||
@engine = new Engine @HB, text_types.parser
|
||||
adaptConnector @connector, @engine, @HB, text_types.execution_listener
|
||||
|
||||
beginning = @HB.addOperation new @types.Delimiter {creator: '_', op_number: '_beginning'} , undefined, undefined
|
||||
end = @HB.addOperation new @types.Delimiter {creator: '_', op_number: '_end'} , beginning, undefined
|
||||
beginning.next_cl = end
|
||||
beginning.execute()
|
||||
end.execute()
|
||||
first_word = new @types.WordType {creator: '_', op_number: '_'}, beginning, end
|
||||
@HB.addOperation(first_word).execute()
|
||||
|
||||
uid_r = { creator: '_', op_number: "RM" }
|
||||
uid_beg = { creator: '_', op_number: "_RM_beginning" }
|
||||
uid_end = { creator: '_', op_number: "_RM_end" }
|
||||
beg = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()
|
||||
end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()
|
||||
@root_element = @HB.addOperation(new @types.ReplaceManager undefined, uid_r, beg, end).execute()
|
||||
@root_element.replace first_word, { creator: '_', op_number: 'Replaceable'}
|
||||
|
||||
|
||||
#
|
||||
# @return WordType
|
||||
#
|
||||
getSharedObject: ()->
|
||||
@root_element.val()
|
||||
|
||||
#
|
||||
# Get the initialized connector.
|
||||
#
|
||||
getConnector: ()->
|
||||
@connector
|
||||
|
||||
#
|
||||
# @see HistoryBuffer
|
||||
#
|
||||
getHistoryBuffer: ()->
|
||||
@HB
|
||||
|
||||
#
|
||||
# Get the UserId from the HistoryBuffer object.
|
||||
# In most cases this will be the same as the user_id value with which
|
||||
# JsonFramework was initialized (Depending on the HistoryBuffer implementation).
|
||||
#
|
||||
getUserId: ()->
|
||||
@HB.getUserId()
|
||||
|
||||
#
|
||||
# @see JsonType.val
|
||||
#
|
||||
val: ()->
|
||||
@getSharedObject().val()
|
||||
|
||||
#
|
||||
# @see WordType.insertText
|
||||
#
|
||||
insertText: (pos, content)->
|
||||
@getSharedObject().insertText pos, content
|
||||
|
||||
#
|
||||
# @see WordType.deleteText
|
||||
#
|
||||
deleteText: (pos, length)->
|
||||
@getSharedObject().deleteText pos, length
|
||||
|
||||
#
|
||||
# @see WordType.bind
|
||||
#
|
||||
bind: (textarea)->
|
||||
@getSharedObject().bind textarea
|
||||
|
||||
#
|
||||
# @see WordType.replaceText
|
||||
#
|
||||
replaceText: (text)->
|
||||
@getSharedObject().replaceText text
|
||||
|
||||
#
|
||||
# @see Operation.on
|
||||
#
|
||||
on: ()->
|
||||
@root_element.on arguments...
|
||||
|
||||
|
||||
module.exports = TextFramework
|
||||
if window?
|
||||
if not window.Y?
|
||||
window.Y = {}
|
||||
window.Y.TextFramework = TextFramework
|
||||
@@ -1,101 +0,0 @@
|
||||
|
||||
json_types_uninitialized = require "../Types/XmlTypes"
|
||||
HistoryBuffer = require "../HistoryBuffer"
|
||||
Engine = require "../Engine"
|
||||
adaptConnector = require "../ConnectorAdapter"
|
||||
|
||||
#
|
||||
# Framework for Xml-like data-structures.
|
||||
# Known values that are supported:
|
||||
#
|
||||
class XmlFramework
|
||||
|
||||
#
|
||||
# @param {String} user_id Unique id of the peer.
|
||||
# @param {Connector} Connector the connector class.
|
||||
#
|
||||
constructor: (user_id, @connector)->
|
||||
@HB = new HistoryBuffer user_id
|
||||
type_manager = json_types_uninitialized @HB
|
||||
@types = type_manager.types
|
||||
@engine = new Engine @HB, type_manager.parser
|
||||
@HB.engine = @engine # TODO: !! only for debugging
|
||||
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
|
||||
#first_word = new @types.XmlType(undefined, undefined, undefined, undefined, document.createElement("shared"))
|
||||
#@HB.addOperation(first_word).execute()
|
||||
|
||||
uid_beg = @HB.getReservedUniqueIdentifier()
|
||||
uid_end = @HB.getReservedUniqueIdentifier()
|
||||
beg = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()
|
||||
end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()
|
||||
|
||||
@root_element = new @types.ReplaceManager undefined, @HB.getReservedUniqueIdentifier(), beg, end
|
||||
@HB.addOperation(@root_element).execute()
|
||||
#@root_element.replace first_word
|
||||
|
||||
#
|
||||
# @return JsonType
|
||||
#
|
||||
getSharedObject: ()->
|
||||
@root_element.val()
|
||||
|
||||
#
|
||||
# Get the initialized connector.
|
||||
#
|
||||
getConnector: ()->
|
||||
@connector
|
||||
|
||||
#
|
||||
# @see HistoryBuffer
|
||||
#
|
||||
getHistoryBuffer: ()->
|
||||
@HB
|
||||
|
||||
#
|
||||
# @see JsonType.setMutableDefault
|
||||
#
|
||||
setMutableDefault: (mutable)->
|
||||
@getSharedObject().setMutableDefault(mutable)
|
||||
|
||||
#
|
||||
# Get the UserId from the HistoryBuffer object.
|
||||
# In most cases this will be the same as the user_id value with which
|
||||
# JsonFramework was initialized (Depending on the HistoryBuffer implementation).
|
||||
#
|
||||
getUserId: ()->
|
||||
@HB.getUserId()
|
||||
|
||||
#
|
||||
# @see JsonType.toJson
|
||||
#
|
||||
toJson : ()->
|
||||
@getSharedObject().toJson()
|
||||
|
||||
#
|
||||
# @see JsonType.val
|
||||
#
|
||||
val : ()->
|
||||
if (arguments.length is 0) or (typeof arguments[0] is "boolean")
|
||||
@getSharedObject().val(arguments[0])
|
||||
else if arguments.length is 1
|
||||
newXml = new @types.XmlType(undefined, undefined, undefined, undefined, arguments[0])
|
||||
@HB.addOperation(newXml).execute()
|
||||
@root_element.replace newXml
|
||||
newXml
|
||||
else
|
||||
throw new Error "can only parse 0, or 1 parameter!"
|
||||
|
||||
|
||||
#
|
||||
# @see Operation.on
|
||||
#
|
||||
on: ()->
|
||||
@getSharedObject().on arguments...
|
||||
|
||||
|
||||
|
||||
module.exports = XmlFramework
|
||||
if window?
|
||||
if not window.Y?
|
||||
window.Y = {}
|
||||
window.Y.XmlFramework = XmlFramework
|
||||
@@ -26,7 +26,7 @@ class HistoryBuffer
|
||||
|
||||
emptyGarbage: ()=>
|
||||
for o in @garbage
|
||||
#if @getOperationCounter(o.creator) > o.op_number
|
||||
#if @getOperationCounter(o.uid.creator) > o.uid.op_number
|
||||
o.cleanup?()
|
||||
|
||||
@garbage = @trash
|
||||
@@ -104,13 +104,13 @@ class HistoryBuffer
|
||||
if o.next_cl? # applies for all ops but the most right delimiter!
|
||||
# search for the next _known_ operation. (When state_vector is {} then this is the Delimiter)
|
||||
o_next = o.next_cl
|
||||
while o_next.next_cl? and unknown(o_next.creator, o_next.op_number)
|
||||
while o_next.next_cl? and unknown(o_next.uid.creator, o_next.uid.op_number)
|
||||
o_next = o_next.next_cl
|
||||
o_json.next = o_next.getUid()
|
||||
else if o.prev_cl? # most right delimiter only!
|
||||
# same as the above with prev.
|
||||
o_prev = o.prev_cl
|
||||
while o_prev.prev_cl? and unknown(o_prev.creator, o_prev.op_number)
|
||||
while o_prev.prev_cl? and unknown(o_prev.uid.creator, o_prev.uid.op_number)
|
||||
o_prev = o_prev.prev_cl
|
||||
o_json.prev = o_prev.getUid()
|
||||
json.push o_json
|
||||
@@ -130,6 +130,7 @@ class HistoryBuffer
|
||||
uid =
|
||||
'creator' : user_id
|
||||
'op_number' : @operation_counter[user_id]
|
||||
'doSync' : true
|
||||
@operation_counter[user_id]++
|
||||
uid
|
||||
|
||||
@@ -147,35 +148,35 @@ class HistoryBuffer
|
||||
# other operations (it wont executed)
|
||||
#
|
||||
addOperation: (o)->
|
||||
if not @buffer[o.creator]?
|
||||
@buffer[o.creator] = {}
|
||||
if @buffer[o.creator][o.op_number]?
|
||||
if not @buffer[o.uid.creator]?
|
||||
@buffer[o.uid.creator] = {}
|
||||
if @buffer[o.uid.creator][o.uid.op_number]?
|
||||
throw new Error "You must not overwrite operations!"
|
||||
@buffer[o.creator][o.op_number] = o
|
||||
@buffer[o.uid.creator][o.uid.op_number] = o
|
||||
@number_of_operations_added_to_HB ?= 0 # TODO: Debug, remove this
|
||||
@number_of_operations_added_to_HB++
|
||||
o
|
||||
|
||||
removeOperation: (o)->
|
||||
delete @buffer[o.creator]?[o.op_number]
|
||||
delete @buffer[o.uid.creator]?[o.uid.op_number]
|
||||
|
||||
#
|
||||
# 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()
|
||||
if not @operation_counter[o.uid.creator]?
|
||||
@operation_counter[o.uid.creator] = 0
|
||||
if typeof o.uid.op_number is 'number' and o.uid.creator isnt @getUserId()
|
||||
# TODO: fix this issue better.
|
||||
# Operations should income in order
|
||||
# Then you don't have to do this..
|
||||
if o.op_number is @operation_counter[o.creator]
|
||||
@operation_counter[o.creator]++
|
||||
while @getOperation({creator:o.creator, op_number: @operation_counter[o.creator]})?
|
||||
@operation_counter[o.creator]++
|
||||
if o.uid.op_number is @operation_counter[o.uid.creator]
|
||||
@operation_counter[o.uid.creator]++
|
||||
while @getOperation({creator:o.uid.creator, op_number: @operation_counter[o.uid.creator]})?
|
||||
@operation_counter[o.uid.creator]++
|
||||
|
||||
#if @operation_counter[o.creator] isnt (o.op_number + 1)
|
||||
#console.log (@operation_counter[o.creator] - (o.op_number + 1))
|
||||
#if @operation_counter[o.uid.creator] isnt (o.uid.op_number + 1)
|
||||
#console.log (@operation_counter[o.uid.creator] - (o.uid.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,.. ;)"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
json_types_uninitialized = require "../Types/JsonTypes"
|
||||
HistoryBuffer = require "../HistoryBuffer"
|
||||
Engine = require "../Engine"
|
||||
adaptConnector = require "../ConnectorAdapter"
|
||||
json_types_uninitialized = require "./Types/JsonTypes"
|
||||
HistoryBuffer = require "./HistoryBuffer"
|
||||
Engine = require "./Engine"
|
||||
adaptConnector = require "./ConnectorAdapter"
|
||||
|
||||
|
||||
#
|
||||
@@ -12,29 +12,28 @@ adaptConnector = require "../ConnectorAdapter"
|
||||
# * Integer
|
||||
# * Array
|
||||
#
|
||||
class JsonFramework
|
||||
class Yatta
|
||||
|
||||
#
|
||||
# @param {String} user_id Unique id of the peer.
|
||||
# @param {Connector} Connector the connector class.
|
||||
#
|
||||
constructor: (user_id, @connector)->
|
||||
constructor: (@connector)->
|
||||
user_id = @connector.id # TODO: change to getUniqueId()
|
||||
@HB = new HistoryBuffer user_id
|
||||
type_manager = json_types_uninitialized @HB
|
||||
@types = type_manager.types
|
||||
@engine = new Engine @HB, type_manager.parser
|
||||
@HB.engine = @engine # TODO: !! only for debugging
|
||||
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
|
||||
first_word = new @types.JsonType(@HB.getReservedUniqueIdentifier())
|
||||
@HB.addOperation(first_word).execute()
|
||||
first_word = new @types.JsonType(@HB.getReservedUniqueIdentifier()).execute()
|
||||
|
||||
uid_beg = @HB.getReservedUniqueIdentifier()
|
||||
uid_end = @HB.getReservedUniqueIdentifier()
|
||||
beg = @HB.addOperation(new @types.Delimiter uid_beg, undefined, uid_end).execute()
|
||||
end = @HB.addOperation(new @types.Delimiter uid_end, beg, undefined).execute()
|
||||
beg = (new @types.Delimiter uid_beg, undefined, uid_end).execute()
|
||||
end = (new @types.Delimiter uid_end, beg, undefined).execute()
|
||||
|
||||
@root_element = new @types.ReplaceManager undefined, @HB.getReservedUniqueIdentifier(), beg, end
|
||||
@HB.addOperation(@root_element).execute()
|
||||
@root_element = (new @types.ReplaceManager undefined, @HB.getReservedUniqueIdentifier(), beg, end).execute()
|
||||
@root_element.replace first_word, @HB.getReservedUniqueIdentifier()
|
||||
|
||||
#
|
||||
@@ -64,7 +63,7 @@ class JsonFramework
|
||||
#
|
||||
# Get the UserId from the HistoryBuffer object.
|
||||
# In most cases this will be the same as the user_id value with which
|
||||
# JsonFramework was initialized (Depending on the HistoryBuffer implementation).
|
||||
# Yatta was initialized (Depending on the HistoryBuffer implementation).
|
||||
#
|
||||
getUserId: ()->
|
||||
@HB.getUserId()
|
||||
@@ -96,7 +95,7 @@ class JsonFramework
|
||||
#
|
||||
# @see JsonType.value
|
||||
#
|
||||
Object.defineProperty JsonFramework.prototype, 'value',
|
||||
Object.defineProperty Yatta.prototype, 'value',
|
||||
get : -> @getSharedObject().value
|
||||
set : (o)->
|
||||
if o.constructor is {}.constructor
|
||||
@@ -105,8 +104,6 @@ class JsonFramework
|
||||
else
|
||||
throw new Error "You must only set Object values!"
|
||||
|
||||
module.exports = JsonFramework
|
||||
if window?
|
||||
if not window.Y?
|
||||
window.Y = {}
|
||||
window.Y.JsonFramework = JsonFramework
|
||||
module.exports = Yatta
|
||||
if window? and not window.Yatta?
|
||||
window.Yatta = Yatta
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
exports['JsonFramework'] =
|
||||
require './Frameworks/JsonFramework'
|
||||
exports['TextFramework'] =
|
||||
require './Frameworks/TextFramework'
|
||||
exports['XmlFramework'] =
|
||||
require './Frameworks/XmlFramework'
|
||||
|
||||
Reference in New Issue
Block a user