iwc client fixes

This commit is contained in:
Kevin Jahns
2014-08-04 14:20:51 +02:00
parent 8169b17eb4
commit 5ba735701c
73 changed files with 2872 additions and 969 deletions

View File

@@ -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

View File

@@ -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)=>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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] = {}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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