     # eventlisteners
 
     onadd: (parent, el) ->
-        el._jquery_tracker = {el}
-        # insert into parent
         that = this
-        delay.call parent, -> # !
-            el = el?._jquery_tracker?.el
-            return if not el or removed this
-            if this is @builder and @_jquery.parent().length is 0
-                @_jquery = @_jquery.add(el._jquery)
-#                 parent._jquery.data('dt-jquery', parent)
-#                 console.error "ready!", el.name, el._jquery_ready
-                el._jquery_ready?()
-                el._jquery_ready = yes
+        # `this` changes in onreplace
+        el._jquery_insert ?= singlton_callback el, ->
+            return if removed this
+            if @parent is @parent.builder
+                $root = @parent._jquery.parent()
+                if $root.length is 0
+                    jq = @parent._jquery
+                    jq = jq.add(@_jquery)
+                    if @parent is that.builder
+                        that.template.jquery = jq
+                        that.template._jquery = jq
+                        @parent.jquery = jq
+                    @parent._jquery = jq
+                else
+                    $root.append(@_jquery)
             else
-                parent = @_jquery_tracker.el
-                done = -> that.animation.push ->
-                    parent = parent?._jquery_tracker?.el
-                    el = el?._jquery_tracker?.el
-                    return unless parent and el
-                    if parent is parent.builder
-                        parent._jquery.parent().append(el._jquery)
-                    else
-                        for e in el._jquery ? []
-                            parent._jquery?.append(e)
-                    # FIXME listen on dom insertion event
-#                     console.error "ready!", el.name, el._jquery_ready
-                    el._jquery_ready?()
-                    el._jquery_ready = yes
-                # delay til end if el is a builder
-                if el is el.builder
-                    el.ready(done)
-                else
-                    done()
+                @parent._jquery?.append(@_jquery)
+            @_jquery_ready?()
+            @_jquery_ready = yes
+            @_jquery_insert = yes
+        el._jquery_insert.replace?(el)
+
+        el._jquery_manip ?= cancelable_and_retrivable_callbacks()
+        el._jquery_done ?= deferred_callbacks()
+        el.ready(el._jquery_done.callback())
+
 
     onclose: (el) ->
-        el._jquery_tracker ?= {el}
-#         return if removed el
         if el is el.builder
-            el._jquery ?= $()
+            el._jquery ?= $([], el.parent._jquery)
         else
-            el._jquery ?= $(el.toString())
-#         el._jquery.data('dt-jquery', el)
+            el._jquery ?= $(el.toString(), el.parent._jquery)
         release.call el
 
-        el.on 'newListener', (type) ->
-            return if el._events?[type]?.length # dont bind two times for the same type
-            el._jquery.bind type, ->
-                el.emit type, this, arguments...
-                return # dont return emit result (which is either true or false)
+
+        insertion = el._jquery_insert
+        insertion = el._jquery_replace if insertion is yes
+        if insertion is undefined
+            @onadd(el.parent, el)
+            insertion = el._jquery_insert
+        el.parent?._jquery_done? =>
+            if el.parent is el.parent.builder
+                insertion()
+            else
+                @animation.push(insertion)
+            # if manip left from last time run them
+            insertion?.that?._jquery_manip?.reset()
+            while (cb = insertion?.that?._jquery_manip?.callbacks.shift())?
+                @animation.push(cb)
+
+    onreplace: (oldtag, newtag) ->
+        newtag._jquery_insert ?= oldtag._jquery_insert
+        oldtag._jquery_insert = null
+
+        if newtag._jquery_insert is true
+            newtag._jquery_replace ?= oldtag._jquery_replace
+            noreplacerequest = newtag._jquery_replace?
+            newtag._jquery_replace ?= singlton_callback newtag, ->
+                return if removed this
+                _jquery = @_jquery ? this
+#                 return unless _jquery?.length
+                oldtag._jquery.replaceWith(_jquery)
+                # replaceWith isnt inplace
+                @_jquery = _jquery
+                if this is @builder
+                    @jquery = _jquery
+            oldtag._jquery_replace = null
+            replace = newtag._jquery_replace
+            replace.replace?(newtag)
+        else
+            newtag._jquery_insert.replace?(newtag)
+
+        newtag._jquery_manip ?= cancelable_and_retrivable_callbacks()
+        oldtag._jquery_manip?.cancel?()
+        newtag._jquery_manip.reset()
+        unless newtag.closed
+            # if manip left from last time run them
+            while (cb = newtag._jquery_manip.callbacks.shift())?
+                @animation.push(cb)
+
+        newtag._jquery_done ?= oldtag._jquery_done
+        newtag._jquery_done ?= deferred_callbacks()
+        oldtag._jquery_done = null
+        cb = newtag._jquery_done.callback()
+        if newtag is newtag.builder
+            cb()
+        else unless newtag.closed
+            newtag.ready(cb)
+        if (newtag._jquery_insert is true and newtag.closed) or noreplacerequest
+            @onclose(newtag)
+        # else just throw cb away, but reset allowed callback
 
     ontext: (el, text) ->
