devided ops/types
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
module.exports = (HB)->
|
||||
module.exports = ()->
|
||||
# @see Engine.parse
|
||||
types = {}
|
||||
ops = {}
|
||||
execution_listener = []
|
||||
|
||||
#
|
||||
# @private
|
||||
# @abstract
|
||||
# @nodoc
|
||||
# A generic interface to operations.
|
||||
# A generic interface to ops.
|
||||
#
|
||||
# An operation has the following methods:
|
||||
# * _encode: encodes an operation (needed only if instance of this operation is sent).
|
||||
@@ -16,7 +16,7 @@ module.exports = (HB)->
|
||||
#
|
||||
# Furthermore an encodable operation has a parser. We extend the parser object in order to parse encoded operations.
|
||||
#
|
||||
class types.Operation
|
||||
class ops.Operation
|
||||
|
||||
#
|
||||
# @param {Object} uid A unique identifier.
|
||||
@@ -60,7 +60,7 @@ module.exports = (HB)->
|
||||
@event_listeners = []
|
||||
|
||||
delete: ()->
|
||||
(new types.Delete undefined, @).execute()
|
||||
(new ops.Delete undefined, @).execute()
|
||||
null
|
||||
|
||||
#
|
||||
@@ -86,11 +86,11 @@ module.exports = (HB)->
|
||||
@is_deleted = true
|
||||
if garbagecollect
|
||||
@garbage_collected = true
|
||||
HB.addToGarbageCollector @
|
||||
@HB.addToGarbageCollector @
|
||||
|
||||
cleanup: ()->
|
||||
#console.log "cleanup: #{@type}"
|
||||
HB.removeOperation @
|
||||
@HB.removeOperation @
|
||||
@deleteAllObservers()
|
||||
|
||||
#
|
||||
@@ -136,9 +136,9 @@ module.exports = (HB)->
|
||||
# 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()
|
||||
@uid = @HB.getNextOperationIdentifier()
|
||||
if not @uid.noOperation?
|
||||
HB.addOperation @
|
||||
@HB.addOperation @
|
||||
for l in execution_listener
|
||||
l @_encode()
|
||||
@
|
||||
@@ -190,7 +190,7 @@ module.exports = (HB)->
|
||||
uninstantiated = {}
|
||||
success = @
|
||||
for name, op_uid of @unchecked
|
||||
op = HB.getOperation op_uid
|
||||
op = @HB.getOperation op_uid
|
||||
if op
|
||||
@[name] = op
|
||||
else
|
||||
@@ -205,7 +205,7 @@ module.exports = (HB)->
|
||||
# @nodoc
|
||||
# A simple Delete-type operation that deletes an operation.
|
||||
#
|
||||
class types.Delete extends types.Operation
|
||||
class ops.Delete extends ops.Operation
|
||||
|
||||
#
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
@@ -245,7 +245,7 @@ module.exports = (HB)->
|
||||
#
|
||||
# Define how to parse Delete operations.
|
||||
#
|
||||
types.Delete.parse = (o)->
|
||||
ops.Delete.parse = (o)->
|
||||
{
|
||||
'uid' : uid
|
||||
'deletes': deletes_uid
|
||||
@@ -262,7 +262,7 @@ module.exports = (HB)->
|
||||
# - The short-list (abbrev. sl) maintains only the operations that are not deleted
|
||||
# - The complete-list (abbrev. cl) maintains all operations
|
||||
#
|
||||
class types.Insert extends types.Operation
|
||||
class ops.Insert extends ops.Operation
|
||||
|
||||
#
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
@@ -314,7 +314,7 @@ module.exports = (HB)->
|
||||
@prev_cl.applyDelete()
|
||||
|
||||
# delete content
|
||||
if @content instanceof types.Operation
|
||||
if @content instanceof ops.Operation
|
||||
@content.applyDelete()
|
||||
delete @content
|
||||
|
||||
@@ -361,7 +361,7 @@ module.exports = (HB)->
|
||||
if not @validateSavedOperations()
|
||||
return false
|
||||
else
|
||||
if @content instanceof types.Operation
|
||||
if @content instanceof ops.Operation
|
||||
@content.insert_parent = @ # TODO: this is probably not necessary and only nice for debugging
|
||||
if @parent?
|
||||
if not @prev_cl?
|
||||
@@ -450,7 +450,7 @@ module.exports = (HB)->
|
||||
position = 0
|
||||
prev = @prev_cl
|
||||
while true
|
||||
if prev instanceof types.Delimiter
|
||||
if prev instanceof ops.Delimiter
|
||||
break
|
||||
if not prev.isDeleted()
|
||||
position++
|
||||
@@ -482,7 +482,7 @@ module.exports = (HB)->
|
||||
json['content'] = JSON.stringify @content
|
||||
json
|
||||
|
||||
types.Insert.parse = (json)->
|
||||
ops.Insert.parse = (json)->
|
||||
{
|
||||
'content' : content
|
||||
'uid' : uid
|
||||
@@ -501,7 +501,7 @@ module.exports = (HB)->
|
||||
# @nodoc
|
||||
# Defines an object that is cannot be changed. You can use this to set an immutable string, or a number.
|
||||
#
|
||||
class types.ImmutableObject extends types.Operation
|
||||
class ops.ImmutableObject extends ops.Operation
|
||||
|
||||
#
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
@@ -529,7 +529,7 @@ module.exports = (HB)->
|
||||
}
|
||||
json
|
||||
|
||||
types.ImmutableObject.parse = (json)->
|
||||
ops.ImmutableObject.parse = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
'content' : content
|
||||
@@ -542,7 +542,7 @@ module.exports = (HB)->
|
||||
# This is necessary in order to have a beginning and an end even if the content
|
||||
# of the Engine is empty.
|
||||
#
|
||||
class types.Delimiter extends types.Operation
|
||||
class ops.Delimiter extends ops.Operation
|
||||
#
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
# @param {Operation} prev_cl The predecessor of this operation in the complete-list (cl)
|
||||
@@ -601,7 +601,7 @@ module.exports = (HB)->
|
||||
'next' : @next_cl?.getUid()
|
||||
}
|
||||
|
||||
types.Delimiter.parse = (json)->
|
||||
ops.Delimiter.parse = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
'prev' : prev
|
||||
@@ -611,7 +611,7 @@ module.exports = (HB)->
|
||||
|
||||
# This is what this module exports after initializing it with the HistoryBuffer
|
||||
{
|
||||
'types' : types
|
||||
'operations' : ops
|
||||
'execution_listener' : execution_listener
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
text_types_uninitialized = require "./TextTypes"
|
||||
text_ops_uninitialized = require "./Text"
|
||||
|
||||
module.exports = (HB)->
|
||||
text_types = text_types_uninitialized HB
|
||||
types = text_types.types
|
||||
module.exports = ()->
|
||||
text_ops = text_ops_uninitialized()
|
||||
ops = text_ops.operations
|
||||
|
||||
#
|
||||
# Manages Object-like values.
|
||||
#
|
||||
class types.Object extends types.MapManager
|
||||
class ops.Object extends ops.MapManager
|
||||
|
||||
#
|
||||
# Identifies this class.
|
||||
@@ -40,11 +40,11 @@ module.exports = (HB)->
|
||||
val = @val()
|
||||
json = {}
|
||||
for name, o of val
|
||||
if o instanceof types.Object
|
||||
if o instanceof ops.Object
|
||||
json[name] = o.toJson(transform_to_value)
|
||||
else if o instanceof types.ListManager
|
||||
else if o instanceof ops.ListManager
|
||||
json[name] = o.toJson(transform_to_value)
|
||||
else if transform_to_value and o instanceof types.Operation
|
||||
else if transform_to_value and o instanceof ops.Operation
|
||||
json[name] = o.val()
|
||||
else
|
||||
json[name] = o
|
||||
@@ -58,7 +58,7 @@ module.exports = (HB)->
|
||||
that.val(event.name, event.object[event.name])
|
||||
@observe (events)->
|
||||
for event in events
|
||||
if event.created_ isnt HB.getUserId()
|
||||
if event.created_ isnt @HB.getUserId()
|
||||
notifier = Object.getNotifier(that.bound_json)
|
||||
oldVal = that.bound_json[event.name]
|
||||
if oldVal?
|
||||
@@ -102,7 +102,7 @@ module.exports = (HB)->
|
||||
val: (name, content)->
|
||||
if name? and arguments.length > 1
|
||||
if content? and content.constructor?
|
||||
type = types[content.constructor.name]
|
||||
type = ops[content.constructor.name]
|
||||
if type? and type.create?
|
||||
args = []
|
||||
for i in [1...arguments.length]
|
||||
@@ -125,23 +125,23 @@ module.exports = (HB)->
|
||||
'uid' : @getUid()
|
||||
}
|
||||
|
||||
types.Object.parse = (json)->
|
||||
ops.Object.parse = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
} = json
|
||||
new this(uid)
|
||||
|
||||
types.Object.create = (content, mutable)->
|
||||
json = new types.Object().execute()
|
||||
ops.Object.create = (content, mutable)->
|
||||
json = new ops.Object().execute()
|
||||
for n,o of content
|
||||
json.val n, o, mutable
|
||||
json
|
||||
|
||||
|
||||
types.Number = {}
|
||||
types.Number.create = (content)->
|
||||
ops.Number = {}
|
||||
ops.Number.create = (content)->
|
||||
content
|
||||
|
||||
text_types
|
||||
text_ops
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
basic_types_uninitialized = require "./BasicTypes"
|
||||
basic_ops_uninitialized = require "./Basic"
|
||||
|
||||
module.exports = (HB)->
|
||||
basic_types = basic_types_uninitialized HB
|
||||
types = basic_types.types
|
||||
module.exports = ()->
|
||||
basic_ops = basic_ops_uninitialized()
|
||||
ops = basic_ops.operations
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# Manages map like objects. E.g. Json-Type and XML attributes.
|
||||
#
|
||||
class types.MapManager extends types.Operation
|
||||
class ops.MapManager extends ops.Operation
|
||||
|
||||
#
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
@@ -28,7 +28,7 @@ module.exports = (HB)->
|
||||
super()
|
||||
|
||||
#
|
||||
# @see JsonTypes.val
|
||||
# @see JsonOperations.val
|
||||
#
|
||||
val: (name, content)->
|
||||
if arguments.length > 1
|
||||
@@ -60,7 +60,7 @@ module.exports = (HB)->
|
||||
noOperation: true
|
||||
sub: property_name
|
||||
alt: @
|
||||
rm = new types.ReplaceManager event_properties, event_this, rm_uid # this operation shall not be saved in the HB
|
||||
rm = new ops.ReplaceManager event_properties, event_this, rm_uid # this operation shall not be saved in the HB
|
||||
@map[property_name] = rm
|
||||
rm.setParent @, property_name
|
||||
rm.execute()
|
||||
@@ -70,7 +70,7 @@ module.exports = (HB)->
|
||||
# @nodoc
|
||||
# Manages a list of Insert-type operations.
|
||||
#
|
||||
class types.ListManager extends types.Operation
|
||||
class ops.ListManager extends ops.Operation
|
||||
|
||||
#
|
||||
# A ListManager maintains a non-empty list that has a beginning and an end (both Delimiters!)
|
||||
@@ -78,8 +78,8 @@ module.exports = (HB)->
|
||||
# @param {Delimiter} beginning Reference or Object.
|
||||
# @param {Delimiter} end Reference or Object.
|
||||
constructor: (uid)->
|
||||
@beginning = new types.Delimiter undefined, undefined
|
||||
@end = new types.Delimiter @beginning, undefined
|
||||
@beginning = new ops.Delimiter undefined, undefined
|
||||
@end = new ops.Delimiter @beginning, undefined
|
||||
@beginning.next_cl = @end
|
||||
@beginning.execute()
|
||||
@end.execute()
|
||||
@@ -100,11 +100,11 @@ module.exports = (HB)->
|
||||
toJson: (transform_to_value = false)->
|
||||
val = @val()
|
||||
for i, o in val
|
||||
if o instanceof types.Object
|
||||
if o instanceof ops.Object
|
||||
o.toJson(transform_to_value)
|
||||
else if o instanceof types.ListManager
|
||||
else if o instanceof ops.ListManager
|
||||
o.toJson(transform_to_value)
|
||||
else if transform_to_value and o instanceof types.Operation
|
||||
else if transform_to_value and o instanceof ops.Operation
|
||||
o.val()
|
||||
else
|
||||
o
|
||||
@@ -160,7 +160,7 @@ module.exports = (HB)->
|
||||
val: (pos)->
|
||||
if pos?
|
||||
o = @getOperationByPosition(pos+1)
|
||||
if not (o instanceof types.Delimiter)
|
||||
if not (o instanceof ops.Delimiter)
|
||||
o.val()
|
||||
else
|
||||
throw new Error "this position does not exist"
|
||||
@@ -177,7 +177,7 @@ module.exports = (HB)->
|
||||
o = @beginning
|
||||
while true
|
||||
# find the i-th op
|
||||
if o instanceof types.Delimiter and o.prev_cl?
|
||||
if o instanceof ops.Delimiter and o.prev_cl?
|
||||
# the user or you gave a position parameter that is to big
|
||||
# for the current array. Therefore we reach a Delimiter.
|
||||
# Then, we'll just return the last character.
|
||||
@@ -199,7 +199,7 @@ module.exports = (HB)->
|
||||
insertAfter: (left, content, options)->
|
||||
createContent = (content, options)->
|
||||
if content? and content.constructor?
|
||||
type = types[content.constructor.name]
|
||||
type = ops[content.constructor.name]
|
||||
if type? and type.create?
|
||||
type.create content, options
|
||||
else
|
||||
@@ -212,11 +212,11 @@ module.exports = (HB)->
|
||||
right = right.next_cl # find the first character to the right, that is not deleted. In the case that position is 0, its the Delimiter.
|
||||
left = right.prev_cl
|
||||
|
||||
if content instanceof types.Operation
|
||||
(new types.Insert content, undefined, left, right).execute()
|
||||
if content instanceof ops.Operation
|
||||
(new ops.Insert content, undefined, left, right).execute()
|
||||
else
|
||||
for c in content
|
||||
tmp = (new types.Insert createContent(c, options), undefined, left, right).execute()
|
||||
tmp = (new ops.Insert createContent(c, options), undefined, left, right).execute()
|
||||
left = tmp
|
||||
@
|
||||
|
||||
@@ -241,11 +241,11 @@ module.exports = (HB)->
|
||||
|
||||
delete_ops = []
|
||||
for i in [0...length]
|
||||
if o instanceof types.Delimiter
|
||||
if o instanceof ops.Delimiter
|
||||
break
|
||||
d = (new types.Delete undefined, o).execute()
|
||||
d = (new ops.Delete undefined, o).execute()
|
||||
o = o.next_cl
|
||||
while (not (o instanceof types.Delimiter)) and o.isDeleted()
|
||||
while (not (o instanceof ops.Delimiter)) and o.isDeleted()
|
||||
o = o.next_cl
|
||||
delete_ops.push d._encode()
|
||||
@
|
||||
@@ -261,16 +261,16 @@ module.exports = (HB)->
|
||||
}
|
||||
json
|
||||
|
||||
types.ListManager.parse = (json)->
|
||||
ops.ListManager.parse = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
} = json
|
||||
new this(uid)
|
||||
|
||||
types.Array = ()->
|
||||
types.Array.create = (content, mutable)->
|
||||
ops.Array = ()->
|
||||
ops.Array.create = (content, mutable)->
|
||||
if (mutable is "mutable")
|
||||
list = new types.ListManager().execute()
|
||||
list = new ops.ListManager().execute()
|
||||
ith = list.getOperationByPosition 0
|
||||
list.insertAfter ith, content
|
||||
list
|
||||
@@ -288,7 +288,7 @@ module.exports = (HB)->
|
||||
# The TextType-type has implemented support for replace
|
||||
# @see TextType
|
||||
#
|
||||
class types.ReplaceManager extends types.ListManager
|
||||
class ops.ReplaceManager extends ops.ListManager
|
||||
#
|
||||
# @param {Object} event_properties Decorates the event that is thrown by the RM
|
||||
# @param {Object} event_this The object on which the event shall be executed
|
||||
@@ -336,7 +336,7 @@ module.exports = (HB)->
|
||||
#
|
||||
replace: (content, replaceable_uid)->
|
||||
o = @getLastOperation()
|
||||
relp = (new types.Replaceable content, @, replaceable_uid, o, o.next_cl).execute()
|
||||
relp = (new ops.Replaceable content, @, replaceable_uid, o, o.next_cl).execute()
|
||||
# TODO: delete repl (for debugging)
|
||||
undefined
|
||||
|
||||
@@ -344,7 +344,7 @@ module.exports = (HB)->
|
||||
@getLastOperation().isDeleted()
|
||||
|
||||
deleteContent: ()->
|
||||
(new types.Delete undefined, @getLastOperation().uid).execute()
|
||||
(new ops.Delete undefined, @getLastOperation().uid).execute()
|
||||
undefined
|
||||
|
||||
#
|
||||
@@ -353,7 +353,7 @@ module.exports = (HB)->
|
||||
#
|
||||
val: ()->
|
||||
o = @getLastOperation()
|
||||
#if o instanceof types.Delimiter
|
||||
#if o instanceof ops.Delimiter
|
||||
# throw new Error "Replace Manager doesn't contain anything."
|
||||
o.val?() # ? - for the case that (currently) the RM does not contain anything (then o is a Delimiter)
|
||||
|
||||
@@ -375,7 +375,7 @@ module.exports = (HB)->
|
||||
# The ReplaceManager manages Replaceables.
|
||||
# @see ReplaceManager
|
||||
#
|
||||
class types.Replaceable extends types.Insert
|
||||
class ops.Replaceable extends ops.Insert
|
||||
|
||||
#
|
||||
# @param {Operation} content The value that this Replaceable holds.
|
||||
@@ -411,7 +411,7 @@ module.exports = (HB)->
|
||||
#
|
||||
# This is called, when the Insert-type was successfully executed.
|
||||
# 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.
|
||||
# done with execute. But currently, there are no specital Insert-ops for ListManager.
|
||||
#
|
||||
callOperationSpecificInsertEvents: ()->
|
||||
if @next_cl.type is "Delimiter" and @prev_cl.type isnt "Delimiter"
|
||||
@@ -461,7 +461,7 @@ module.exports = (HB)->
|
||||
else if @origin isnt @prev_cl
|
||||
json.origin = @origin.getUid()
|
||||
|
||||
if @content instanceof types.Operation
|
||||
if @content instanceof ops.Operation
|
||||
json['content'] = @content.getUid()
|
||||
else
|
||||
# This could be a security concern.
|
||||
@@ -471,7 +471,7 @@ module.exports = (HB)->
|
||||
json['content'] = @content
|
||||
json
|
||||
|
||||
types.Replaceable.parse = (json)->
|
||||
ops.Replaceable.parse = (json)->
|
||||
{
|
||||
'content' : content
|
||||
'parent' : parent
|
||||
@@ -484,7 +484,7 @@ module.exports = (HB)->
|
||||
new this(content, parent, uid, prev, next, origin, is_deleted)
|
||||
|
||||
|
||||
basic_types
|
||||
basic_ops
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
structured_types_uninitialized = require "./StructuredTypes"
|
||||
structured_ops_uninitialized = require "./Structured"
|
||||
|
||||
module.exports = (HB)->
|
||||
structured_types = structured_types_uninitialized HB
|
||||
types = structured_types.types
|
||||
parser = structured_types.parser
|
||||
module.exports = ()->
|
||||
structured_ops = structured_ops_uninitialized()
|
||||
ops = structured_ops.operations
|
||||
|
||||
#
|
||||
# Handles a String-like data structures with support for insert/delete at a word-position.
|
||||
# @note Currently, only Text is supported!
|
||||
#
|
||||
class types.String extends types.ListManager
|
||||
class ops.String extends ops.ListManager
|
||||
|
||||
#
|
||||
# @private
|
||||
@@ -287,15 +286,15 @@ module.exports = (HB)->
|
||||
}
|
||||
json
|
||||
|
||||
types.String.parse = (json)->
|
||||
ops.String.parse = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
} = json
|
||||
new this(uid)
|
||||
|
||||
types.String.create = (content, mutable)->
|
||||
ops.String.create = (content, mutable)->
|
||||
if (mutable is "mutable")
|
||||
word = new types.String().execute()
|
||||
word = new ops.String().execute()
|
||||
word.insert 0, content
|
||||
word
|
||||
else if (not mutable?) or (mutable is "immutable")
|
||||
@@ -304,6 +303,6 @@ module.exports = (HB)->
|
||||
throw new Error "Specify either \"mutable\" or \"immutable\"!!"
|
||||
|
||||
|
||||
structured_types
|
||||
structured_ops
|
||||
|
||||
|
||||
38
lib/y.coffee
38
lib/y.coffee
@@ -1,5 +1,6 @@
|
||||
|
||||
json_types_uninitialized = require "./Types/JsonTypes"
|
||||
json_ops_uninitialized = require "./Operations/Json"
|
||||
|
||||
HistoryBuffer = require "./HistoryBuffer"
|
||||
Engine = require "./Engine"
|
||||
adaptConnector = require "./ConnectorAdapter"
|
||||
@@ -14,34 +15,19 @@ createY = (connector)->
|
||||
user_id = id
|
||||
HB.resetUserId id
|
||||
HB = new HistoryBuffer user_id
|
||||
type_manager = json_types_uninitialized HB
|
||||
types = type_manager.types
|
||||
ops_manager = json_ops_uninitialized HB, this.constructor
|
||||
ops = ops_manager.operations
|
||||
|
||||
#
|
||||
# Framework for Json data-structures.
|
||||
# Known values that are supported:
|
||||
# * String
|
||||
# * Integer
|
||||
# * Array
|
||||
#
|
||||
class Y extends types.Object
|
||||
engine = new Engine HB, ops
|
||||
adaptConnector connector, engine, HB, ops_manager.execution_listener
|
||||
|
||||
#
|
||||
# @param {String} user_id Unique id of the peer.
|
||||
# @param {Connector} Connector the connector class.
|
||||
#
|
||||
constructor: ()->
|
||||
@connector = connector
|
||||
@HB = HB
|
||||
@types = types
|
||||
@engine = new Engine @HB, type_manager.types
|
||||
adaptConnector @connector, @engine, @HB, type_manager.execution_listener
|
||||
super
|
||||
ops.Operation.prototype.HB = HB
|
||||
ops.Operation.prototype.operations = ops
|
||||
ops.Operation.prototype.engine = engine
|
||||
ops.Operation.prototype.connector = connector
|
||||
ops.Operation.prototype.custom_ops = this.constructor
|
||||
|
||||
getConnector: ()->
|
||||
@connector
|
||||
|
||||
return new Y(HB.getReservedUniqueIdentifier()).execute()
|
||||
return new ops.Object(HB.getReservedUniqueIdentifier()).execute()
|
||||
|
||||
module.exports = createY
|
||||
if window? and not window.Y?
|
||||
|
||||
Reference in New Issue
Block a user