Browse Source

Refactoring of ticket zoom (less rerendering, just rerender particular area's instant of whole view). Added live broadcasting of tag and links.

Martin Edenhofer 8 years ago
parent
commit
3d878a5547

+ 6 - 6
app/assets/javascripts/app/controllers/_application_controller_generic.coffee

@@ -1117,7 +1117,7 @@ class App.ObserverController extends App.Controller
           currentAttributes[key] = object[key]
     if @observeNot
       for key, value of object
-        if !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
+        if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
           currentAttributes[key] = value
 
     if !@lastAttributres
@@ -1128,13 +1128,13 @@ class App.ObserverController extends App.Controller
         @log 'debug', 'maybeRender no diff, no rerender'
         return
 
-    @log 'debug', 'maybeRender.diff', diff
+    @log 'debug', 'maybeRender.diff', diff, @observe, @model
     @lastAttributres = currentAttributes
 
-    @render(object)
+    @render(object, diff)
 
-  render: (object) =>
-    @log 'debug', 'render', @template, object
+  render: (object, diff) =>
+    @log 'debug', 'render', @template, object, diff
     @html App.view(@template)(
       object: object
     )
@@ -1144,5 +1144,5 @@ class App.ObserverController extends App.Controller
 
   release: =>
     #console.trace()
-    @log 'debug', 'release', @object_id, @model
+    @log 'debug', 'release', @object_id, @model, @subscribeId
     App[@model].unsubscribe(@subscribeId)

+ 150 - 154
app/assets/javascripts/app/controllers/ticket_zoom.coffee

@@ -18,11 +18,10 @@ class App.TicketZoom extends App.Controller
       App.TaskManager.remove(@task_key)
       return
 
-    @formMeta             = undefined
-    @ticket_id            = params.ticket_id
-    @article_id           = params.article_id
-    @sidebarState         = {}
-    @ticketLastAttributes = {}
+    @formMeta     = undefined
+    @ticket_id    = params.ticket_id
+    @article_id   = params.article_id
+    @sidebarState = {}
 
     # if we are in init task startup, ignore overview_id
     if !params.init
@@ -51,7 +50,7 @@ class App.TicketZoom extends App.Controller
       update = =>
         @fetch(@ticket_id, false)
       if !@ticketUpdatedAtLastCall || ( new Date(data.updated_at).toString() isnt new Date(@ticketUpdatedAtLastCall).toString() )
-        @delay(update, 1200, "ticket-zoom-#{@ticket_id}")
+        @delay(update, 1100, "ticket-zoom-#{@ticket_id}")
     )
 
     # rerender view, e. g. on langauge change
@@ -59,84 +58,6 @@ class App.TicketZoom extends App.Controller
       @fetch(@ticket_id, true)
     )
 
-  meta: =>
-
-    # default attributes
-    meta =
-      url: @url()
-      id:  @ticket_id
-
-    # set icon and tilte if defined
-    if @taskIconClass
-      meta.iconClass = @taskIconClass
-    if @taskHead
-      meta.head = @taskHead
-
-    # set icon and title based on ticket
-    if @ticket
-      @ticket        = App.Ticket.fullLocal(@ticket.id)
-      meta.head      = @ticket.title
-      meta.title     = '#' + @ticket.number + ' - ' + @ticket.title
-      meta.class     = "task-state-#{ @ticket.getState() }"
-      meta.type      = 'task'
-      meta.iconTitle = @ticket.iconTitle()
-      meta.iconClass = @ticket.iconClass()
-    meta
-
-  url: =>
-    "#ticket/zoom/#{@ticket_id}"
-
-  show: (params) =>
-
-    @navupdate(url: '#', type: 'menu')
-
-    # set all notifications to seen
-    App.OnlineNotification.seen('Ticket', @ticket_id)
-
-    # if controller is executed twice, go to latest article (e. g. click on notification)
-    if @activeState
-      @scrollToBottom()
-      return
-    @activeState = true
-
-    # start autosave
-    @autosaveStart()
-
-    # if ticket is shown the first time
-    if !@shown
-      @shown = true
-
-      # trigger shown to article
-      App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
-
-      # scroll to end of page
-      @scrollToBottom()
-
-    # observe content header position
-    @positionPageHeaderStart()
-
-  hide: =>
-    @activeState = false
-
-    # stop observing content header position
-    @positionPageHeaderStop()
-
-    # stop autosave
-    @autosaveStop()
-
-  changed: =>
-    return false if !@ticket
-    currentParams = @formCurrent()
-    currentStore = @currentStore()
-    modelDiff = @formDiff(currentParams, currentStore)
-    return false if !modelDiff || _.isEmpty(modelDiff)
-    return false if _.isEmpty(modelDiff.ticket) && _.isEmpty(modelDiff.article)
-    return true
-
-  release: =>
-    @autosaveStop()
-    @positionPageHeaderStop()
-
   fetch: (ticket_id, force) ->
     return if !@Session.get()
 
