iwc client fixes
This commit is contained in:
@@ -16,7 +16,11 @@ createIwcConnector = (callback)->
|
||||
root_element = null
|
||||
received_HB = null
|
||||
|
||||
|
||||
#
|
||||
# The Iwc Connector adds support for the Inter-Widget-Communication protocol that is used in the Role-SDK.
|
||||
# @see http://dbis.rwth-aachen.de/cms/projects/the-xmpp-experience#interwidget-communication
|
||||
# @see http://dbis.rwth-aachen.de/cms/projects/ROLE
|
||||
#
|
||||
class IwcConnector
|
||||
constructor: (@engine, @HB, @execution_listener, @yatta)->
|
||||
@duiClient = duiClient
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
_ = require "underscore"
|
||||
|
||||
module.exports = (user_list)->
|
||||
|
||||
#
|
||||
# A trivial Connector that simulates network delay.
|
||||
#
|
||||
class TestConnector
|
||||
constructor: (@engine, @HB, @execution_listener)->
|
||||
send_ = (o)=>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
#
|
||||
# The Engine handles how and in which order to execute operations and add operations to the HistoryBuffer.
|
||||
#
|
||||
class Engine
|
||||
constructor: (@HB, @parser)->
|
||||
@unprocessed_ops = []
|
||||
@@ -10,7 +13,6 @@ class Engine
|
||||
else
|
||||
throw new Error "You forgot to specify a parser for type #{json.type}. The message is #{JSON.stringify json}."
|
||||
|
||||
# TODO:
|
||||
applyOps: (ops_json)->
|
||||
ops = []
|
||||
for o in ops_json
|
||||
|
||||
@@ -3,6 +3,9 @@ json_types_uninitialized = require "../Types/JsonTypes.coffee"
|
||||
HistoryBuffer = require "../HistoryBuffer.coffee"
|
||||
Engine = require "../Engine.coffee"
|
||||
|
||||
#
|
||||
# Framework for arbitrary Json data-structures.
|
||||
#
|
||||
class JsonYatta
|
||||
constructor: (user_id, Connector)->
|
||||
@HB = new HistoryBuffer user_id
|
||||
|
||||
@@ -3,6 +3,9 @@ text_types_uninitialized = require "../Types/TextTypes.coffee"
|
||||
HistoryBuffer = require "../HistoryBuffer.coffee"
|
||||
Engine = require "../Engine.coffee"
|
||||
|
||||
#
|
||||
# Framework for Text Datastructures.
|
||||
#
|
||||
class TextYatta
|
||||
constructor: (user_id, Connector)->
|
||||
@HB = new HistoryBuffer user_id
|
||||
|
||||
@@ -5,21 +5,25 @@
|
||||
# @note The HistoryBuffer is commonly abbreviated to HB.
|
||||
#
|
||||
class HistoryBuffer
|
||||
# @overload new HistoryBuffer()
|
||||
# Creates an empty HB.
|
||||
# @param {Object} user_id Creator of the HB.
|
||||
# @overload new HistoryBuffer(initial_content)
|
||||
# Creates an HB with initial operations that represent the initial_value.
|
||||
# @param {Array<Object>} initial_content Initial content of the DUC
|
||||
# @see DUC DUC - Document Under Collaboration
|
||||
|
||||
#
|
||||
# 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
|
||||
|
||||
#
|
||||
# Get the operation counter that describes the current state of the document.
|
||||
#
|
||||
getOperationCounter: ()->
|
||||
res = {}
|
||||
for user,ctn of @operation_counter
|
||||
@@ -34,9 +38,10 @@ class HistoryBuffer
|
||||
json.push o.toJson()
|
||||
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.
|
||||
# You'll get new results only if you added the operation with $addOperation.
|
||||
# This will increment the operation counter.
|
||||
#
|
||||
getNextOperationIdentifier: (user_id)->
|
||||
if not user_id?
|
||||
@@ -59,7 +64,7 @@ class HistoryBuffer
|
||||
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 be executable)
|
||||
# other operations (it wont executed)
|
||||
addOperation: (o)->
|
||||
if not @buffer[o.creator]?
|
||||
@buffer[o.creator] = {}
|
||||
|
||||
@@ -6,15 +6,29 @@ module.exports = (HB)->
|
||||
#
|
||||
# A generic interface to operations.
|
||||
#
|
||||
# An operation has the following methods:
|
||||
# toJson: encodes an operation (needed only if instance of this operation is sent).
|
||||
# execute: execute the effects of this operations. Good examples are Insert-type and AddName-type
|
||||
# val: in the case that the operation holds a value
|
||||
#
|
||||
# Furthermore an encodable operation has a parser.
|
||||
#
|
||||
class Operation
|
||||
# @param {Object} uid A unique identifier
|
||||
# @see HistoryBuffer.getNextOperationIdentifier
|
||||
constructor: ({'creator': @creator, 'op_number' : @op_number})->
|
||||
constructor: (uid)->
|
||||
{
|
||||
'creator': @creator
|
||||
'op_number' : @op_number
|
||||
} = uid
|
||||
|
||||
# Computes a unique identifier (uid).
|
||||
getUid: ()->
|
||||
{ 'creator': @creator, 'op_number': @op_number }
|
||||
|
||||
#
|
||||
# Notify the all the listeners.
|
||||
#
|
||||
execute: ()->
|
||||
@is_executed = true
|
||||
for l in execution_listener
|
||||
@@ -22,13 +36,14 @@ module.exports = (HB)->
|
||||
@
|
||||
|
||||
#
|
||||
# Operations may depend on other operations (linked lists, etc.). The saveOperation and validateSavedOperations methods provide
|
||||
# Operations may depend on other operations (linked lists, etc.).
|
||||
# The saveOperation and validateSavedOperations methods provide
|
||||
# an easy way to refer to these operations via an uid or object reference.
|
||||
#
|
||||
# For example: We can create a new Delete operation that deletes the operation $o like this
|
||||
# - var d = new Delete(uid, $o); or
|
||||
# - var d = new Delete(uid, $o.getUid());
|
||||
# Either way we want to access $o via d.deletes. This is possible after calling validateSavedOperations.
|
||||
# Either way we want to access $o via d.deletes. In the second case validateSavedOperations must be called first.
|
||||
#
|
||||
# @overload saveOperation(name, op_uid)
|
||||
# @param {String} name The name of the operation. After validating (with validateSavedOperations) the instantiated operation will be accessible via this[name].
|
||||
@@ -38,9 +53,12 @@ module.exports = (HB)->
|
||||
# @param {Operation} op An Operation object
|
||||
#
|
||||
saveOperation: (name, op)->
|
||||
|
||||
#
|
||||
# Every instance of $Operation must have an $execute function.
|
||||
# We use duck-typing to check if op is instantiated since there
|
||||
# could exist multiple classes of $Operation
|
||||
#
|
||||
if op?.execute?
|
||||
# is instantiated
|
||||
@[name] = op
|
||||
@@ -73,7 +91,7 @@ module.exports = (HB)->
|
||||
|
||||
|
||||
#
|
||||
# A simple delete-type operation.
|
||||
# A simple Delete-type operation that deletes an Insert-type operation.
|
||||
#
|
||||
class Delete extends Operation
|
||||
constructor: (uid, deletes)->
|
||||
@@ -91,6 +109,9 @@ module.exports = (HB)->
|
||||
'deletes': @deletes.getUid()
|
||||
}
|
||||
|
||||
#
|
||||
# Apply the deletion.
|
||||
#
|
||||
execute: ()->
|
||||
if @validateSavedOperations()
|
||||
@deletes.applyDelete @
|
||||
@@ -100,9 +121,13 @@ module.exports = (HB)->
|
||||
false
|
||||
|
||||
#
|
||||
# Define how to parse $Delete operations.
|
||||
# Define how to parse Delete operations.
|
||||
#
|
||||
parser['Delete'] = ({'uid' : uid, 'deletes': deletes_uid})->
|
||||
parser['Delete'] = (o)->
|
||||
{
|
||||
'uid' : uid
|
||||
'deletes': deletes_uid
|
||||
} = o
|
||||
new Delete uid, deletes_uid
|
||||
|
||||
#
|
||||
@@ -115,12 +140,15 @@ module.exports = (HB)->
|
||||
# - The complete-list (abbrev. cl) maintains all operations
|
||||
#
|
||||
class Insert extends Operation
|
||||
|
||||
#
|
||||
# @param {Object} creator A unique user identifier
|
||||
# @param {Integer} op_number This Number was assigned via getNextOperationIdentifier().
|
||||
# @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
|
||||
|
||||
@@ -5,6 +5,9 @@ module.exports = (HB)->
|
||||
types = text_types.types
|
||||
parser = text_types.parser
|
||||
|
||||
#
|
||||
# Manages Object-like values.
|
||||
#
|
||||
class JsonType extends types.MapManager
|
||||
constructor: (uid, initial_value)->
|
||||
super uid
|
||||
@@ -14,18 +17,32 @@ module.exports = (HB)->
|
||||
for name,o of initial_value
|
||||
@val name, o
|
||||
|
||||
#
|
||||
# Get this as a Json object. Note that none of the values of the result is of type Operation.
|
||||
# @overload val()
|
||||
# @results [Json]
|
||||
#
|
||||
# Get value of a property.
|
||||
# @overload val(name)
|
||||
# @param {String} name Name of the object property.
|
||||
# @results [JsonType|WordType]
|
||||
#
|
||||
# Set a new property.
|
||||
# @overload val(name, content)
|
||||
# @param {String} name Name of the object property.
|
||||
# @param {Object|String} content Content of the object property.
|
||||
#
|
||||
val: (name, content)->
|
||||
if name? and content?
|
||||
if typeof content is 'string'
|
||||
word = HB.addOperation(new types.Word HB.getNextOperationIdentifier(), content).execute()
|
||||
super name, word
|
||||
content
|
||||
else if typeof content is 'object'
|
||||
json = HB.addOperation(JsonType HB.getNextOperationIdentifier(), content).execute()
|
||||
super name, json
|
||||
content
|
||||
else
|
||||
throw new Error "You must not set #{typeof content}-types in collaborative Json-objects!"
|
||||
@
|
||||
else
|
||||
super name, content
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ module.exports = (HB)->
|
||||
types = basic_types.types
|
||||
parser = basic_types.parser
|
||||
|
||||
#
|
||||
# Manages map like objects. E.g. Json-Type and XML attributes.
|
||||
#
|
||||
class MapManager extends types.Operation
|
||||
constructor: (uid)->
|
||||
@map = {}
|
||||
@@ -23,6 +26,12 @@ module.exports = (HB)->
|
||||
result[name] = o.val()
|
||||
result
|
||||
|
||||
#
|
||||
# When a new property in a map manager is created, then the uids of the inserted Operations
|
||||
# must be unique (think about concurrent operations). Therefore only an AddName operation is allowed to
|
||||
# add a property in a MapManager. If two AddName operations on the same MapManager name happen concurrently
|
||||
# only one will AddName operation will be executed.
|
||||
#
|
||||
class AddName extends types.Operation
|
||||
constructor: (uid, map_manager, @name)->
|
||||
@saveOperation 'map_manager', map_manager
|
||||
@@ -61,7 +70,9 @@ module.exports = (HB)->
|
||||
} = json
|
||||
new AddName uid, map_manager, name
|
||||
|
||||
|
||||
#
|
||||
# Manages a list of Insert-type operations.
|
||||
#
|
||||
class ListManager extends types.Insert
|
||||
constructor: (uid, beginning, end, prev, next, origin)->
|
||||
if beginning? and end?
|
||||
@@ -110,7 +121,13 @@ module.exports = (HB)->
|
||||
throw new Error "position parameter exceeded the length of the document!"
|
||||
o
|
||||
|
||||
|
||||
#
|
||||
# Adds support for replace. The ReplaceManager manages Replaceable operations.
|
||||
# Each Replaceable holds a value that is now replaceable.
|
||||
#
|
||||
# The Word-type has implemented support for replace
|
||||
# @see Word
|
||||
#
|
||||
class ReplaceManager extends ListManager
|
||||
constructor: (initial_content, uid, beginning, end, prev, next, origin)->
|
||||
super uid, beginning, end, prev, next, origin
|
||||
@@ -157,7 +174,8 @@ module.exports = (HB)->
|
||||
|
||||
|
||||
#
|
||||
# Extends the basic Insert type.
|
||||
# The ReplaceManager manages Replaceables.
|
||||
# @see ReplaceManager
|
||||
#
|
||||
class Replaceable extends types.Insert
|
||||
constructor: (content, parent, uid, prev, next, origin)->
|
||||
@@ -167,8 +185,6 @@ module.exports = (HB)->
|
||||
throw new Error "You must define content, prev, and next for Replaceable-types!"
|
||||
super uid, prev, next, origin
|
||||
|
||||
#
|
||||
#
|
||||
val: ()->
|
||||
@content
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ module.exports = (HB)->
|
||||
parser["TextDelete"] = parser["Delete"]
|
||||
|
||||
#
|
||||
# Extends the basic Insert type.
|
||||
# Extends the basic Insert type to an operation that holds a text value
|
||||
#
|
||||
class TextInsert extends types.Insert
|
||||
constructor: (@content, uid, prev, next, origin)->
|
||||
@@ -67,20 +67,26 @@ module.exports = (HB)->
|
||||
} = json
|
||||
new TextInsert content, uid, prev, next, origin
|
||||
|
||||
#
|
||||
# Handles a Text-like data structures with support for insertText/deleteText at a word-position.
|
||||
#
|
||||
class Word extends types.ListManager
|
||||
constructor: (uid, initial_content, beginning, end, prev, next, origin)->
|
||||
super uid, beginning, end, prev, next, origin
|
||||
if initial_content?
|
||||
@insertText 0, initial_content
|
||||
|
||||
# inserts a
|
||||
#
|
||||
# Inserts a string into the word
|
||||
#
|
||||
insertText: (position, content)->
|
||||
o = @getOperationByPosition position
|
||||
for c in content
|
||||
op = new TextInsert c, HB.getNextOperationIdentifier(), o.prev_cl, o
|
||||
HB.addOperation(op).execute()
|
||||
|
||||
# Creates a set of delete operations
|
||||
#
|
||||
# Deletes a part of the word.
|
||||
#
|
||||
deleteText: (position, length)->
|
||||
o = @getOperationByPosition position
|
||||
|
||||
@@ -93,6 +99,13 @@ module.exports = (HB)->
|
||||
o = o.next_cl
|
||||
d.toJson()
|
||||
|
||||
#
|
||||
# Replace the content of this word with another one. Concurrent replacements are not merged!
|
||||
# Only one of the replacements will be used.
|
||||
#
|
||||
# Can only be used if the ReplaceManager was set!
|
||||
# @see Word.setReplaceManager
|
||||
#
|
||||
replaceText: (text)->
|
||||
if @replace_manager?
|
||||
word = HB.addOperation(new Word HB.getNextOperationIdentifier()).execute()
|
||||
@@ -101,6 +114,9 @@ module.exports = (HB)->
|
||||
else
|
||||
throw new Error "This type is currently not maintained by a ReplaceManager!"
|
||||
|
||||
#
|
||||
# @returns [Json] A Json object.
|
||||
#
|
||||
val: ()->
|
||||
c = for o in @toArray()
|
||||
if o.val?
|
||||
@@ -109,6 +125,10 @@ module.exports = (HB)->
|
||||
""
|
||||
c.join('')
|
||||
|
||||
#
|
||||
# In most cases you would embed a Word in a Replaceable, wich is handled by the ReplaceManager in order
|
||||
# to provide replace functionality.
|
||||
#
|
||||
setReplaceManager: (op)->
|
||||
@saveOperation 'replace_manager', op
|
||||
@validateSavedOperations
|
||||
|
||||
Reference in New Issue
Block a user