Documentation and cleanup
This commit is contained in:
@@ -4,14 +4,17 @@ module.exports = (HB)->
|
||||
execution_listener = []
|
||||
|
||||
#
|
||||
# @private
|
||||
# @abstract
|
||||
# @nodoc
|
||||
# A generic interface to operations.
|
||||
#
|
||||
# An operation has the following methods:
|
||||
# _encode: 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
|
||||
# * _encode: 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.
|
||||
# Furthermore an encodable operation has a parser. We extend the parser object in order to parse encoded operations.
|
||||
#
|
||||
class Operation
|
||||
|
||||
@@ -40,6 +43,16 @@ module.exports = (HB)->
|
||||
@event_listeners[e] ?= []
|
||||
@event_listeners[e].push f
|
||||
|
||||
#
|
||||
# Deletes a function from an event / list of events.
|
||||
# @see Operation.on
|
||||
#
|
||||
# @overload deleteListener(event, f)
|
||||
# @param event {String} An event name
|
||||
# @param f {Function} The function that you want to delete from these events
|
||||
# @overload deleteListener(events, f)
|
||||
# @param events {Array<String>} A list of event names
|
||||
# @param f {Function} The function that you want to delete from these events.
|
||||
deleteListener: (events, f)->
|
||||
if events.constructor isnt [].constructor
|
||||
events = [events]
|
||||
@@ -148,6 +161,7 @@ module.exports = (HB)->
|
||||
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# A simple Delete-type operation that deletes an Insert-type operation.
|
||||
#
|
||||
class Delete extends Operation
|
||||
@@ -194,6 +208,7 @@ module.exports = (HB)->
|
||||
new Delete uid, deletes_uid
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# A simple insert-type operation.
|
||||
#
|
||||
# An insert operation is always positioned between two other insert operations.
|
||||
@@ -350,7 +365,9 @@ module.exports = (HB)->
|
||||
position++
|
||||
prev = prev.prev_cl
|
||||
position
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# Defines an object that is cannot be changed. You can use this to set an immutable string, or a number.
|
||||
#
|
||||
class ImmutableObject extends Insert
|
||||
@@ -396,6 +413,7 @@ module.exports = (HB)->
|
||||
new ImmutableObject uid, content, prev, next, origin
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# A delimiter is placed at the end and at the beginning of the associative lists.
|
||||
# This is necessary in order to have a beginning and an end even if the content
|
||||
# of the Engine is empty.
|
||||
|
||||
@@ -5,15 +5,17 @@ module.exports = (HB)->
|
||||
types = text_types.types
|
||||
parser = text_types.parser
|
||||
|
||||
createJsonWrapper = (_jsonType)->
|
||||
createJsonTypeWrapper = (_jsonType)->
|
||||
|
||||
#
|
||||
# A JsonWrapper was intended to be a convenient wrapper for the JsonType.
|
||||
# @note EXPERIMENTAL
|
||||
#
|
||||
# A JsonTypeWrapper was intended to be a convenient wrapper for the JsonType.
|
||||
# But it can make things more difficult than they are.
|
||||
# @see JsonType
|
||||
#
|
||||
# @example create a JsonWrapper
|
||||
# # You get a JsonWrapper from a JsonType by calling
|
||||
# @example create a JsonTypeWrapper
|
||||
# # You get a JsonTypeWrapper from a JsonType by calling
|
||||
# w = yatta.value
|
||||
#
|
||||
# It creates Javascripts -getter and -setter methods for each property that JsonType maintains.
|
||||
@@ -34,10 +36,10 @@ module.exports = (HB)->
|
||||
# yatta.val('x', "text")
|
||||
#
|
||||
# In order to set a new property you have to overwrite an existing property.
|
||||
# Therefore the JsonWrapper supports a special feature that should make things more convenient
|
||||
# Therefore the JsonTypeWrapper supports a special feature that should make things more convenient
|
||||
# (we can argue about that, use the JsonType if you don't like it ;).
|
||||
# If you overwrite an object property of the JsonWrapper with a new object, it will result in a merged version of the objects.
|
||||
# Let w.p the property that is to be overwritten and o the new value. E.g. w.p = o
|
||||
# If you overwrite an object property of the JsonTypeWrapper with a new object, it will result in a merged version of the objects.
|
||||
# Let `yatta.value.p` the property that is to be overwritten and o the new value. E.g. `yatta.value.p = o`
|
||||
# * The result has all properties of o
|
||||
# * The result has all properties of w.p if they don't occur under the same property-name in o.
|
||||
#
|
||||
@@ -63,7 +65,7 @@ module.exports = (HB)->
|
||||
# yatta.value = {newProperty : "Awesome"}
|
||||
# console.log(w.newProperty == "Awesome") # true!
|
||||
#
|
||||
class JsonWrapper
|
||||
class JsonTypeWrapper
|
||||
|
||||
#
|
||||
# @param {JsonType} jsonType Instance of the JsonType that this class wrappes.
|
||||
@@ -71,11 +73,11 @@ module.exports = (HB)->
|
||||
constructor: (jsonType)->
|
||||
for name, obj of jsonType.map
|
||||
do (name, obj)->
|
||||
Object.defineProperty JsonWrapper.prototype, name,
|
||||
Object.defineProperty JsonTypeWrapper.prototype, name,
|
||||
get : ->
|
||||
x = obj.val()
|
||||
if x instanceof JsonType
|
||||
createJsonWrapper x
|
||||
createJsonTypeWrapper x
|
||||
else if x instanceof types.ImmutableObject
|
||||
x.val()
|
||||
else
|
||||
@@ -89,7 +91,7 @@ module.exports = (HB)->
|
||||
jsonType.val(name, o, 'immutable')
|
||||
enumerable: true
|
||||
configurable: false
|
||||
new JsonWrapper _jsonType
|
||||
new JsonTypeWrapper _jsonType
|
||||
|
||||
#
|
||||
# Manages Object-like values.
|
||||
@@ -109,6 +111,18 @@ module.exports = (HB)->
|
||||
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.
|
||||
#
|
||||
# @example
|
||||
# var x = yatta.val('unknown')
|
||||
# if (x.type === "JsonType") {
|
||||
# console.log JSON.stringify(x.toJson())
|
||||
# }
|
||||
#
|
||||
type: "JsonType"
|
||||
|
||||
#
|
||||
# Transform this to a Json and loose all the sharing-abilities (the new object will be a deep clone)!
|
||||
# @return {Json}
|
||||
@@ -128,7 +142,7 @@ module.exports = (HB)->
|
||||
json
|
||||
|
||||
#
|
||||
# @see Word.setReplaceManager
|
||||
# @see WordType.setReplaceManager
|
||||
# Sets the parent of this JsonType object.
|
||||
#
|
||||
setReplaceManager: (rm)->
|
||||
@@ -168,7 +182,7 @@ module.exports = (HB)->
|
||||
# @overload val(name)
|
||||
# Get value of a property.
|
||||
# @param {String} name Name of the object property.
|
||||
# @return [JsonType|Word|String|Object] Depending on the value of the property. If mutable it will return a Operation-type object, if immutable it will return String/Object.
|
||||
# @return [JsonType|WordType|String|Object] Depending on the value of the property. If mutable it will return a Operation-type object, if immutable it will return String/Object.
|
||||
#
|
||||
# @overload val(name, content)
|
||||
# Set a new property.
|
||||
@@ -198,7 +212,7 @@ module.exports = (HB)->
|
||||
super name, obj
|
||||
else
|
||||
if typeof content is 'string'
|
||||
word = HB.addOperation(new types.Word undefined).execute()
|
||||
word = HB.addOperation(new types.WordType undefined).execute()
|
||||
word.insertText 0, content
|
||||
super name, word
|
||||
else if content.constructor is Object
|
||||
@@ -210,7 +224,7 @@ module.exports = (HB)->
|
||||
super name, content
|
||||
|
||||
Object.defineProperty JsonType.prototype, 'value',
|
||||
get : -> createJsonWrapper @
|
||||
get : -> createJsonTypeWrapper @
|
||||
set : (o)->
|
||||
if o.constructor is {}.constructor
|
||||
for o_name,o_obj of o
|
||||
|
||||
@@ -6,6 +6,7 @@ module.exports = (HB)->
|
||||
parser = basic_types.parser
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# Manages map like objects. E.g. Json-Type and XML attributes.
|
||||
#
|
||||
class MapManager extends types.Operation
|
||||
@@ -42,6 +43,7 @@ module.exports = (HB)->
|
||||
result
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# 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
|
||||
@@ -102,6 +104,7 @@ module.exports = (HB)->
|
||||
new AddName uid, map_manager, name
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# Manages a list of Insert-type operations.
|
||||
#
|
||||
class ListManager extends types.Insert
|
||||
@@ -123,6 +126,10 @@ module.exports = (HB)->
|
||||
@end.execute()
|
||||
super uid, prev, next, origin
|
||||
|
||||
#
|
||||
# @private
|
||||
# @see Operation.execute
|
||||
#
|
||||
execute: ()->
|
||||
if @validateSavedOperations()
|
||||
@beginning.setParent @
|
||||
@@ -170,11 +177,12 @@ module.exports = (HB)->
|
||||
o
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# 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
|
||||
# The WordType-type has implemented support for replace
|
||||
# @see WordType
|
||||
#
|
||||
class ReplaceManager extends ListManager
|
||||
#
|
||||
@@ -214,8 +222,9 @@ module.exports = (HB)->
|
||||
@deleteListener 'addProperty', addPropertyListener
|
||||
@on 'insert', addPropertyListener
|
||||
super parent
|
||||
|
||||
#
|
||||
# Get the value of this Word
|
||||
# Get the value of this WordType
|
||||
# @return {String}
|
||||
#
|
||||
val: ()->
|
||||
@@ -256,6 +265,7 @@ module.exports = (HB)->
|
||||
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# The ReplaceManager manages Replaceables.
|
||||
# @see ReplaceManager
|
||||
#
|
||||
@@ -287,7 +297,7 @@ module.exports = (HB)->
|
||||
|
||||
#
|
||||
# If possible set the replace manager in the content.
|
||||
# @see Word.setReplaceManager
|
||||
# @see WordType.setReplaceManager
|
||||
#
|
||||
execute: ()->
|
||||
if not @validateSavedOperations()
|
||||
|
||||
@@ -6,6 +6,7 @@ module.exports = (HB)->
|
||||
parser = structured_types.parser
|
||||
|
||||
#
|
||||
# @nodoc
|
||||
# At the moment TextDelete type equals the Delete type in BasicTypes.
|
||||
# @see BasicTypes.Delete
|
||||
#
|
||||
@@ -13,7 +14,8 @@ module.exports = (HB)->
|
||||
parser["TextDelete"] = parser["Delete"]
|
||||
|
||||
#
|
||||
# Extends the basic Insert type to an operation that holds a text value
|
||||
# @nodoc
|
||||
# Extends the basic Insert type to an operation that holds a text value
|
||||
#
|
||||
class TextInsert extends types.Insert
|
||||
#
|
||||
@@ -72,28 +74,47 @@ module.exports = (HB)->
|
||||
new TextInsert content, uid, prev, next, origin
|
||||
|
||||
#
|
||||
# Handles a Text-like data structures with support for insertText/deleteText at a word-position.
|
||||
# Handles a WordType-like data structures with support for insertText/deleteText at a word-position.
|
||||
# @note Currently, only Text is supported!
|
||||
#
|
||||
class Word extends types.ListManager
|
||||
class WordType extends types.ListManager
|
||||
|
||||
#
|
||||
# @private
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
#
|
||||
constructor: (uid, beginning, end, prev, next, origin)->
|
||||
super uid, beginning, end, prev, next, origin
|
||||
|
||||
#
|
||||
# Inserts a string into the word
|
||||
# Identifies this class.
|
||||
# Use it to check whether this is a word-type or something else.
|
||||
#
|
||||
# @example
|
||||
# var x = yatta.val('unknown')
|
||||
# if (x.type === "WordType") {
|
||||
# console.log JSON.stringify(x.toJson())
|
||||
# }
|
||||
#
|
||||
type: "WordType"
|
||||
|
||||
#
|
||||
# Inserts a string into the word.
|
||||
#
|
||||
# @return {WordType} This WordType object.
|
||||
#
|
||||
insertText: (position, content)->
|
||||
o = @getOperationByPosition position
|
||||
for c in content
|
||||
op = new TextInsert c, undefined, o.prev_cl, o
|
||||
HB.addOperation(op).execute()
|
||||
@
|
||||
|
||||
#
|
||||
# Deletes a part of the word.
|
||||
#
|
||||
# @return {WordType} This WordType object
|
||||
#
|
||||
deleteText: (position, length)->
|
||||
o = @getOperationByPosition position
|
||||
|
||||
@@ -106,25 +127,28 @@ module.exports = (HB)->
|
||||
while not (o instanceof types.Delimiter) and o.isDeleted()
|
||||
o = o.next_cl
|
||||
delete_ops.push d._encode()
|
||||
delete_ops
|
||||
@
|
||||
|
||||
#
|
||||
# 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
|
||||
# @return {WordType} Returns the new WordType object.
|
||||
#
|
||||
replaceText: (text)->
|
||||
# Can only be used if the ReplaceManager was set!
|
||||
# @see WordType.setReplaceManager
|
||||
if @replace_manager?
|
||||
word = HB.addOperation(new Word undefined).execute()
|
||||
word = HB.addOperation(new WordType undefined).execute()
|
||||
word.insertText 0, text
|
||||
@replace_manager.replace(word)
|
||||
word
|
||||
else
|
||||
throw new Error "This type is currently not maintained by a ReplaceManager!"
|
||||
|
||||
#
|
||||
# @returns [Json] A Json object.
|
||||
# Get the String-representation of this word.
|
||||
# @return {String} The String-representation of this object.
|
||||
#
|
||||
val: ()->
|
||||
c = for o in @toArray()
|
||||
@@ -135,7 +159,15 @@ module.exports = (HB)->
|
||||
c.join('')
|
||||
|
||||
#
|
||||
# In most cases you would embed a Word in a Replaceable, wich is handled by the ReplaceManager in order
|
||||
# Same as WordType.val
|
||||
# @see WordType.val
|
||||
#
|
||||
toString: ()->
|
||||
@val()
|
||||
|
||||
#
|
||||
# @private
|
||||
# In most cases you would embed a WordType in a Replaceable, wich is handled by the ReplaceManager in order
|
||||
# to provide replace functionality.
|
||||
#
|
||||
setReplaceManager: (op)->
|
||||
@@ -145,7 +177,11 @@ module.exports = (HB)->
|
||||
@replace_manager?.callEvent 'change'
|
||||
|
||||
#
|
||||
# Bind this Word to a textfield.
|
||||
# Bind this WordType to a textfield or input field.
|
||||
#
|
||||
# @example
|
||||
# var textbox = document.getElementById("textfield");
|
||||
# yatta.bind(textbox);
|
||||
#
|
||||
bind: (textfield)->
|
||||
word = @
|
||||
@@ -250,11 +286,12 @@ module.exports = (HB)->
|
||||
|
||||
|
||||
#
|
||||
# @private
|
||||
# Encode this operation in such a way that it can be parsed by remote peers.
|
||||
#
|
||||
_encode: ()->
|
||||
json = {
|
||||
'type': "Word"
|
||||
'type': "WordType"
|
||||
'uid' : @getUid()
|
||||
'beginning' : @beginning.getUid()
|
||||
'end' : @end.getUid()
|
||||
@@ -267,7 +304,7 @@ module.exports = (HB)->
|
||||
json["origin"] = @origin.getUid()
|
||||
json
|
||||
|
||||
parser['Word'] = (json)->
|
||||
parser['WordType'] = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
'beginning' : beginning
|
||||
@@ -276,11 +313,11 @@ module.exports = (HB)->
|
||||
'next': next
|
||||
'origin' : origin
|
||||
} = json
|
||||
new Word uid, beginning, end, prev, next, origin
|
||||
new WordType uid, beginning, end, prev, next, origin
|
||||
|
||||
types['TextInsert'] = TextInsert
|
||||
types['TextDelete'] = TextDelete
|
||||
types['Word'] = Word
|
||||
types['WordType'] = WordType
|
||||
structured_types
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user