@@ -144,7 +65,7 @@ class App.TicketZoom extends App.Controller
     @ajax(
       id:    "ticket_zoom_#{ticket_id}"
       type:  'GET'
-      url:   "#{@apiPath}/tickets/#{ticket_id}?full=true"
+      url:   "#{@apiPath}/tickets/#{ticket_id}?all=true"
       processData: true
       success: (data, status, xhr) =>
 
@@ -162,26 +83,21 @@ class App.TicketZoom extends App.Controller
         # remember current data
         @ticketUpdatedAtLastCall = newTicketRaw.updated_at
 
-        @load(data, force)
+        @load(data)
         App.SessionStorage(@key, data)
 
         if !@doNotLog
           @doNotLog = 1
           @recentView('Ticket', ticket_id)
 
-        # scroll to end of page
-        if force
-          @scrollToBottom()
-          @positionPageHeaderUpdate()
-
       error: (xhr) =>
+        @renderDone = false
         statusText = xhr.statusText
         status     = xhr.status
         detail     = xhr.responseText
 
         # ignore if request is aborted
-        if statusText is 'abort'
-          return
+        return if statusText is 'abort'
 
         # if ticket is already loaded, ignore status "0" - network issues e. g. temp. not connection
         if @ticketUpdatedAtLastCall && status is 0
@@ -210,11 +126,7 @@ class App.TicketZoom extends App.Controller
           )
     )
 
-
-  muteTask: =>
-    App.TaskManager.mute(@task_key)
-
-  load: (data, force) =>
+  load: (data) =>
 
     # remember article ids
     @ticket_article_ids = data.ticket_article_ids
@@ -238,6 +150,87 @@ class App.TicketZoom extends App.Controller
     # render page
     @render()
 
