From 812d953c1cc5862bfec5e197aaa4198c9329042c Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 4 Nov 2015 17:04:17 +0100 Subject: [PATCH] Split of model/collections and controller. --- .../app/controllers/ticket_overview.coffee | 312 +++++++----------- .../ticket_zoom/overview_navigator.coffee | 29 +- .../lib/app_post/overview_collection.coffee | 103 ++++++ .../app_post/overview_index_collection.coffee | 28 +- 4 files changed, 274 insertions(+), 198 deletions(-) create mode 100644 app/assets/javascripts/app/lib/app_post/overview_collection.coffee diff --git a/app/assets/javascripts/app/controllers/ticket_overview.coffee b/app/assets/javascripts/app/controllers/ticket_overview.coffee index 2759e13ac..09680d17e 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.coffee @@ -3,7 +3,6 @@ class App.TicketOverview extends App.Controller constructor: -> super - @render() render: -> @@ -29,7 +28,7 @@ class App.TicketOverview extends App.Controller @activeState url: => - '#ticket/view/' + @view + "#ticket/view/#{@view}" show: (params) => @@ -77,9 +76,105 @@ class App.TicketOverview extends App.Controller release: -> # no - overview: (overview_id) => - return if !@contentController - @contentController.meta(overview_id) +class Navbar extends App.Controller + elements: + '.js-tabsClone': 'clone' + '.js-tabClone': 'tabClone' + '.js-tabs': 'tabs' + '.js-tab': 'tab' + '.js-dropdown': 'dropdown' + '.js-toggle': 'dropdownToggle' + '.js-dropdownItem': 'dropdownItem' + + events: + 'click .js-tab': 'activate' + 'click .js-dropdownItem': 'navigateTo' + 'hide.bs.dropdown': 'onDropdownHide' + 'show.bs.dropdown': 'onDropdownShow' + + constructor: -> + super + + @bindId = App.OverviewIndexCollection.bind(@render) + + # rerender view, e. g. on language change + @bind 'ui:rerender', => + @render(App.OverviewIndexCollection.get()) + + if @vertical + $(window).on 'resize.navbar', @autoFoldTabs + + navigateTo: (event) => + location.hash = $(event.currentTarget).attr('data-target') + + onDropdownShow: => + @dropdownToggle.addClass('active') + + onDropdownHide: => + @dropdownToggle.removeClass('active') + + activate: (event) => + @tab.removeClass('active') + $(event.currentTarget).addClass('active') + + release: => + $(window).off 'resize.navbar', @autoFoldTabs + if @bindId + App.OverviewIndexCollection.unbind(@bindId) + + autoFoldTabs: => + items = App.OverviewIndexCollection.get() + @html App.view("agent_ticket_view/navbar#{ if @vertical then '_vertical' }") + items: items + + while @clone.width() > @el.width() + @tabClone.not('.hide').last().addClass('hide') + @tab.not('.hide').last().addClass('hide') + @dropdownItem.filter('.hide').last().removeClass('hide') + + # if all tabs are visible + # remove dropdown and dropdown button + if @dropdownItem.filter('.hide').size() is 0 + @dropdown.remove() + @dropdownToggle.remove() + + active: (state) => + @activeState = state + + update: (params = {}) -> + for key, value of params + @[key] = value + @render(App.OverviewIndexCollection.get()) + + render: (data) => + return if !data + + # set page title + if @activeState && @view && !@vertical + for item in data + if item.link is @view + @title item.name, true + + # redirect to first view + if @activeState && !@view && !@vertical + view = data[0].link + @navigate "ticket/view/#{view}", true + return + + # add new views + for item in data + item.target = "#ticket/view/#{item.link}" + if item.link is @view + item.active = true + activeOverview = item + else + item.active = false + + @html App.view("agent_ticket_view/navbar#{ if @vertical then '_vertical' else '' }") + items: data + + if @vertical + @autoFoldTabs() class Table extends App.Controller events: @@ -89,34 +184,17 @@ class Table extends App.Controller constructor: -> super - @cache = {} - - # rebuild ticket overview data - @bind 'ticket_overview_rebuild', (data) => - #console.log('EVENT ticket_overview_rebuild', @view, data.view) - - # remeber bulk attributes - @bulk = data.bulk - - # fill cache - @cache[data.view] = data - - # check if current view is updated - if @view is data.view - @render() - - # force fetch ticket overview - @bind 'ticket_overview_fetch_force', => - @fetch() - - # force fetch ticket overview - @bind 'ticket_overview_local', => - @render(true) + if @view + @bindId = App.OverviewCollection.bind(@view, @render) # rerender view, e. g. on langauge change @bind 'ui:rerender', => return if !@authenticate(true) - @render() + @render(App.OverviewCollection.get(@view)) + + release: => + if @bindId + App.OverviewCollection.unbind(@bindId) update: (params) => for key, value of params @@ -127,61 +205,26 @@ class Table extends App.Controller return if !@view - # fetch initial data - if !@cache || !@cache[@view] - @fetch() - else - @render() + if @view + if @bindId + App.OverviewCollection.unbind(@bindId) + @bindId = App.OverviewCollection.bind(@view, @render) - fetch: => - - # init fetch via ajax, all other updates on time via websockets - @ajax( - id: 'ticket_overview_' + @view + '_' + @view_mode - type: 'GET' - url: @apiPath + '/ticket_overviews' - data: - view: @view - view_mode: @view_mode - processData: true - success: (data) => - if data.assets - App.Collection.loadAssets( data.assets ) - - # remeber bulk attributes - @bulk = data.bulk - - @cache[data.view] = data - @render() - ) - - meta: (overview_id) => - return if !@cache - - # find requested overview data - for url, data of @cache - if data.overview.id is overview_id - return data - false - - render: (overview_changed = false) => - #console.log('RENDER', @cache, @view) - return if !@cache - return if !@cache[@view] + render: (data) => + return if !data # use cache - overview = @cache[@view].overview - tickets_count = @cache[@view].tickets_count - ticket_ids = @cache[@view].ticket_ids + overview = data.overview + tickets_count = data.tickets_count + ticket_ids = data.ticket_ids # use cache if no local change - if !overview_changed - App.Overview.refresh( overview, { clear: true } ) + App.Overview.refresh(overview, { clear: true }) # get ticket list ticket_list_show = [] for ticket_id in ticket_ids - ticket_list_show.push App.Ticket.fullLocal( ticket_id ) + ticket_list_show.push App.Ticket.fullLocal(ticket_id) # if customer and no ticket exists, show the following message only if !ticket_list_show[0] && @isRole('Customer') @@ -191,7 +234,7 @@ class Table extends App.Controller @selected = @bulkGetSelected() # set page title - @overview = App.Overview.find( overview.id ) + @overview = App.Overview.find(overview.id) # render init page checkbox = true @@ -513,7 +556,8 @@ class Table extends App.Controller if @bulk_count_index == @bulk_count # fetch overview data again - App.Event.trigger('ticket_overview_fetch_force') + App.OverviewIndexCollection.fetch() + App.OverviewCollection.fetch(@view) ) ) @el.find('.table-overview').find('[name="bulk"]:checked').prop('checked', false) @@ -640,7 +684,7 @@ class App.OverviewSettings extends App.ControllerModal e.preventDefault() params = @formParam(e.target) - # check if refetch is needed + # check if re-fetch is needed @reload_needed = false if @overview.order.by isnt params.order.by @overview.order.by = params.order.by @@ -660,120 +704,16 @@ class App.OverviewSettings extends App.ControllerModal # fetch overview data again if @reload_needed - App.Event.trigger('ticket_overview_fetch_force') + App.OverviewIndexCollection.fetch() + App.OverviewCollection.fetch(@overview.link) else - App.Event.trigger('ticket_overview_local') + App.OverviewIndexCollection.trigger() + App.OverviewCollection.trigger(@overview.link) # hide modal @hide() ) -class Navbar extends App.Controller - elements: - '.js-tabsClone': 'clone' - '.js-tabClone': 'tabClone' - '.js-tabs': 'tabs' - '.js-tab': 'tab' - '.js-dropdown': 'dropdown' - '.js-toggle': 'dropdownToggle' - '.js-dropdownItem': 'dropdownItem' - - events: - 'click .js-tab': 'activate' - 'click .js-dropdownItem': 'navigate' - 'hide.bs.dropdown': 'onDropdownHide' - 'show.bs.dropdown': 'onDropdownShow' - - constructor: -> - super - console.log('RR', @vertical) - - App.OverviewIndexCollection.bind(@render) - - App.OverviewIndexCollection.fetch() - - # force fetch ticket overview - #@bind 'ticket_overview_fetch_force', => - # @fetch() - - # rerender view, e. g. on langauge change - @bind 'ui:rerender', => - @render(App.OverviewIndexCollection.get()) - - if @options.vertical - $(window).on 'resize.navbar', @autoFoldTabs - - navigate: (event) => - location.hash = $(event.currentTarget).attr('data-target') - - onDropdownShow: => - @dropdownToggle.addClass('active') - - onDropdownHide: => - @dropdownToggle.removeClass('active') - - activate: (event) => - @tab.removeClass('active') - $(event.currentTarget).addClass('active') - - release: => - $(window).off 'resize.navbar', @autoFoldTabs - - autoFoldTabs: => - items = App.OverviewIndexCollection.get() - @html App.view("agent_ticket_view/navbar#{ if @options.vertical then '_vertical' }") - items: items - - while @clone.width() > @el.width() - @tabClone.not('.hide').last().addClass('hide') - @tab.not('.hide').last().addClass('hide') - @dropdownItem.filter('.hide').last().removeClass('hide') - - # if all tabs are visible - # remove dropdown and dropdown button - if @dropdownItem.filter('.hide').size() is 0 - @dropdown.remove() - @dropdownToggle.remove() - - active: (state) => - @activeState = state - - update: (params = {}) -> - for key, value of params - @[key] = value - @render(App.OverviewIndexCollection.get()) - - render: (data) => - return if !data - - # set page title - if @activeState && @view - for item in data - if item.link is @view - @title item.name, true - - # redirect to first view - if @activeState && !@view - view = data[0].link - #console.log('REDIRECT', "ticket/view/#{view}") - @navigate "ticket/view/#{view}", true - return - - # add new views - for item in data - item.target = '#ticket/view/' + item.link - if item.link is @view - item.active = true - activeOverview = item - else - item.active = false - - @html App.view("agent_ticket_view/navbar#{ if @options.vertical then '_vertical' else '' }") - items: data - - if @options.vertical - @autoFoldTabs() - class TicketOverviewRouter extends App.ControllerPermanent constructor: (params) -> super diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/overview_navigator.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/overview_navigator.coffee index 1d09db1f3..2ccb0685c 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/overview_navigator.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/overview_navigator.coffee @@ -5,32 +5,43 @@ class App.TicketZoomOverviewNavigator extends App.Controller constructor: -> super + return if !@overview_id + # rebuild overview navigator if overview has changed - @bind 'ticket_overview_rebuild', (data) => - execute = => - @render() - @delay(execute, 1600, 'overview-navigator') + lateUpdate = => + @delay(@render, 2600, 'overview-navigator') + + @overview = App.Overview.find(@overview_id) + @bindId = App.OverviewCollection.bind(@overview.link, lateUpdate, false) @render() - render: (overview) => + release: => + App.OverviewCollection.unbind(@bindId) + + render: => if !@overview_id @html('') return # get overview data - worker = App.TaskManager.worker( 'TicketOverview' ) - return if !worker - overview = worker.overview(@overview_id) + overview = App.OverviewCollection.get(@overview.link) return if !overview current_position = 0 + found = false next = false previous = false for ticket_id in overview.ticket_ids current_position += 1 next = overview.ticket_ids[current_position] previous = overview.ticket_ids[current_position-2] - break if ticket_id is @ticket_id + if ticket_id is @ticket_id + found = true + break + + if !found + @html('') + return # get next/previous ticket if next diff --git a/app/assets/javascripts/app/lib/app_post/overview_collection.coffee b/app/assets/javascripts/app/lib/app_post/overview_collection.coffee new file mode 100644 index 000000000..cc21ed7c6 --- /dev/null +++ b/app/assets/javascripts/app/lib/app_post/overview_collection.coffee @@ -0,0 +1,103 @@ +class App.OverviewCollection + _instance = undefined # Must be declared here to force the closure on the class + + @get: (view) -> + if _instance == undefined + _instance ?= new _Singleton + _instance.get(view) + + @bind: (view, callback, init) -> + if _instance == undefined + _instance ?= new _Singleton + _instance.bind(view, callback, init) + + @unbind: (counter) -> + if _instance == undefined + _instance ?= new _Singleton + _instance.unbind(counter) + + @fetch: (view) -> + if _instance == undefined + _instance ?= new _Singleton + _instance.fetch(view) + + @trigger: (view) -> + if _instance == undefined + _instance ?= new _Singleton + _instance.trigger(view) + +# The actual Singleton class +class _Singleton + constructor: -> + @overview = {} + @callbacks = {} + @fetchActive = {} + @counter = 0 + + # websocket updates + App.Event.bind 'ticket_overview_rebuild', (data) => + if !@overview[data.view] + @overview[data.view] = {} + + # proccess assets, delete them later + if data.assets + App.Collection.loadAssets( data.assets ) + delete data.assets + + @overview[data.view] = data + + @callback(data.view, data) + + get: (view) -> + @overview[view] + + bind: (view, callback, init = true) -> + @counter += 1 + @callbacks[@counter] = + view: view + callback: callback + + # start init call if needed + if init + if @overview[view] is undefined + @fetch(view) + else + @callback(view, @overview[view]) + + @counter + + unbind: (counter) -> + delete @callbacks[counter] + + fetch: (view) => + return if @fetchActive[view] + @fetchActive[view] = true + App.Ajax.request( + id: 'ticket_overview_' + view + type: 'GET', + url: App.Config.get('api_path') + '/ticket_overviews', + data: + view: view + processData: true, + success: (data) => + @fetchActive[view] = false + + # proccess assets, delete them later + if data.assets + App.Collection.loadAssets( data.assets ) + delete data.assets + + @overview[data.view] = data + + @callback(view, data) + error: => + @fetchActive[view] = false + ) + + trigger: (view) => + @callback(view, @get(view)) + + callback: (view, data) => + for counter, meta of @callbacks + if meta.view is view + meta.callback(data) diff --git a/app/assets/javascripts/app/lib/app_post/overview_index_collection.coffee b/app/assets/javascripts/app/lib/app_post/overview_index_collection.coffee index cb65f8539..196fdc996 100644 --- a/app/assets/javascripts/app/lib/app_post/overview_index_collection.coffee +++ b/app/assets/javascripts/app/lib/app_post/overview_index_collection.coffee @@ -16,6 +16,11 @@ class App.OverviewIndexCollection _instance ?= new _Singleton _instance.unbind(callback) + @trigger: -> + if _instance == undefined + _instance ?= new _Singleton + _instance.trigger() + @fetch: -> if _instance == undefined _instance ?= new _Singleton @@ -26,14 +31,25 @@ class _Singleton constructor: -> @callbacks = {} @counter = 0 + + # websocket updates App.Event.bind 'ticket_overview_index', (data) => @overview_index = data + @callback(data) get: -> @overview_index - bind: (callback) -> + bind: (callback, init = true) -> @counter += 1 + + # start init call if needed + if init + if @overview_index is undefined + @fetch() + else + @callback(@overview_index) + @callbacks[@counter] = callback unbind: (callback) -> @@ -52,8 +68,14 @@ class _Singleton success: (data) => @fetchActive = false @overview_index = data - for counter, callback of @callbacks - callback(data) + @callback(data) error: => @fetchActive = false ) + + trigger: => + @callback(@get()) + + callback: (data) => + for counter, callback of @callbacks + callback(data)