Merge branch 'develop' of github.com:martini/zammad into develop
This commit is contained in:
commit
8e6807b0eb
23 changed files with 267 additions and 226 deletions
|
@ -443,7 +443,7 @@ class App.Controller extends Spine.Controller
|
||||||
}
|
}
|
||||||
processData: true,
|
processData: true,
|
||||||
success: (data, status, xhr) ->
|
success: (data, status, xhr) ->
|
||||||
App.Store.write( "user-ticket-popover::#{params.user_id}", data )
|
App.SessionStorage.set( "user-ticket-popover::#{params.user_id}", data )
|
||||||
|
|
||||||
# load assets
|
# load assets
|
||||||
App.Collection.loadAssets( data.assets )
|
App.Collection.loadAssets( data.assets )
|
||||||
|
@ -452,7 +452,7 @@ class App.Controller extends Spine.Controller
|
||||||
)
|
)
|
||||||
|
|
||||||
# get data
|
# get data
|
||||||
data = App.Store.get( "user-ticket-popover::#{params.user_id}" )
|
data = App.SessionStorage.get( "user-ticket-popover::#{params.user_id}" )
|
||||||
if data
|
if data
|
||||||
show( params, { open: data.ticket_ids_open, closed: data.ticket_ids_closed } )
|
show( params, { open: data.ticket_ids_open, closed: data.ticket_ids_closed } )
|
||||||
@delay(
|
@delay(
|
||||||
|
|
|
@ -504,13 +504,13 @@ class App.ControllerTable extends App.Controller
|
||||||
data[type][key] = {}
|
data[type][key] = {}
|
||||||
data[type][key] = value
|
data[type][key] = value
|
||||||
@log 'debug', @table_id, 'preferencesStore', data
|
@log 'debug', @table_id, 'preferencesStore', data
|
||||||
localStorage.setItem(@preferencesStoreKey(), JSON.stringify(data))
|
App.LocalStorage.set(@preferencesStoreKey(), data, @Session.get('id'))
|
||||||
|
|
||||||
preferencesGet: =>
|
preferencesGet: =>
|
||||||
data = localStorage.getItem(@preferencesStoreKey())
|
data = App.LocalStorage.get(@preferencesStoreKey(), @Session.get('id'))
|
||||||
return {} if !data
|
return {} if !data
|
||||||
@log 'debug', @table_id, 'preferencesGet', data
|
@log 'debug', @table_id, 'preferencesGet', data
|
||||||
JSON.parse(data)
|
data
|
||||||
|
|
||||||
preferencesStoreKey: =>
|
preferencesStoreKey: =>
|
||||||
"tablePreferences:#{@table_id}"
|
"tablePreferences:#{@table_id}"
|
||||||
|
|
|
@ -5,14 +5,14 @@ class App.DashboardActivityStream extends App.Controller
|
||||||
@fetch()
|
@fetch()
|
||||||
|
|
||||||
# bind to rebuild view event
|
# bind to rebuild view event
|
||||||
@bind( 'activity_stream_rebuild', @load )
|
@bind('activity_stream_rebuild', @load)
|
||||||
|
|
||||||
fetch: =>
|
fetch: =>
|
||||||
|
|
||||||
# use cache of first page
|
# use cache of first page
|
||||||
cache = App.Store.get( 'activity_stream' )
|
cache = App.SessionStorage.get('activity_stream')
|
||||||
if cache
|
if cache
|
||||||
@load( cache )
|
@load(cache)
|
||||||
|
|
||||||
# init fetch via ajax, all other updates on time via websockets
|
# init fetch via ajax, all other updates on time via websockets
|
||||||
else
|
else
|
||||||
|
@ -25,15 +25,16 @@ class App.DashboardActivityStream extends App.Controller
|
||||||
}
|
}
|
||||||
processData: true
|
processData: true
|
||||||
success: (data) =>
|
success: (data) =>
|
||||||
App.Store.write( 'activity_stream', data )
|
|
||||||
@load(data)
|
@load(data)
|
||||||
)
|
)
|
||||||
|
|
||||||
load: (data) =>
|
load: (data) =>
|
||||||
|
|
||||||
|
App.SessionStorage.set('activity_stream', data)
|
||||||
|
|
||||||
items = data.activity_stream
|
items = data.activity_stream
|
||||||
|
|
||||||
# load assets
|
App.Collection.loadAssets(data.assets)
|
||||||
App.Collection.loadAssets( data.assets )
|
|
||||||
|
|
||||||
@render(items)
|
@render(items)
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ class App.DashboardActivityStream extends App.Controller
|
||||||
|
|
||||||
html = $('<div class="activity-entries"></div>')
|
html = $('<div class="activity-entries"></div>')
|
||||||
for item in items
|
for item in items
|
||||||
html.append( @renderItem(item) )
|
html.append(@renderItem(item))
|
||||||
|
|
||||||
@$('.activity-entries').remove()
|
@$('.activity-entries').remove()
|
||||||
@el.append html
|
@el.append html
|
||||||
|
|
|
@ -3,7 +3,7 @@ class App.DashboardRss extends App.Controller
|
||||||
super
|
super
|
||||||
|
|
||||||
# bind to rebuild view event
|
# bind to rebuild view event
|
||||||
@bind( 'rss_rebuild', @fetch )
|
@bind('rss_rebuild', @fetch)
|
||||||
|
|
||||||
# refresh list ever 600 sec.
|
# refresh list ever 600 sec.
|
||||||
@fetch()
|
@fetch()
|
||||||
|
@ -11,7 +11,7 @@ class App.DashboardRss extends App.Controller
|
||||||
fetch: =>
|
fetch: =>
|
||||||
|
|
||||||
# get data from cache
|
# get data from cache
|
||||||
cache = App.Store.get( 'dashboard_rss' )
|
cache = App.SessionStorage.get('dashboard_rss')
|
||||||
if cache
|
if cache
|
||||||
cache.head = 'Heise ATOM'
|
cache.head = 'Heise ATOM'
|
||||||
@render( cache )
|
@render( cache )
|
||||||
|
@ -34,7 +34,7 @@ class App.DashboardRss extends App.Controller
|
||||||
message: data.message
|
message: data.message
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
App.Store.write( 'dashboard_rss', data )
|
App.SessionStorage.set('dashboard_rss', data)
|
||||||
data.head = 'Heise ATOM'
|
data.head = 'Heise ATOM'
|
||||||
@render(data)
|
@render(data)
|
||||||
error: =>
|
error: =>
|
||||||
|
|
|
@ -134,7 +134,7 @@ class App.TicketCreate extends App.Controller
|
||||||
fetch: (params) ->
|
fetch: (params) ->
|
||||||
|
|
||||||
# use cache
|
# use cache
|
||||||
cache = App.Store.get( 'ticket_create_attributes' )
|
cache = App.SessionStorage.get( 'ticket_create_attributes' )
|
||||||
|
|
||||||
if cache && !params.ticket_id && !params.article_id
|
if cache && !params.ticket_id && !params.article_id
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ class App.TicketCreate extends App.Controller
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
|
||||||
# cache request
|
# cache request
|
||||||
App.Store.write( 'ticket_create_attributes', data )
|
App.SessionStorage.set( 'ticket_create_attributes', data )
|
||||||
|
|
||||||
# get edit form attributes
|
# get edit form attributes
|
||||||
@form_meta = data.form_meta
|
@form_meta = data.form_meta
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Index extends App.ControllerContent
|
||||||
fetch: (params) ->
|
fetch: (params) ->
|
||||||
|
|
||||||
# use cache
|
# use cache
|
||||||
cache = App.Store.get( 'ticket_create_attributes' )
|
cache = App.SessionStorage.get( 'ticket_create_attributes' )
|
||||||
|
|
||||||
if cache
|
if cache
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class Index extends App.ControllerContent
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
|
|
||||||
# cache request
|
# cache request
|
||||||
App.Store.write( 'ticket_create_attributes', data )
|
App.SessionStorage.set( 'ticket_create_attributes', data )
|
||||||
|
|
||||||
# get edit form attributes
|
# get edit form attributes
|
||||||
@form_meta = data.form_meta
|
@form_meta = data.form_meta
|
||||||
|
|
|
@ -1757,6 +1757,12 @@ class App.CustomerChatRef extends App.Controller
|
||||||
|
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
|
@interval(
|
||||||
|
=>
|
||||||
|
@updateNavMenu()
|
||||||
|
6800
|
||||||
|
)
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
@html App.view('layout_ref/customer_chat')()
|
@html App.view('layout_ref/customer_chat')()
|
||||||
|
|
||||||
|
@ -1765,11 +1771,36 @@ class App.CustomerChatRef extends App.Controller
|
||||||
# @testChat @chatWindows[0], 100
|
# @testChat @chatWindows[0], 100
|
||||||
@initQuiz()
|
@initQuiz()
|
||||||
|
|
||||||
|
@updateNavMenu()
|
||||||
|
|
||||||
show: (params) =>
|
show: (params) =>
|
||||||
|
|
||||||
# highlight navbar
|
# highlight navbar
|
||||||
@navupdate '#layout_ref/customer_chat'
|
@navupdate '#layout_ref/customer_chat'
|
||||||
|
|
||||||
|
randomCounter: (min, max) ->
|
||||||
|
parseInt(Math.random() * (max - min) + min)
|
||||||
|
|
||||||
|
counter: =>
|
||||||
|
@randomCounter(0,100)
|
||||||
|
|
||||||
|
switch: (state = undefined) =>
|
||||||
|
|
||||||
|
# read state
|
||||||
|
if state is undefined
|
||||||
|
value = App.SessionStorage.get('chat')
|
||||||
|
if value is undefined
|
||||||
|
value = false
|
||||||
|
return value
|
||||||
|
|
||||||
|
# write state
|
||||||
|
App.SessionStorage.set('chat', state)
|
||||||
|
|
||||||
|
updateNavMenu: =>
|
||||||
|
delay = ->
|
||||||
|
App.Event.trigger('menu:render')
|
||||||
|
@delay(delay, 200)
|
||||||
|
|
||||||
testChat: (chat, count) ->
|
testChat: (chat, count) ->
|
||||||
for i in [0..count]
|
for i in [0..count]
|
||||||
text = @questions[Math.floor(Math.random() * @questions.length)].question
|
text = @questions[Math.floor(Math.random() * @questions.length)].question
|
||||||
|
@ -1878,7 +1909,7 @@ class CustomerChatRouter extends App.ControllerPermanent
|
||||||
|
|
||||||
App.Config.set( 'layout_ref/customer_chat', CustomerChatRouter, 'Routes' )
|
App.Config.set( 'layout_ref/customer_chat', CustomerChatRouter, 'Routes' )
|
||||||
App.Config.set( 'CustomerChatRef', { controller: 'CustomerChatRef', authentication: true }, 'permanentTask' )
|
App.Config.set( 'CustomerChatRef', { controller: 'CustomerChatRef', authentication: true }, 'permanentTask' )
|
||||||
App.Config.set( 'CustomerChatRef', { prio: 1200, parent: '', name: 'Customer Chat', target: '#layout_ref/customer_chat', switch: true, counter: true, role: ['Agent'], class: 'chat' }, 'NavBar' )
|
App.Config.set( 'CustomerChatRef', { prio: 1200, parent: '', name: 'Customer Chat', target: '#layout_ref/customer_chat', key: 'CustomerChatRef', role: ['Agent'], class: 'chat' }, 'NavBar' )
|
||||||
|
|
||||||
|
|
||||||
class chatWindowRef extends Spine.Controller
|
class chatWindowRef extends Spine.Controller
|
||||||
|
|
|
@ -6,18 +6,25 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
# rerender view, e. g. on langauge change
|
# rerender view, e. g. on langauge change
|
||||||
@bind 'ui:rerender', (data) =>
|
@bind 'ui:rerender', =>
|
||||||
@renderMenu()
|
@renderMenu()
|
||||||
@renderPersonal()
|
@renderPersonal()
|
||||||
|
|
||||||
|
# rerender menu
|
||||||
|
@bind 'menu:render', =>
|
||||||
|
@renderMenu()
|
||||||
|
|
||||||
|
# rerender menu
|
||||||
|
@bind 'personal:render', =>
|
||||||
|
@renderPersonal()
|
||||||
|
|
||||||
# update selected item
|
# update selected item
|
||||||
@bind 'navupdate', (data) =>
|
@bind 'navupdate', =>
|
||||||
@update( arguments[0] )
|
@update(arguments[0])
|
||||||
|
|
||||||
# rebuild nav bar with given user data
|
# rebuild nav bar with given user data
|
||||||
@bind 'auth', (user) =>
|
@bind 'auth', (user) =>
|
||||||
@log 'Navigation', 'debug', 'navbar rebuild', user
|
@log 'Navigation', 'debug', 'navbar rebuild', user
|
||||||
|
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
# fetch new recent viewed after collection change
|
# fetch new recent viewed after collection change
|
||||||
|
@ -43,6 +50,16 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
renderMenu: =>
|
renderMenu: =>
|
||||||
items = @getItems( navbar: @Config.get( 'NavBar' ) )
|
items = @getItems( navbar: @Config.get( 'NavBar' ) )
|
||||||
|
|
||||||
|
# apply counter and switch info from persistant controllers (if exists)
|
||||||
|
for item in items
|
||||||
|
if item.key
|
||||||
|
worker = App.TaskManager.worker(item.key)
|
||||||
|
if worker
|
||||||
|
if worker.counter
|
||||||
|
item.counter = worker.counter()
|
||||||
|
if worker.switch
|
||||||
|
item.switch = worker.switch()
|
||||||
|
|
||||||
# get open tabs to repopen on rerender
|
# get open tabs to repopen on rerender
|
||||||
open_tab = {}
|
open_tab = {}
|
||||||
@$('.open').children('a').each( (i,d) ->
|
@$('.open').children('a').each( (i,d) ->
|
||||||
|
@ -56,12 +73,24 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
href = $(d).attr('href')
|
href = $(d).attr('href')
|
||||||
active_tab[href] = true
|
active_tab[href] = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# render menu
|
||||||
@$('.js-menu').html App.view('navigation/menu')(
|
@$('.js-menu').html App.view('navigation/menu')(
|
||||||
items: items
|
items: items
|
||||||
open_tab: open_tab
|
open_tab: open_tab
|
||||||
active_tab: active_tab
|
active_tab: active_tab
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# bind on switch changes and execute it on controller
|
||||||
|
@$('.js-menu .js-switch').bind('change', (e) =>
|
||||||
|
val = $(e.target).prop('checked')
|
||||||
|
key = $(e.target).closest('.menu-item').data('key')
|
||||||
|
return if !key
|
||||||
|
worker = App.TaskManager.worker(key)
|
||||||
|
return if !worker
|
||||||
|
worker.switch(val)
|
||||||
|
)
|
||||||
|
|
||||||
renderPersonal: =>
|
renderPersonal: =>
|
||||||
@recentViewNavbarItemsRebuild()
|
@recentViewNavbarItemsRebuild()
|
||||||
items = @getItems( navbar: @Config.get( 'NavBarRight' ) )
|
items = @getItems( navbar: @Config.get( 'NavBarRight' ) )
|
||||||
|
@ -198,7 +227,6 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
# remove not needed popovers
|
# remove not needed popovers
|
||||||
@delay( removePopovers, 280, 'removePopovers' )
|
@delay( removePopovers, 280, 'removePopovers' )
|
||||||
|
|
||||||
|
|
||||||
# observer search box
|
# observer search box
|
||||||
@$('#global-search').bind( 'focusout', (e) =>
|
@$('#global-search').bind( 'focusout', (e) =>
|
||||||
# delay to be able to click x
|
# delay to be able to click x
|
||||||
|
|
|
@ -23,9 +23,9 @@ class Index extends App.ControllerContent
|
||||||
return @params if @params
|
return @params if @params
|
||||||
|
|
||||||
@params = {}
|
@params = {}
|
||||||
paramsRaw = localStorage.getItem('report::params')
|
paramsRaw = App.SessionStorage.get('report::params')
|
||||||
if paramsRaw
|
if paramsRaw
|
||||||
@params = JSON.parse(paramsRaw)
|
@params = paramsRaw
|
||||||
return @params
|
return @params
|
||||||
|
|
||||||
@params.timeRange = 'year'
|
@params.timeRange = 'year'
|
||||||
|
@ -58,7 +58,7 @@ class Index extends App.ControllerContent
|
||||||
|
|
||||||
storeParams: =>
|
storeParams: =>
|
||||||
# store latest params
|
# store latest params
|
||||||
localStorage.setItem('report::params', JSON.stringify(@params))
|
App.SessionStorage.set('report::params', @params)
|
||||||
|
|
||||||
render: (data = {}) =>
|
render: (data = {}) =>
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ class Table extends App.Controller
|
||||||
for key, value of params
|
for key, value of params
|
||||||
@[key] = value
|
@[key] = value
|
||||||
|
|
||||||
@view_mode = localStorage.getItem( "mode:#{@view}" ) || 's'
|
@view_mode = App.LocalStorage.get("mode:#{@view}", @Session.get('id')) || 's'
|
||||||
@log 'notice', 'view:', @view, @view_mode
|
@log 'notice', 'view:', @view, @view_mode
|
||||||
|
|
||||||
return if !@view
|
return if !@view
|
||||||
|
@ -381,7 +381,7 @@ class Table extends App.Controller
|
||||||
viewmode: (e) =>
|
viewmode: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@view_mode = $(e.target).data('mode')
|
@view_mode = $(e.target).data('mode')
|
||||||
localStorage.setItem( "mode:#{@view}", @view_mode )
|
App.LocalStorage.set("mode:#{@view}", @view_mode, @Session.get('id'))
|
||||||
@fetch()
|
@fetch()
|
||||||
#@render()
|
#@render()
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ class App.TicketZoom extends App.Controller
|
||||||
@overview_id = false
|
@overview_id = false
|
||||||
|
|
||||||
@key = 'ticket::' + @ticket_id
|
@key = 'ticket::' + @ticket_id
|
||||||
cache = App.Store.get(@key)
|
cache = App.SessionStorage.get(@key)
|
||||||
if cache
|
if cache
|
||||||
@load(cache)
|
@load(cache)
|
||||||
update = =>
|
update = =>
|
||||||
|
@ -168,7 +168,7 @@ class App.TicketZoom extends App.Controller
|
||||||
@ticketUpdatedAtLastCall = newTicketRaw.updated_at
|
@ticketUpdatedAtLastCall = newTicketRaw.updated_at
|
||||||
|
|
||||||
@load(data, force)
|
@load(data, force)
|
||||||
App.Store.write(@key, data)
|
App.SessionStorage(@key, data)
|
||||||
|
|
||||||
if !@doNotLog
|
if !@doNotLog
|
||||||
@doNotLog = 1
|
@doNotLog = 1
|
||||||
|
|
|
@ -137,6 +137,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
ticket: ticket
|
ticket: ticket
|
||||||
articleTypes: @articleTypes
|
articleTypes: @articleTypes
|
||||||
article: @defaults
|
article: @defaults
|
||||||
|
form_id: @form_id
|
||||||
isCustomer: @isRole('Customer')
|
isCustomer: @isRole('Customer')
|
||||||
)
|
)
|
||||||
@setArticleType(@type)
|
@setArticleType(@type)
|
||||||
|
@ -167,7 +168,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
|
|
||||||
html5Upload.initialize(
|
html5Upload.initialize(
|
||||||
uploadUrl: App.Config.get('api_path') + '/ticket_attachment_upload',
|
uploadUrl: App.Config.get('api_path') + '/ticket_attachment_upload',
|
||||||
dropContainer: @el.get(0),
|
dropContainer: @$('.article-add').get(0),
|
||||||
cancelContainer: @cancelContainer,
|
cancelContainer: @cancelContainer,
|
||||||
inputField: @$('.article-attachment input').get(0),
|
inputField: @$('.article-attachment input').get(0),
|
||||||
key: 'File',
|
key: 'File',
|
||||||
|
|
|
@ -91,7 +91,7 @@ class App.TicketZoomHighlighter extends App.Controller
|
||||||
articles.off('mousedown', @onMouseDown)
|
articles.off('mousedown', @onMouseDown)
|
||||||
articles.on('mousedown', @onMouseDown) #future: touchend
|
articles.on('mousedown', @onMouseDown) #future: touchend
|
||||||
|
|
||||||
# for testing purposes the highlights get stored in localStorage
|
# for testing purposes the highlights get stored in atrticle preferences
|
||||||
loadHighlights: (ticket_article_id) ->
|
loadHighlights: (ticket_article_id) ->
|
||||||
return if !@isRole('Agent')
|
return if !@isRole('Agent')
|
||||||
article = App.TicketArticle.find(ticket_article_id)
|
article = App.TicketArticle.find(ticket_article_id)
|
||||||
|
|
|
@ -19,7 +19,7 @@ class App.WidgetTag extends App.Controller
|
||||||
@render()
|
@render()
|
||||||
return
|
return
|
||||||
|
|
||||||
@tags = App.Store.get( @cacheKey ) || []
|
@tags = App.SessionStorage.get( @cacheKey ) || []
|
||||||
if !_.isEmpty(@tags)
|
if !_.isEmpty(@tags)
|
||||||
@render()
|
@render()
|
||||||
@delay(
|
@delay(
|
||||||
|
@ -42,7 +42,7 @@ class App.WidgetTag extends App.Controller
|
||||||
processData: true
|
processData: true
|
||||||
success: (data, status, xhr) =>
|
success: (data, status, xhr) =>
|
||||||
@tags = data.tags
|
@tags = data.tags
|
||||||
App.Store.write( @cacheKey, @tags )
|
App.SessionStorage.set( @cacheKey, @tags )
|
||||||
@render()
|
@render()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,25 +4,25 @@ class App.Collection
|
||||||
@init: ->
|
@init: ->
|
||||||
_instance = new _collectionSingleton
|
_instance = new _collectionSingleton
|
||||||
|
|
||||||
@load: ( args ) ->
|
@load: (args) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _collectionSingleton
|
_instance ?= new _collectionSingleton
|
||||||
_instance.load( args )
|
_instance.load(args)
|
||||||
|
|
||||||
@loadAssets: ( args ) ->
|
@loadAssets: (args) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _collectionSingleton
|
_instance ?= new _collectionSingleton
|
||||||
_instance.loadAssets( args )
|
_instance.loadAssets(args)
|
||||||
|
|
||||||
@reset: ( args ) ->
|
@reset: (args) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _collectionSingleton
|
_instance ?= new _collectionSingleton
|
||||||
_instance.reset( args )
|
_instance.reset(args)
|
||||||
|
|
||||||
@resetCollections: ( args ) ->
|
@resetCollections: (args) ->
|
||||||
if _instance == undefined
|
if _instance == undefined
|
||||||
_instance ?= new _collectionSingleton
|
_instance ?= new _collectionSingleton
|
||||||
_instance.resetCollections( args )
|
_instance.resetCollections(args)
|
||||||
|
|
||||||
class _collectionSingleton extends Spine.Module
|
class _collectionSingleton extends Spine.Module
|
||||||
@include App.LogInclude
|
@include App.LogInclude
|
||||||
|
@ -35,7 +35,7 @@ class _collectionSingleton extends Spine.Module
|
||||||
@log 'error', 'loadAssets:trigger, got no data, cant load assets'
|
@log 'error', 'loadAssets:trigger, got no data, cant load assets'
|
||||||
return
|
return
|
||||||
|
|
||||||
@loadAssets( data )
|
@loadAssets(data)
|
||||||
|
|
||||||
# add trigger - bind new events
|
# add trigger - bind new events
|
||||||
App.Event.bind 'resetCollection', (data) =>
|
App.Event.bind 'resetCollection', (data) =>
|
||||||
|
@ -43,28 +43,14 @@ class _collectionSingleton extends Spine.Module
|
||||||
@log 'error', 'resetCollection:trigger, got no data, cant for collections'
|
@log 'error', 'resetCollection:trigger, got no data, cant for collections'
|
||||||
return
|
return
|
||||||
|
|
||||||
@resetCollections( data )
|
@resetCollections(data)
|
||||||
|
|
||||||
# find collections to load
|
|
||||||
@_loadObjectsFromSessionStore()
|
|
||||||
|
|
||||||
_loadObjectsFromSessionStore: ->
|
|
||||||
list = App.Store.list()
|
|
||||||
for key in list
|
|
||||||
parts = key.split('::')
|
|
||||||
if parts[0] is 'collection'
|
|
||||||
data = App.Store.get( key )
|
|
||||||
data['type'] = parts[1]
|
|
||||||
data['sessionStorage'] = true
|
|
||||||
|
|
||||||
@log 'debug', 'load INIT', data
|
|
||||||
@load( data )
|
|
||||||
|
|
||||||
resetCollections: (data) ->
|
resetCollections: (data) ->
|
||||||
# load assets
|
|
||||||
|
# load collection
|
||||||
for type, collection of data
|
for type, collection of data
|
||||||
@log 'debug', 'resetCollection:trigger', type, collection
|
@log 'debug', 'resetCollection:trigger', type, collection
|
||||||
@reset( sessionStorage: data.sessionStorage, type: type, data: collection )
|
@reset(type: type, data: collection)
|
||||||
|
|
||||||
reset: (params) ->
|
reset: (params) ->
|
||||||
|
|
||||||
|
@ -74,42 +60,28 @@ class _collectionSingleton extends Spine.Module
|
||||||
@log 'error', 'reset', "no such collection #{params.type}", params
|
@log 'error', 'reset', "no such collection #{params.type}", params
|
||||||
return
|
return
|
||||||
|
|
||||||
# remove permanent storage
|
|
||||||
@localDelete( params.type )
|
|
||||||
|
|
||||||
# reset in-memory
|
# reset in-memory
|
||||||
appObject.refresh( params.data, { clear: true } )
|
appObject.refresh(params.data, { clear: true })
|
||||||
|
|
||||||
# remember in store if not already requested from local storage
|
|
||||||
for object in params.data
|
|
||||||
@localStore( params.type, object )
|
|
||||||
|
|
||||||
loadAssets: (assets) ->
|
loadAssets: (assets) ->
|
||||||
@log 'debug', 'loadAssets', assets
|
@log 'debug', 'loadAssets', assets
|
||||||
for type, collections of assets
|
for type, collections of assets
|
||||||
@load( sessionStorage: false, type: type, data: collections )
|
@load(type: type, data: collections)
|
||||||
|
|
||||||
load: (params) ->
|
load: (params) ->
|
||||||
|
|
||||||
# no data to load
|
# no data to load
|
||||||
return if _.isEmpty( params.data )
|
return if _.isEmpty(params.data)
|
||||||
|
|
||||||
# check if collection exists
|
# check if collection exists
|
||||||
appObject = App[ params.type ]
|
appObject = App[params.type]
|
||||||
if !appObject
|
if !appObject
|
||||||
@log 'error', 'reset', "no such collection #{params.type}", params
|
@log 'error', 'reset', "no such collection #{params.type}", params
|
||||||
return
|
return
|
||||||
|
|
||||||
sessionStorage = params.sessionStorage
|
|
||||||
|
|
||||||
# load full array once
|
# load full array once
|
||||||
if _.isArray( params.data )
|
if _.isArray(params.data)
|
||||||
appObject.refresh( params.data )
|
appObject.refresh(params.data)
|
||||||
|
|
||||||
# remember in store if not already requested from local storage
|
|
||||||
if !sessionStorage
|
|
||||||
for object in params.data
|
|
||||||
@localStore( params.type, object )
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# load data from object
|
# load data from object
|
||||||
|
@ -117,26 +89,12 @@ class _collectionSingleton extends Spine.Module
|
||||||
if !params.refresh && appObject
|
if !params.refresh && appObject
|
||||||
|
|
||||||
# check if new object is newer, just load newer objects
|
# check if new object is newer, just load newer objects
|
||||||
if object.updated_at && appObject.exists( key )
|
if object.updated_at && appObject.exists(key)
|
||||||
exists = appObject.find( key )
|
exists = appObject.find(key)
|
||||||
if exists.updated_at
|
if exists.updated_at
|
||||||
if exists.updated_at < object.updated_at
|
if exists.updated_at < object.updated_at
|
||||||
appObject.refresh( object )
|
appObject.refresh(object)
|
||||||
else
|
else
|
||||||
appObject.refresh( object )
|
appObject.refresh(object)
|
||||||
else
|
else
|
||||||
appObject.refresh( object )
|
appObject.refresh(object)
|
||||||
|
|
||||||
# remember in store if not already requested from local storage
|
|
||||||
if !sessionStorage
|
|
||||||
@localStore( params.type, object)
|
|
||||||
|
|
||||||
localDelete: (type) ->
|
|
||||||
list = App.Store.list()
|
|
||||||
for key in list
|
|
||||||
parts = key.split('::')
|
|
||||||
if parts[0] is 'collection' && parts[1] is type
|
|
||||||
App.Store.delete(key)
|
|
||||||
|
|
||||||
localStore: (type, object) ->
|
|
||||||
App.Store.write( 'collection::' + type + '::' + object.id, { data: [ object ] } )
|
|
||||||
|
|
64
app/assets/javascripts/app/lib/app_post/local_storage.coffee
Normal file
64
app/assets/javascripts/app/lib/app_post/local_storage.coffee
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
class App.LocalStorage
|
||||||
|
_instance = undefined # Must be declared here to force the closure on the class
|
||||||
|
|
||||||
|
@set: (key, value, user_id) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.set(key, value, user_id)
|
||||||
|
|
||||||
|
@get: (key, user_id) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.get(key, user_id)
|
||||||
|
|
||||||
|
@delete: (key, user_id) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.delete(key)
|
||||||
|
|
||||||
|
@clear: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.clear()
|
||||||
|
|
||||||
|
@list: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.list()
|
||||||
|
|
||||||
|
# The actual Singleton class
|
||||||
|
class _storeSingleton
|
||||||
|
constructor: ->
|
||||||
|
|
||||||
|
# write to local storage
|
||||||
|
set: (key, value, user_id) ->
|
||||||
|
try
|
||||||
|
if user_id
|
||||||
|
key = "personal::#{user_id}::#{key}"
|
||||||
|
localStorage.setItem(key, JSON.stringify(value))
|
||||||
|
catch e
|
||||||
|
if e is QUOTA_EXCEEDED_ERR
|
||||||
|
# do something nice to notify your users
|
||||||
|
App.Log.error 'App.LocalStorage', 'Local storage quote exceeded!'
|
||||||
|
|
||||||
|
# get item
|
||||||
|
get: (key, user_id) ->
|
||||||
|
if user_id
|
||||||
|
key = "personal::#{user_id}::#{key}"
|
||||||
|
value = localStorage.getItem(key)
|
||||||
|
return if !value
|
||||||
|
JSON.parse(value)
|
||||||
|
|
||||||
|
# delete item
|
||||||
|
delete: (key, user_id) ->
|
||||||
|
if user_id
|
||||||
|
key = "personal::#{user_id}::#{key}"
|
||||||
|
localStorage.removeItem(key)
|
||||||
|
|
||||||
|
# clear local storage
|
||||||
|
clear: ->
|
||||||
|
localStorage.clear()
|
||||||
|
|
||||||
|
# return list of all keys
|
||||||
|
list: ->
|
||||||
|
window.localStorage
|
|
@ -0,0 +1,61 @@
|
||||||
|
class App.SessionStorage
|
||||||
|
_instance = undefined # Must be declared here to force the closure on the class
|
||||||
|
|
||||||
|
@set: (key, value) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.set(key, value)
|
||||||
|
|
||||||
|
@get: (key) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.get(key)
|
||||||
|
|
||||||
|
@delete: (key) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.delete(key)
|
||||||
|
|
||||||
|
@clear: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.clear()
|
||||||
|
|
||||||
|
@list: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _storeSingleton
|
||||||
|
_instance.list()
|
||||||
|
|
||||||
|
# The actual Singleton class
|
||||||
|
class _storeSingleton
|
||||||
|
constructor: ->
|
||||||
|
|
||||||
|
App.Event.bind 'clearStore', =>
|
||||||
|
@clear()
|
||||||
|
|
||||||
|
# write to local storage
|
||||||
|
set: (key, value) ->
|
||||||
|
try
|
||||||
|
sessionStorage.setItem(key, JSON.stringify(value))
|
||||||
|
catch e
|
||||||
|
if e is QUOTA_EXCEEDED_ERR
|
||||||
|
# do something nice to notify your users
|
||||||
|
App.Log.error 'App.SessionStorage', 'Session storage quote exceeded!'
|
||||||
|
|
||||||
|
# get item
|
||||||
|
get: (key) ->
|
||||||
|
value = sessionStorage.getItem(key)
|
||||||
|
return if !value
|
||||||
|
JSON.parse(value)
|
||||||
|
|
||||||
|
# delete item
|
||||||
|
delete: (key) ->
|
||||||
|
sessionStorage.removeItem(key)
|
||||||
|
|
||||||
|
# clear local storage
|
||||||
|
clear: ->
|
||||||
|
sessionStorage.clear()
|
||||||
|
|
||||||
|
# return list of all keys
|
||||||
|
list: ->
|
||||||
|
window.sessionStorage
|
|
@ -1,93 +0,0 @@
|
||||||
class App.Store
|
|
||||||
_instance = undefined # Must be declared here to force the closure on the class
|
|
||||||
@renew: ->
|
|
||||||
_instance = new _storeSingleton
|
|
||||||
|
|
||||||
@write: (key, value) ->
|
|
||||||
if _instance == undefined
|
|
||||||
_instance ?= new _storeSingleton
|
|
||||||
_instance.write(key, value)
|
|
||||||
|
|
||||||
@get: (args) ->
|
|
||||||
if _instance == undefined
|
|
||||||
_instance ?= new _storeSingleton
|
|
||||||
_instance.get(args)
|
|
||||||
|
|
||||||
@delete: (args) ->
|
|
||||||
if _instance == undefined
|
|
||||||
_instance ?= new _storeSingleton
|
|
||||||
_instance.delete(args)
|
|
||||||
|
|
||||||
@clear: ->
|
|
||||||
if _instance == undefined
|
|
||||||
_instance ?= new _storeSingleton
|
|
||||||
_instance.clear()
|
|
||||||
|
|
||||||
@list: ->
|
|
||||||
if _instance == undefined
|
|
||||||
_instance ?= new _storeSingleton
|
|
||||||
_instance.list()
|
|
||||||
|
|
||||||
# The actual Singleton class
|
|
||||||
class _storeSingleton
|
|
||||||
store: {}
|
|
||||||
constructor: ->
|
|
||||||
@support = true
|
|
||||||
if !window.sessionStorage
|
|
||||||
@support = false
|
|
||||||
# @support = false
|
|
||||||
|
|
||||||
# clear store on every login/logout
|
|
||||||
if @support
|
|
||||||
App.Event.bind 'clearStore', =>
|
|
||||||
@clear('all')
|
|
||||||
|
|
||||||
# write to local storage
|
|
||||||
write: (key, value) ->
|
|
||||||
@store[key] = value
|
|
||||||
return if !@support
|
|
||||||
return if !App.Config.get('ui_client_storage')
|
|
||||||
try
|
|
||||||
sessionStorage.setItem( key, JSON.stringify( value ) )
|
|
||||||
catch e
|
|
||||||
if e is QUOTA_EXCEEDED_ERR
|
|
||||||
# do something nice to notify your users
|
|
||||||
App.Log.error 'App.Store', 'Local storage quote exceeded, please relogin!'
|
|
||||||
|
|
||||||
# get item
|
|
||||||
get: (key) ->
|
|
||||||
return @store[key] if !@support
|
|
||||||
return @store[key] if !App.Config.get('ui_client_storage')
|
|
||||||
value = sessionStorage.getItem( key )
|
|
||||||
return if !value
|
|
||||||
object = JSON.parse( value )
|
|
||||||
return object
|
|
||||||
|
|
||||||
# delete item
|
|
||||||
delete: (key) ->
|
|
||||||
delete @store[key]
|
|
||||||
return if !@support
|
|
||||||
return if !App.Config.get('ui_client_storage')
|
|
||||||
sessionStorage.removeItem( key )
|
|
||||||
|
|
||||||
# clear local storage
|
|
||||||
clear: ->
|
|
||||||
@store = {}
|
|
||||||
sessionStorage.clear()
|
|
||||||
|
|
||||||
# return list of all keys
|
|
||||||
list: ->
|
|
||||||
list = []
|
|
||||||
if !@support || !App.Config.get('ui_client_storage')
|
|
||||||
for key of @store
|
|
||||||
list.push key
|
|
||||||
return list
|
|
||||||
|
|
||||||
# logLength = sessionStorage.length-1;
|
|
||||||
# for count in [0..logLength]
|
|
||||||
# key = sessionStorage.key( count )
|
|
||||||
# if key
|
|
||||||
# list.push key
|
|
||||||
for key of window.sessionStorage
|
|
||||||
list.push key
|
|
||||||
list
|
|
|
@ -290,7 +290,6 @@ class _webSocketSingleton extends App.Controller
|
||||||
# fill collection
|
# fill collection
|
||||||
if item['collection']
|
if item['collection']
|
||||||
@log 'debug', 'onmessage collection:' + item['collection']
|
@log 'debug', 'onmessage collection:' + item['collection']
|
||||||
App.Store.write( item['collection'], item['data'] )
|
|
||||||
|
|
||||||
# fire event
|
# fire event
|
||||||
if item['event']
|
if item['event']
|
||||||
|
|
|
@ -1,18 +1,9 @@
|
||||||
class App.Model extends Spine.Model
|
class App.Model extends Spine.Model
|
||||||
@destroyBind: false
|
|
||||||
@apiPath: App.Config.get('api_path')
|
@apiPath: App.Config.get('api_path')
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
|
|
||||||
# delete object from local storage on destroy
|
|
||||||
if !@constructor.destroyBind
|
|
||||||
@bind( 'destroy', (e) ->
|
|
||||||
className = Object.getPrototypeOf(e).constructor.className
|
|
||||||
key = "collection::#{className}::#{e.id}"
|
|
||||||
App.Store.delete(key)
|
|
||||||
)
|
|
||||||
|
|
||||||
uiUrl: ->
|
uiUrl: ->
|
||||||
'#'
|
'#'
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,17 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<% else: %>
|
<% else: %>
|
||||||
<a class="menu-item js-<%- item.class %>MenuItem<%- ' is-active' if @active_tab[item.target] %>" href="<%= item.target %>">
|
<a class="menu-item js-<%- item.class %>MenuItem<%- ' is-active' if @active_tab[item.target] %>" href="<%= item.target %>" data-key="<%- item.key %>">
|
||||||
<%- @Icon(item.class, 'menu-item-icon') %>
|
<%- @Icon(item.class, 'menu-item-icon') %>
|
||||||
<span class="menu-item-name">
|
<span class="menu-item-name">
|
||||||
<%- @T(item.name) %>
|
<%- @T(item.name) %>
|
||||||
</span>
|
</span>
|
||||||
<% if item.counter: %>
|
<% if item.counter isnt undefined: %>
|
||||||
<span class="counter badge badge--big"></span>
|
<span class="counter badge badge--big"><%= item.counter %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if item.switch: %>
|
<% if item.switch isnt undefined: %>
|
||||||
<span class="zammad-switch zammad-switch--dark zammad-switch--small">
|
<span class="zammad-switch zammad-switch--dark zammad-switch--small">
|
||||||
<input type="checkbox" id="<%- item.class %>-switch">
|
<input type="checkbox" id="<%- item.class %>-switch" class="js-switch" <% if item.switch: %>checked<% end %>>
|
||||||
<label for="<%- item.class %>-switch"></label>
|
<label for="<%- item.class %>-switch"></label>
|
||||||
</span>
|
</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<form class="article-add <% if @article.internal: %>is-internal<% else: %>is-public<% end %>" data-type="<%= @article.type %>">
|
<form class="article-add <% if @article.internal: %>is-internal<% else: %>is-public<% end %>" data-type="<%= @article.type %>">
|
||||||
<input type="hidden" name="type" value="<%= @article.type %>">
|
<input type="hidden" name="type" value="<%= @article.type %>">
|
||||||
<input type="hidden" name="internal" value="<%= @article.internal %>">
|
<input type="hidden" name="internal" value="<%= @article.internal %>">
|
||||||
<input type="hidden" name="form_id" value="<%= @article.form_id %>">
|
<input type="hidden" name="form_id" value="<%= @form_id %>">
|
||||||
<input type="hidden" name="in_reply_to" value="<%= @article.in_reply_to %>">
|
<input type="hidden" name="in_reply_to" value="<%= @article.in_reply_to %>">
|
||||||
<div class="editControls">
|
<div class="editControls">
|
||||||
<div class="js-avatar"></div>
|
<div class="js-avatar"></div>
|
||||||
|
|
|
@ -374,8 +374,8 @@ test( "events level", function() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// local store
|
// session store
|
||||||
test( "local store", function() {
|
test( "session store", function() {
|
||||||
|
|
||||||
var tests = [
|
var tests = [
|
||||||
'some 123äöüßadajsdaiosjdiaoidj',
|
'some 123äöüßadajsdaiosjdiaoidj',
|
||||||
|
@ -384,17 +384,17 @@ test( "local store", function() {
|
||||||
];
|
];
|
||||||
|
|
||||||
// write/get
|
// write/get
|
||||||
App.Store.clear()
|
App.SessionStorage.clear()
|
||||||
_.each(tests, function(test) {
|
_.each(tests, function(test) {
|
||||||
App.Store.write( 'test1', test );
|
App.SessionStorage.set( 'test1', test );
|
||||||
var item = App.Store.get( 'test1' );
|
var item = App.SessionStorage.get( 'test1' );
|
||||||
deepEqual( test, item, 'write/get - compare stored and actual data' )
|
deepEqual( test, item, 'write/get - compare stored and actual data' )
|
||||||
});
|
});
|
||||||
|
|
||||||
// undefined/get
|
// undefined/get
|
||||||
App.Store.clear()
|
App.SessionStorage.clear()
|
||||||
_.each(tests, function(test) {
|
_.each(tests, function(test) {
|
||||||
var item = App.Store.get( 'test1' );
|
var item = App.SessionStorage.get( 'test1' );
|
||||||
deepEqual( undefined, item, 'undefined/get - compare not existing data and actual data' )
|
deepEqual( undefined, item, 'undefined/get - compare not existing data and actual data' )
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -405,16 +405,16 @@ test( "local store", function() {
|
||||||
{ key: '123äöüß', value: { key1: [1,2,3,4] }, key2: [1,2,'äöüß'] },
|
{ key: '123äöüß', value: { key1: [1,2,3,4] }, key2: [1,2,'äöüß'] },
|
||||||
];
|
];
|
||||||
|
|
||||||
App.Store.clear()
|
App.SessionStorage.clear()
|
||||||
_.each(tests, function(test) {
|
_.each(tests, function(test) {
|
||||||
App.Store.write( test.key, test.value );
|
App.SessionStorage.set( test.key, test.value );
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(tests, function(test) {
|
_.each(tests, function(test) {
|
||||||
var item = App.Store.get( test.key );
|
var item = App.SessionStorage.get( test.key );
|
||||||
deepEqual( test.value, item, 'write/get/delete - compare stored and actual data' );
|
deepEqual( test.value, item, 'write/get/delete - compare stored and actual data' );
|
||||||
App.Store.delete( test.key );
|
App.SessionStorage.delete( test.key );
|
||||||
item = App.Store.get( test.key );
|
item = App.SessionStorage.get( test.key );
|
||||||
deepEqual( undefined, item, 'write/get/delete - compare deleted data' );
|
deepEqual( undefined, item, 'write/get/delete - compare deleted data' );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue