tests run fine. but it needs some more user testing

This commit is contained in:
Kevin Jahns
2014-10-02 21:14:37 +02:00
parent 968e07a8ff
commit 3415d0ee5e
56 changed files with 1329 additions and 457 deletions

View File

@@ -39,6 +39,7 @@ createPeerJsConnector = ()->
@peer = peer
@connections = {}
@new_connection_listeners = []
@peer.on 'connection', (conn)=>
@addConnection conn
@@ -82,6 +83,9 @@ createPeerJsConnector = ()->
for conn_id of @connections
conn_id
onNewConnection: (f)->
@new_connection_listeners.push f
#
# Adds an existing connection to this connector.
# @param conn {PeerJsConnection}
@@ -105,6 +109,8 @@ createPeerJsConnector = ()->
if not data.initialized
conn.send
conns: @getAllConnectionIds()
@new_connection_listeners.map (f)->
f(conn)
else if data.op?
@engine.applyOp data.op
else if data.conns?

View File

@@ -271,15 +271,18 @@ module.exports = (HB)->
#
applyDelete: (o)->
@deleted_by ?= []
callLater = false
if @parent? and not @isDeleted()
# call iff wasn't deleted earlyer
@parent.callEvent "delete", @, o
callLater = true
if o?
@deleted_by.push o
garbagecollect = false
if not (@prev_cl? and @next_cl?) or @prev_cl.isDeleted()
garbagecollect = true
super garbagecollect
if callLater
@parent.callEvent "delete", @, o
if @next_cl?.isDeleted()
# garbage collect next_cl
@next_cl.applyDelete()

View File

@@ -43,10 +43,18 @@ module.exports = (HB)->
@content.length
applyDelete: ()->
super # no braces indeed!
if @content instanceof types.Operation
@content.applyDelete()
@content = null
super
execute: ()->
if not @validateSavedOperations()
return false
else
if @content instanceof types.Operation
@content.insert_parent = @
super()
#
# The result will be concatenated with the results from the other insert operations

View File