+  meta: =>
+
+    # default attributes
+    meta =
+      url: @url()
+      id:  @ticket_id
+
+    # set icon and tilte if defined
+    if @taskIconClass
+      meta.iconClass = @taskIconClass
+    if @taskHead
+      meta.head = @taskHead
+
+    # set icon and title based on ticket
+    if @ticket_id && App.Ticket.exists(@ticket_id)
+      ticket         = App.Ticket.find(@ticket_id)
+      meta.head      = ticket.title
+      meta.title     = "##{ticket.number} - #{ticket.title}"
+      meta.class     = "task-state-#{ ticket.getState() }"
+      meta.type      = 'task'
+      meta.iconTitle = ticket.iconTitle()
+      meta.iconClass = ticket.iconClass()
+    meta
+
+  url: =>
+    "#ticket/zoom/#{@ticket_id}"
+
+  show: (params) =>
+
+    @navupdate(url: '#', type: 'menu')
+
+    # set all notifications to seen
+    App.OnlineNotification.seen('Ticket', @ticket_id)
+
+    # if controller is executed twice, go to latest article (e. g. click on notification)
+    if @activeState
+      @scrollToBottom()
+      return
+    @activeState = true
+
+    # start autosave
+    @autosaveStart()
+
+    # if ticket is shown the first time
+    if !@shown
+      @shown = true
+
+      # trigger shown to article
+      App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
+
+      # scroll to end of page
+      @scrollToBottom()
+
+    # observe content header position
+    @positionPageHeaderStart()
+
+  hide: =>
+    @activeState = false
+
+    # stop observing content header position
+    @positionPageHeaderStop()
+
+    # stop autosave
+    @autosaveStop()
+
+  changed: =>
+    return false if !@ticket
+    currentParams = @formCurrent()
+    currentStore = @currentStore()
+    modelDiff = @formDiff(currentParams, currentStore)
+    return false if !modelDiff || _.isEmpty(modelDiff)
+    return false if _.isEmpty(modelDiff.ticket) && _.isEmpty(modelDiff.article)
+    return true
+
+  release: =>
+    @autosaveStop()
+    @positionPageHeaderStop()
+
+  muteTask: =>
+    App.TaskManager.mute(@task_key)
+
   positionPageHeaderStart: =>
 
     # init header update needed for safari, scroll event is fired
@@ -281,10 +274,9 @@ class App.TicketZoom extends App.Controller
     # update taskbar with new meta data
     App.TaskManager.touch(@task_key)
 
-    @formEnable( @$('.submit') )
-
     if !@renderDone
       @renderDone = true