-        delay.call el, ->
-            @_jquery.text(text)
+        that = this
+        delay.call el, ->
+            that.animation.push @_jquery_manip =>
+                @_jquery.text(text)
 
     onraw: (el, html) ->
         that = this
         delay.call el, ->
-            that.animation.push =>
+            that.animation.push @_jquery_manip =>
                 @_jquery?.html(html)
 
+    onattr: (el, key, value) ->
+        that = this
+        delay.call el, ->
+            that.animation.push @_jquery_manip =>
+                if value is undefined
+                    @_jquery.removeAttr(key)
+                else
+                    @_jquery.attr(key, value)
+
     onshow: (el) ->
         delay.call el, ->
             @_jquery.show()

    onhide: (el) ->
        delay.call el, ->
            @_jquery.hide()

    onattr: (el, key, value) ->
        delay.call el, ->
            if value is undefined
                @_jquery.removeAttr(key)
            else
                @_jquery.attr(key, value)

    onreplace: (oldtag, newtag) ->
        newtag._jquery_tracker ?= el:newtag
        oldtag._jquery_tracker.el = newtag
        that = this
        delay.call oldtag, ->
            newtag = newtag._jquery_tracker.el
            delay.call newtag, ->
                that.animation.push =>
                    newtag = @_jquery_tracker.el
                    return if removed(oldtag) or removed(newtag)
                    _jquery = newtag._jquery ? newtag
                    return unless _jquery?.length > 0
                    oldtag._jquery.replaceWith(_jquery)
                    # replaceWith isnt inplace
                    for tag in [oldtag, newtag]
                        tag._jquery = _jquery
                        if tag is tag.builder
                            tag.jquery = _jquery

    onremove: (el) ->
        if el._jquery?
            el._jquery.remove()
            delete el._jquery
        delete el._jquery_tracker

    onend: () ->
#         @builder._jquery.data('dt-jquery', @template.xml)

# TODO mit canvas tag kommt man direkt auf die browser render ticks.


# multiple changes of this context possible
singlton_callback = (that, callback) ->
    req = -> callback?.apply(that, arguments)
    req.replace = (replacement) -> that = req.that = replacement
    req.that = that
#     req.callback = callback?.callback
#     req.cancel = callback?.cancel
    return req

cancelable_callback = (callback) ->
    canceled = no
    cb = -> callback?() unless canceled
    cb.cancel = -> canceled = yes
    cb.cancel.reset = -> canceled = no
#     cb.callback = callback?.callback
#     cb.replace = callback?.replace
    return cb

deferred_callbacks = () ->
    done = no
    callbacks = []
    res = (cb) ->
        return cb?() if done
        callbacks.push(cb)
    allowed = null
    res.callback = ->
        return (->) if done
        callback = ->
            if callback is allowed
                while (cb = callbacks.shift())?
                    cb?(arguments...)
                callbacks = null
                allowed = null
                done = yes
        allowed = callback
        return callback
    return res

cancelable_and_retrivable_callbacks = () ->
    canceled = no
    res = (cb) ->
        return ->
            if canceled
                res.callbacks.push(cb)
            else
                cb?(arguments...)
    res.cancel = -> canceled = yes
    res.reset = -> canceled = no
    res.callbacks = []
    return res


removed = (el) ->
    el.closed is "removed"


# NOTE delay and release are only for manipulations where no parent is needed
# delay or invoke job immediately
delay = (job) ->
    return if removed this