@@ -5,15 +5,25 @@ json_types_uninitialized = require "./JsonTypes"
# For example xml.insertChild(dom) , wich inserts an element at the end, and xml.insertAfter(dom,null) wich does the same
# But yatta's proxy may be called only once!
proxy_token = false
dont_proxy = (f)->
proxy_token = true
try
f()
catch e
proxy_token = false
throw new Error e
proxy_token = false
_proxy = (f_name, f)->
old_f = @[f_name]
if old_f?
@[f_name] = ()->
if not proxy_token and not @_yatta?.isDeleted()
proxy_token = true
old_f.apply this, arguments
f.apply this, arguments
proxy_token = false
that = this
args = arguments
dont_proxy ()->
f.apply that, args
old_f.apply that, args
else
old_f.apply this, arguments
#else
@@ -48,11 +58,18 @@ module.exports = (HB)->
super(uid)
if @xml?._yatta?
d = new types.Delete undefined, @xml._yatta
HB.addOperation(d).execute()
@xml._yatta = null
if attributes? and elements?
@saveOperation 'attributes', attributes
@saveOperation 'elements', elements
else if (not attributes?) and (not elements?)
@attributes = new types.JsonType()
@attributes.setMutableDefault 'immutable'
HB.addOperation(@attributes).execute()
@elements = new types.WordType()
@elements.parent = @
@@ -67,11 +84,9 @@ module.exports = (HB)->
@attributes.val(attr.name, attr.value)
for n in @xml.childNodes
if n.nodeType is n.TEXT_NODE
word = new types.WordType()
word = new TextNodeType(undefined, n)
HB.addOperation(word).execute()
word.push n.textContent
@elements.push word
n._yatta = word
else if n.nodeType is n.ELEMENT_NODE
element = new XmlType undefined, undefined, undefined, undefined, n
HB.addOperation(element).execute()
@@ -87,10 +102,13 @@ module.exports = (HB)->
#
type: "XmlType"
applyDelete: ()->
@attributes.applyDelete()
@elements.applyDelete()
super()
applyDelete: (op)->
if @insert_parent? and not @insert_parent.isDeleted()
@insert_parent.applyDelete op
else
@attributes.applyDelete()
@elements.applyDelete()
super
cleanup: ()->
super()
@@ -98,11 +116,50 @@ module.exports = (HB)->
setXmlProxy: ()->
@xml._yatta = @
that = @
@elements.on 'insert', (event, op)->
if op.creator isnt HB.getUserId() and this is that.elements
newNode = op.content.val()
right = op.next_cl
while right? and right.isDeleted()
right = right.next_cl
rightNode = null
if right.type isnt 'Delimiter'
rightNode = right.val().val()
dont_proxy ()->
that.xml.insertBefore newNode, rightNode
@elements.on 'delete', (event, op)->
del_op = op.deleted_by[0]
if del_op? and del_op.creator isnt HB.getUserId() and this is that.elements
deleted = op.content.val()
dont_proxy ()->
that.xml.removeChild deleted
@attributes.on ['addProperty', 'change'], (event, property_name, op)->
if op.creator isnt HB.getUserId() and this is that.attributes
dont_proxy ()->
newval = op.val().val()
if newval?
that.xml.setAttribute(property_name, op.val().val())
else
that.xml.removeAttribute(property_name)
## Here are all methods that proxy the behavior of the xml
# you want to find a specific child element. Since they are carried by an Insert-Type, you want to find that Insert-Operation.
# @param child {DomElement} Dom element.
# @return {InsertType} This carries the XmlType that represents the DomElement (child). false if i couldn't find it.
#
findNode = (child)->
if not child?
throw new Error "you must specify a parameter!"
child = child._yatta
elem = that.elements.beginning.next_cl
while elem.type isnt 'Delimiter' and elem.content isnt child
@@ -112,7 +169,7 @@ module.exports = (HB)->
else
elem
insertBefore = (insertedNode, adjacentNode)->
insertBefore = (insertedNode_s, adjacentNode)->
next = null
if adjacentNode?
next = findNode adjacentNode
@@ -121,9 +178,21 @@ module.exports = (HB)->
prev = next.prev_cl
else
prev = @_yatta.elements.end.prev_cl
element = new XmlType undefined, undefined, undefined, undefined, insertedNode
HB.addOperation(element).execute()
that.elements.insertAfter prev, element
while prev.isDeleted()
prev = prev.prev_cl
inserted_nodes = null
if insertedNode_s.nodeType is insertedNode_s.DOCUMENT_FRAGMENT_NODE
child = insertedNode_s.lastChild
while child?
element = new XmlType undefined, undefined, undefined, undefined, child
HB.addOperation(element).execute()
that.elements.insertAfter prev, element
child = child.previousSibling
else
element = new XmlType undefined, undefined, undefined, undefined, insertedNode_s
HB.addOperation(element).execute()
that.elements.insertAfter prev, element
@xml._proxy 'insertBefore', insertBefore
@xml._proxy 'appendChild', insertBefore
@xml._proxy 'removeAttribute', (name)->
@@ -131,8 +200,16 @@ module.exports = (HB)->
@xml._proxy 'setAttribute', (name, value)->
that.attributes.val name, value
renewClassList = ()->
that.attributes.val('class', Array.prototype.join.call this, " ")
renewClassList = (newclass)->
dont_do_it = false
if newclass?
for elem in this
if newclass is elem
dont_do_it = true
value = Array.prototype.join.call this, " "
if newclass? and not dont_do_it
value += " "+newclass
that.attributes.val('class', value )
_proxy.call @xml.classList, 'add', renewClassList
_proxy.call @xml.classList, 'remove', renewClassList
@xml.__defineSetter__ 'className', (val)->
@@ -158,6 +235,7 @@ module.exports = (HB)->
throw new Error "You are only allowed to delete existing (direct) child elements!"
d = new types.Delete undefined, elem
HB.addOperation(d).execute()
node._yatta = null
@xml._proxy 'removeChild', removeChild
@xml._proxy 'replaceChild', (insertedNode, replacedNode)->
insertBefore.call this, insertedNode, replacedNode
@@ -180,12 +258,11 @@ module.exports = (HB)->
e = @elements.beginning.next_cl
while e.type isnt "Delimiter"
n = e.content
if not e.isDeleted()
if not e.isDeleted() and e.content? # TODO: how can this happen? Probably because listeners
if n.type is "XmlType"
@xml.appendChild n.val(enforce)
else if n.type is "WordType"
text_node = document.createTextNode n.val()
text_node._yatta = @
else if n.type is "TextNodeType"
text_node = n.val()
@xml.appendChild text_node
else
throw new Error "Internal structure cannot be transformed to dom"
@@ -238,6 +315,51 @@ module.exports = (HB)->
new XmlType uid, tagname, attributes, elements, undefined
#
# @nodoc
# Defines an object that is cannot be changed. You can use this to set an immutable string, or a number.
#
class TextNodeType extends types.ImmutableObject
#
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
# @param {Object} content
#
constructor: (uid, content)->
if content._yatta?
d = new types.Delete undefined, content._yatta
HB.addOperation(d).execute()
content._yatta = null
content._yatta = @
super uid, content
applyDelete: (op)->
if @insert_parent? and not @insert_parent.isDeleted()
@insert_parent.applyDelete op
else
super
type: "TextNodeType"
#
# Encode this operation in such a way that it can be parsed by remote peers.
#
_encode: ()->
json = {
'type': @type
'uid' : @getUid()
'content' : @content.textContent
}
json
parser['TextNodeType'] = (json)->
{
'uid' : uid
'content' : content
} = json
textnode = document.createTextNode content
new TextNodeType uid, textnode
types['XmlType'] = XmlType