+      @autosaveLast = {}
       elLocal = $(App.view('ticket_zoom')
         ticket:         @ticket
         nav:            @nav
@@ -294,24 +286,23 @@ class App.TicketZoom extends App.Controller
 
       new App.TicketZoomOverviewNavigator(
         el:          elLocal.find('.overview-navigator')
-        ticket_id:   @ticket.id
+        ticket_id:   @ticket_id
         overview_id: @overview_id
       )
 
       new App.TicketZoomTitle(
-        object_id:   @ticket.id
+        object_id:   @ticket_id
         overview_id: @overview_id
         el:          elLocal.find('.ticket-title')
         task_key:    @task_key
       )
 
       new App.TicketZoomMeta(
-        object_id: @ticket.id
+        object_id: @ticket_id
         el:        elLocal.find('.ticket-meta')
       )
 
       new App.TicketZoomAttributeBar(
-        ticket:      @ticket
         el:          elLocal.find('.js-attributeBar')
         overview_id: @overview_id
         callback:    @submit
@@ -322,7 +313,7 @@ class App.TicketZoom extends App.Controller
 
       @articleNew = new App.TicketZoomArticleNew(
         ticket:    @ticket
-        ticket_id: @ticket.id
+        ticket_id: @ticket_id
         el:        elLocal.find('.article-new')
         formMeta:  @formMeta
         form_id:   @form_id
@@ -333,7 +324,7 @@ class App.TicketZoom extends App.Controller
 
       @highligher = new App.TicketZoomHighlighter(
         el:        elLocal.find('.highlighter')
-        ticket_id: @ticket.id
+        ticket_id: @ticket_id
       )
 
       @articleView = new App.TicketZoomArticleView(
@@ -344,27 +335,20 @@ class App.TicketZoom extends App.Controller
         ticket_article_ids: @ticket_article_ids
       )
 
-    # rerender whole sidebar if customer or organization has changed
-    if @ticketLastAttributes.customer_id isnt @ticket.customer_id || @ticketLastAttributes.organization_id isnt @ticket.organization_id
-      if elLocal
-        el = elLocal
-      else
-        el = @el
-      new App.WidgetAvatar(
-        el:        el.find('.ticketZoom-header .js-avatar')
-        object_id: @ticket.customer_id
-        size:      50
+      new App.TicketCustomerAvatar(
+        object_id: @ticket_id
+        el:        elLocal.find('.ticketZoom-header')
       )
+
       @sidebar = new App.TicketZoomSidebar(
-        el:           el.find('.tabsSidebar')
+        el:           elLocal
         sidebarState: @sidebarState
-        object_id:    @ticket.id
+        object_id:    @ticket_id
         model:        'Ticket'
         taskGet:      @taskGet
         task_key:     @task_key
-        tags:         @tags
-        links:        @links
         formMeta:     @formMeta
+        markForm:     @markForm
       )
 
     # render init content
@@ -377,24 +361,34 @@ class App.TicketZoom extends App.Controller
         ticket_article_ids: @ticket_article_ids
       )
 
+    if @sidebar
+
+      # update tags
+      if @sidebar.tagWidget
+        @sidebar.tagWidget.reload(@tags)
+
+      # update links
+      if @sidebar.linkWidget
+        @sidebar.linkWidget.reload(@links)
+
     # scroll to article if given
-    if @article_id && document.getElementById('article-' + @article_id)
-      offset = document.getElementById('article-' + @article_id).offsetTop
+    if @article_id && document.getElementById("article-#{@article_id}")
+      offset = document.getElementById("article-#{@article_id}").offsetTop
       offset = offset - 45
       scrollTo = ->
         @scrollTo(0, offset)
       @delay(scrollTo, 100, false)
 
-    @ticketLastAttributes = @ticket.attributes()
+    if @shown
 
-    if @shown && !@initDone
-      @initDone = true
+      # scroll to end if new article has been added
+      if !@last_ticket_article_ids || !_.isEqual(_.sortBy(@last_ticket_article_ids), _.sortBy(@ticket_article_ids))
+        @last_ticket_article_ids = @ticket_article_ids
+        @scrollToBottom()
+        @positionPageHeaderUpdate()
 
-      # scroll to end of page
-      @scrollToBottom()
-
-      # observe content header position
-      @positionPageHeaderStart()
+      return if @initDone
+      @initDone = true
 
       # trigger shown if init shown render
       App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
@@ -403,32 +397,34 @@ class App.TicketZoom extends App.Controller
     @main.scrollTop( @main.prop('scrollHeight') )
 
   autosaveStop: =>
+    console.log('autosaveStop')
     @clearDelay('ticket-zoom-form-update')
     @autosaveLast = {}
     @el.off('change.local blur.local keyup.local paste.local input.local')
 
   autosaveStart: =>
+    console.log('autosaveStart')
+    @el.on('change.local blur.local keyup.local paste.local input.local', 'form, .js-textarea', (e) =>
+      @delay(@markForm, 250, 'ticket-zoom-form-update')
+    )
+    @delay(@markForm, 800, 'ticket-zoom-form-update')
+
+  markForm: (force) =>
     if !@autosaveLast
       @autosaveLast = @taskGet()
-    update = =>
-      return if !@ticket
-      currentParams = @formCurrent()
-
-      # check changed between last autosave
-      sameAsLastSave = _.isEqual(currentParams, @autosaveLast)
-      return if sameAsLastSave
-      @autosaveLast = clone(currentParams)
+    return if !@ticket
+    currentParams = @formCurrent()
 
-      # update changes in ui
-      currentStore = @currentStore()
-      modelDiff = @formDiff(currentParams, currentStore)
-      @markFormDiff(modelDiff)
-      @taskUpdateAll(modelDiff)
+    # check changed between last autosave
+    sameAsLastSave = _.isEqual(currentParams, @autosaveLast)
+    return if !force && sameAsLastSave
+    @autosaveLast = clone(currentParams)
 
-    @el.on('change.local blur.local keyup.local paste.local input.local', 'form, .js-textarea', (e) =>
-      @delay(update, 250, 'ticket-zoom-form-update')
-    )
-    @delay(update, 800, 'ticket-zoom-form-update')
+    # update changes in ui
+    currentStore = @currentStore()
+    modelDiff = @formDiff(currentParams, currentStore)
+    @markFormDiff(modelDiff)
+    @taskUpdateAll(modelDiff)
 
   currentStore: =>
     return if !@ticket
@@ -534,7 +530,7 @@ class App.TicketZoom extends App.Controller
     ticketParams = @formParam( @$('.edit') )
 
     # validate ticket
-    ticket = App.Ticket.fullLocal(@ticket.id)
+    ticket = App.Ticket.find(@ticket_id)
 
     # reset article - should not be resubmited on next ticket update
     ticket.article = undefined
@@ -550,13 +546,13 @@ class App.TicketZoom extends App.Controller
 
         # apply tag changes
         if attributes[1] is 'tags'
-          if @sidebar && @sidebar.tagWidget
+          if @sidebar && @sidebar.edit && @sidebar.edit.tagWidget
             tags = content.value.split(',')
             for tag in tags
               if content.operator is 'remove'
-                @sidebar.tagWidget.remove(tag)
+                @sidebar.edit.tagWidget.remove(tag)
               else
-                @sidebar.tagWidget.add(tag)
+                @sidebar.edit.tagWidget.add(tag)
 
         # apply user changes
         else if attributes[1] is 'owner_id'
@@ -671,7 +667,7 @@ class App.TicketZoom extends App.Controller
 
         @autosaveStart()
         @muteTask()
-        @fetch(ticket.id, true)
+        @fetch(ticket.id, false)
 
         # enable form
         @formEnable(e)
@@ -701,7 +697,7 @@ class App.TicketZoom extends App.Controller
     @$('.js-reset').addClass('hide')
 
     # reset edit ticket / reset new article
-    App.Event.trigger('ui::ticket::taskReset', { ticket_id: @ticket.id })
+    App.Event.trigger('ui::ticket::taskReset', { ticket_id: @ticket_id })
 
     # remove change flag on tab
     @$('.tabsSidebar-tab[data-tab="ticket"]').removeClass('is-changed')
@@ -744,7 +740,7 @@ class TicketZoomRouter extends App.ControllerPermanent
       shown:      true
 
     App.TaskManager.execute(
-      key:        'Ticket-' + @ticket_id
+      key:        "Ticket-#{@ticket_id}"
       controller: 'TicketZoom'
       params:     clean_params
       show:       true

+ 2 - 1
app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee

@@ -257,7 +257,8 @@ class App.TicketZoomArticleNew extends App.Controller
           ticket: ticket
           user: App.Session.get()
         )
-      @subscribeIdTextModule = ticket.subscribe(callback)
+      if !@subscribeIdTextModule
+        @subscribeIdTextModule = ticket.subscribe(callback)
 
   params: =>
     params = @formParam( @$('.article-add') )

+ 2 - 0
app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee

@@ -86,6 +86,8 @@ class ArticleViewItem extends App.ObserverController
     @el.attr('id', "article-#{article.id}")
     if article.internal
       @el.addClass('is-internal')
+    else
+      @el.removeClass('is-internal')
 
     # prepare html body
     if article.content_type is 'text/html'

+ 11 - 0
app/assets/javascripts/app/controllers/ticket_zoom/customer_avatar.coffee

@@ -0,0 +1,11 @@
+class App.TicketCustomerAvatar extends App.ObserverController
+  model: 'Ticket'
+  observe:
+    customer_id: true
+
+  render: (ticket) =>
+    new App.WidgetAvatar(
+      el:        @el.find('.js-avatar')
+      object_id: ticket.customer_id
+      size:      50
+    )

+ 44 - 37
app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee

@@ -1,59 +1,66 @@
-class App.TicketZoomSidebar extends App.ObserverController
+class Edit extends App.ObserverController
   model: 'Ticket'
   observeNot:
     created_at: true
     updated_at: true
 
-  render: (ticket) =>
+  render: (ticket, diff) =>
+    defaults = ticket.attributes()
+    delete defaults.article # ignore article infos
+    taskState = @taskGet('ticket')
 
-    editTicket = (el) =>
-      el.append('<form class="edit"></form>')
-      @editEl = el
+    if !_.isEmpty(taskState)
+      defaults = _.extend(defaults, taskState)
 
-      show = (ticket) =>
-        el.find('.edit').html('')
+    form = new App.ControllerForm(
+      model:    App.Ticket
+      screen:   'edit'
+      handlers: [
+        @ticketFormChanges
+      ]
+      filter:    @formMeta.filter
+      params:    defaults
+      #bookmarkable: true
+    )
+    @html form.html()
 
-        defaults = ticket.attributes()
-        delete defaults.article # ignore article infos
-        taskState = @taskGet('ticket')
-        modelDiff = App.Utils.formDiff(taskState, defaults)
+    @markForm(true)
 
-        if !_.isEmpty(taskState)
-          defaults = _.extend(defaults, taskState)
+    return if @resetBind
+    @resetBind = true
+    @bind('ui::ticket::taskReset', (data) =>
+      return if data.ticket_id isnt ticket.id
+      @render(ticket)
+    )
 
-        new App.ControllerForm(
-          el:       el.find('.edit')
-          model:    App.Ticket
-          screen:   'edit'
-          handlers: [
-            @ticketFormChanges
-          ]
-          filter:    @formMeta.filter
-          params:    defaults
-          #bookmarkable: true
-        )
-        #console.log('Ichanges', modelDiff, taskState, ticket.attributes(), defaults)
-        #@markFormDiff( modelDiff )
+class App.TicketZoomSidebar extends App.ObserverController
+  model: 'Ticket'
+  observe:
+    customer_id: true
+    organization_id: true
+
+  render: (ticket) =>
+
+    editTicket = (el) =>
+      el.append('<form><fieldset class="edit"></fieldset></form><div class="tags"></div><div class="links"></div>')
 
-      show(ticket)
-      @bind(
-        'ui::ticket::taskReset'
-        (data) ->
-          if data.ticket_id is ticket.id
-            show(ticket)
+      @edit = new Edit(
+        object_id: ticket.id
+        el:        el.find('.edit')
+        taskGet:   @taskGet
+        formMeta:  @formMeta
+        markForm:  @markForm
       )
 
       if !@isRole('Customer')
-        el.append('<div class="tags"></div>')
         @tagWidget = new App.WidgetTag(
-          el:          el.find('.tags')
+          el:          @el.find('.tags')
           object_type: 'Ticket'
           object:      ticket
           tags:        @tags
         )
-        el.append('<div class="links"></div>')
         @linkWidget = new App.WidgetLink(
-          el:          el.find('.links')
+          el:          @el.find('.links')
           object_type: 'Ticket'
           object:      ticket
           links:       @links
@@ -166,7 +173,7 @@ class App.TicketZoomSidebar extends App.ObserverController
           callback: showOrganization
         }
     new App.Sidebar(
-      el:           @el
+      el:           @el.find('.tabsSidebar')
       sidebarState: @sidebarState
       items:        @sidebarItems
     )

+ 6 - 0
app/assets/javascripts/app/controllers/widget/link.coffee

@@ -30,7 +30,13 @@ class App.WidgetLink extends App.Controller
         @render()
     )
 
+  reload: (links) ->
+    @links = links
+    @render()
+
   render: =>
+    return if @lastLinks && _.isEqual(@lastLinks, @links)
+    lastLinks = @links
     list = {}
     for item in @links
       if !list[ item['link_type'] ]

+ 9 - 3
app/assets/javascripts/app/controllers/widget/tag.coffee

@@ -29,7 +29,7 @@ class App.WidgetTag extends App.Controller
     @ajax(
       id:    @key
       type:  'GET'
-      url:   @apiPath + '/tags'
+      url:   "#{@apiPath}/tags"
       data:
         object: @object_type
         o_id:   @object.id
@@ -39,7 +39,13 @@ class App.WidgetTag extends App.Controller
         @render()
     )
 
+  reload: (tags) ->
+    @tags = tags
+    @render()
+
   render: ->
+    return if @lastTags && _.isEqual(@lastTags, @tags)
+    lastTags = @tags
     @html App.view('widget/tag')(
       tags: @tags || [],
     )
@@ -87,7 +93,7 @@ class App.WidgetTag extends App.Controller
 
     @ajax(
       type:  'GET'
-      url:   @apiPath + '/tags/add'
+      url:   "#{@apiPath}/tags/add"
       data:
         object: @object_type
         o_id:   @object.id
@@ -110,7 +116,7 @@ class App.WidgetTag extends App.Controller
 
     @ajax(
       type:  'GET'
-      url:   @apiPath + '/tags/remove'
+      url:   "#{@apiPath}/tags/remove"
       data:
         object: @object_type
         o_id:   @object.id

+ 22 - 4
app/assets/javascripts/app/lib/app_post/collection.coffee

@@ -65,8 +65,17 @@ class _collectionSingleton extends Spine.Module
 
   loadAssets: (assets) ->
     @log 'debug', 'loadAssets', assets
+
+    # proess not existing assets / to avoid not exising ref errors
+    loadAssetsLater = []
     for type, collections of assets
-      @load(type: type, data: collections)
+      later = @load(type: type, data: collections, later: true)
+      if later
+        loadAssetsLater[type] = later
+
+    # proess existing assets
+    for type, collections of loadAssetsLater
+      App[type].refresh(collections)
 
   load: (params) ->
 
@@ -81,11 +90,13 @@ class _collectionSingleton extends Spine.Module
 
     # load full array once
     if _.isArray(params.data)
+      @log 'debug', 'refresh', params.data
       appObject.refresh(params.data)
       return
 
     # load data from object
     listToRefresh = []
+    listToRefreshLater = []
     for key, object of params.data
       if !params.refresh && appObject
         @log 'debug', 'refrest try', params.type, key
@@ -93,15 +104,22 @@ class _collectionSingleton extends Spine.Module
         # check if new object is newer, just load newer objects
         if object.updated_at && appObject.exists(key)
           exists = appObject.find(key)
+          objectToLoad = undefined
           if exists.updated_at
             if exists.updated_at < object.updated_at
-              listToRefresh.push object
+              objectToLoad = object
               @log 'debug', 'refrest newser', params.type, key
           else
-            listToRefresh.push object
+            objectToLoad = object
             @log 'debug', 'refrest try no updated_at', params.type, key
+          if objectToLoad
+            if params.later
+              listToRefreshLater.push objectToLoad
+            else
+              listToRefresh.push object
         else
           listToRefresh.push object
           @log 'debug', 'refrest new', params.type, key
-    return if _.isEmpty(listToRefresh)
+    return listToRefreshLater if _.isEmpty(listToRefresh)
     appObject.refresh(listToRefresh)
+    listToRefreshLater

+ 3 - 3
app/assets/javascripts/app/models/_application_model.coffee

@@ -347,7 +347,7 @@ class App.Model extends Spine.Model
             clear: true
           )
 
-        'Collection::Subscribe::' + @className
+        "Collection::Subscribe::#{@className}"
       )
 
     key = @className + '-' + Math.floor( Math.random() * 99999 )
@@ -454,9 +454,9 @@ class App.Model extends Spine.Model
               if !genericObject || new Date(item.updated_at) >= new Date(genericObject.updated_at)
                 App.Log.debug('Model', "request #{@className}.find(#{item.id}) from server")
                 @full(item.id, false, true)
-            App.Delay.set(callback, 500, item.id, "full-#{@className}")
+            App.Delay.set(callback, 500, item.id, "full-#{@className}-#{item.id}")
 
-        'Item::Subscribe::' + @className
+        "Item::Subscribe::#{@className}"
       )
 
     # remember item callback

Some files were not shown because too many files changed in this diff