Refactoring: Bindings and namespaces improves memory usage and resolved ghost bindings.
* Renamed controllers `@bind` and `@unbind` to `@controllerBind` and `@controllerUnbind` to not overwrite spine's methods to take advantage of spine's binding/unbinding and cleanup features. * Cleanup of controller namespaces `App.ObserverController` -> `App.ControllerObserver`, `App.ObserverActionRow` -> `App.ControllerObserverActionRow` and `App.WizardModal` -> `App.ControllerWizardModal` * Moved to named local controller names to have better trace backs/debugging (e. g. `class Index` to `class UserIndex`). * Splited `app/assets/javascripts/app/controllers/_application_controller.coffee` into separate files under `app/assets/javascripts/app/controllers/_application_controller/*.coffee` to have better trace backs/debugging. * Moved classes with executed code from `app/assets/javascripts/app/controllers/widget/*.coffee` into `app/assets/javascripts/app/controllers/_plugin/` from now `app/assets/javascripts/app/controllers/widget/*.coffee` will only contain UI widgets like popovers. * Refactored second argument of `@navigate`. Old version was only `true` to hide `@navigate` redirect from browser back list. Now we introduced params instant of boolean argument. Now we support: * `hideCurrentLocationFromHistory: true` -> hide redirect from browser back list (old `true` argument) * `emptyEl: true` -> will empty `@el` before redirect to new location * `removeEl: true` -> will remove `@el` before redirect to new location
This commit is contained in:
parent
0eac6f0fd9
commit
5ee6418c18
193 changed files with 3846 additions and 3788 deletions
|
@ -2,12 +2,7 @@ class App.Controller extends Spine.Controller
|
|||
@include App.LogInclude
|
||||
@include App.RenderScreen
|
||||
|
||||
constructor: (params) ->
|
||||
|
||||
# unbind old bindings
|
||||
if params && params.el && params.el.unbind
|
||||
params.el.unbind()
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# generate controllerId
|
||||
|
@ -30,11 +25,14 @@ class App.Controller extends Spine.Controller
|
|||
ajaxId = App.Ajax.request(data)
|
||||
@ajaxCalls.push ajaxId
|
||||
|
||||
navigate: (location, hideCurrentLocationFromHistory = false) ->
|
||||
@log 'debug', "navigate to '#{location}', hide from history '#{hideCurrentLocationFromHistory}'"
|
||||
navigate: (location, params = {}) ->
|
||||
@log 'debug', "navigate to '#{location}'"
|
||||
@log 'debug', "navigate hide from history '#{params.hideCurrentLocationFromHistory}'" if params.hideCurrentLocationFromHistory
|
||||
@el.empty() if params.emptyEl
|
||||
@el.remove() if params.removeEl
|
||||
|
||||
# hide current location from browser history, allow to use back button in browser
|
||||
if hideCurrentLocationFromHistory
|
||||
if params.hideCurrentLocationFromHistory
|
||||
if window.history
|
||||
history = App.Config.get('History')
|
||||
oldLocation = history[history.length-2]
|
||||
|
@ -45,22 +43,14 @@ class App.Controller extends Spine.Controller
|
|||
preventDefault: (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
bind: (event, callback) =>
|
||||
controllerBind: (event, callback) =>
|
||||
App.Event.bind(
|
||||
event
|
||||
callback
|
||||
@controllerId
|
||||
)
|
||||
|
||||
one: (event, callback) =>
|
||||
App.Event.bind(
|
||||
event
|
||||
callback
|
||||
@controllerId
|
||||
true
|
||||
)
|
||||
|
||||
unbind: (event, callback) =>
|
||||
controllerUnbind: (event, callback) =>
|
||||
App.Event.unbind(
|
||||
event
|
||||
callback
|
||||
|
@ -85,6 +75,16 @@ class App.Controller extends Spine.Controller
|
|||
App.Interval.clearLevel(@controllerId)
|
||||
@abortAjaxCalls()
|
||||
|
||||
# release bindings
|
||||
if @el
|
||||
@el.undelegate()
|
||||
@el.unbind()
|
||||
@el.empty()
|
||||
|
||||
# release spine bindings (see release() of spine.coffee)
|
||||
@unbind()
|
||||
@stopListening()
|
||||
|
||||
abortAjaxCalls: =>
|
||||
if !@ajaxCalls
|
||||
return
|
||||
|
@ -125,11 +125,11 @@ class App.Controller extends Spine.Controller
|
|||
|
||||
# add @notify method to create notification
|
||||
notify: (data) ->
|
||||
App.Event.trigger 'notify', data
|
||||
App.Event.trigger('notify', data)
|
||||
|
||||
# add @notifyDesktop method to create desktop notification
|
||||
notifyDesktop: (data) ->
|
||||
App.Event.trigger 'notifyDesktop', data
|
||||
App.Event.trigger('notifyDesktop', data)
|
||||
|
||||
# add @navupdate method to update navigation
|
||||
navupdate: (url, force = false) ->
|
||||
|
@ -137,17 +137,7 @@ class App.Controller extends Spine.Controller
|
|||
# ignore navupdate until #clues are gone
|
||||
return if !force && window.location.hash is '#clues'
|
||||
|
||||
App.Event.trigger 'navupdate', url
|
||||
|
||||
# show navigation
|
||||
navShow: ->
|
||||
return if $('#navigation').is(':visible')
|
||||
$('#navigation').removeClass('hide')
|
||||
|
||||
# hide navigation
|
||||
navHide: ->
|
||||
return if !$('#navigation').is(':visible')
|
||||
$('#navigation').addClass('hide')
|
||||
App.Event.trigger('navupdate', url)
|
||||
|
||||
updateNavMenu: =>
|
||||
delay = ->
|
||||
|
@ -402,340 +392,3 @@ class App.Controller extends Spine.Controller
|
|||
return true
|
||||
|
||||
throw 'Cant reload page!'
|
||||
|
||||
class App.ControllerPermanent extends App.Controller
|
||||
constructor: ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission, true)
|
||||
|
||||
super
|
||||
|
||||
@navShow()
|
||||
|
||||
class App.ControllerSubContent extends App.Controller
|
||||
constructor: ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission)
|
||||
|
||||
super
|
||||
|
||||
show: =>
|
||||
if @genericController && @genericController.show
|
||||
@genericController.show()
|
||||
return if !@header
|
||||
@title @header, true
|
||||
|
||||
hide: =>
|
||||
if @genericController && @genericController.hide
|
||||
@genericController.hide()
|
||||
|
||||
class App.ControllerContent extends App.Controller
|
||||
constructor: ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission)
|
||||
|
||||
super
|
||||
|
||||
# hide tasks
|
||||
App.TaskManager.hideAll()
|
||||
$('#content').removeClass('hide').removeClass('active')
|
||||
@navShow()
|
||||
|
||||
class App.ControllerModal extends App.Controller
|
||||
authenticateRequired: false
|
||||
backdrop: true
|
||||
keyboard: true
|
||||
large: false
|
||||
small: false
|
||||
veryLarge: false
|
||||
head: '?'
|
||||
autoFocusOnFirstInput: true
|
||||
container: null
|
||||
buttonClass: 'btn--success'
|
||||
centerButtons: []
|
||||
leftButtons: []
|
||||
buttonClose: true
|
||||
buttonCancel: false
|
||||
buttonCancelClass: 'btn--text btn--subtle'
|
||||
buttonSubmit: true
|
||||
includeForm: true
|
||||
headPrefix: ''
|
||||
shown: true
|
||||
closeOnAnyClick: false
|
||||
initalFormParams: {}
|
||||
initalFormParamsIgnore: false
|
||||
showTrySupport: false
|
||||
showTryMax: 10
|
||||
showTrydelay: 1000
|
||||
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
'click .js-submit:not(.is-disabled)': 'submit'
|
||||
'click .js-cancel': 'cancel'
|
||||
'click .js-close': 'cancel'
|
||||
|
||||
className: 'modal fade'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@showTryCount = 0
|
||||
|
||||
if @authenticateRequired
|
||||
return if !@authenticateCheckRedirect()
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@bind('ui:rerender', =>
|
||||
@update()
|
||||
'modal'
|
||||
)
|
||||
if @shown
|
||||
@render()
|
||||
|
||||
showDelayed: =>
|
||||
delay = =>
|
||||
@showTryCount += 1
|
||||
@render()
|
||||
@delay(delay, @showTrydelay)
|
||||
|
||||
modalAlreadyExists: ->
|
||||
return true if $('.modal').length > 0
|
||||
false
|
||||
|
||||
content: ->
|
||||
'You need to implement a one @content()!'
|
||||
|
||||
update: =>
|
||||
if @message
|
||||
content = App.i18n.translateContent(@message)
|
||||
else if @contentInline
|
||||
content = @contentInline
|
||||
else
|
||||
content = @content()
|
||||
modal = $(App.view('modal')(
|
||||
head: @head
|
||||
headPrefix: @headPrefix
|
||||
message: @message
|
||||
detail: @detail
|
||||
buttonClose: @buttonClose
|
||||
buttonCancel: @buttonCancel
|
||||
buttonCancelClass: @buttonCancelClass
|
||||
buttonSubmit: @buttonSubmit
|
||||
buttonClass: @buttonClass
|
||||
centerButtons: @centerButtons
|
||||
leftButtons: @leftButtons
|
||||
includeForm: @includeForm
|
||||
))
|
||||
modal.find('.modal-body').html(content)
|
||||
if !@initRenderingDone
|
||||
@initRenderingDone = true
|
||||
@html(modal)
|
||||
else
|
||||
@$('.modal-dialog').replaceWith(modal)
|
||||
@post()
|
||||
|
||||
post: ->
|
||||
# nothing
|
||||
|
||||
element: =>
|
||||
@el
|
||||
|
||||
render: =>
|
||||
if @showTrySupport is true && @modalAlreadyExists() && @showTryCount <= @showTryMax
|
||||
@showDelayed()
|
||||
return
|
||||
|
||||
@initalFormParamsIgnore = false
|
||||
|
||||
if @buttonSubmit is true
|
||||
@buttonSubmit = 'Submit'
|
||||
if @buttonCancel is true
|
||||
@buttonCancel = 'Cancel & Go Back'
|
||||
|
||||
@update()
|
||||
|
||||
if @container
|
||||
@el.addClass('modal--local')
|
||||
if @veryLarge
|
||||
@el.addClass('modal--veryLarge')
|
||||
if @large
|
||||
@el.addClass('modal--large')
|
||||
if @small
|
||||
@el.addClass('modal--small')
|
||||
|
||||
@el
|
||||
.on(
|
||||
'show.bs.modal': @localOnShow
|
||||
'shown.bs.modal': @localOnShown
|
||||
'hide.bs.modal': @localOnClose
|
||||
'hidden.bs.modal': @localOnClosed
|
||||
'dismiss.bs.modal': @localOnCancel
|
||||
).modal(
|
||||
keyboard: @keyboard
|
||||
show: true
|
||||
backdrop: @backdrop
|
||||
container: @container
|
||||
)
|
||||
|
||||
if @closeOnAnyClick
|
||||
@el.on('click', =>
|
||||
@close()
|
||||
)
|
||||
|
||||
close: (e) =>
|
||||
if e
|
||||
e.preventDefault()
|
||||
@initalFormParamsIgnore = true
|
||||
@el.modal('hide')
|
||||
|
||||
formParams: =>
|
||||
if @container
|
||||
return @formParam(@container.find('.modal form'))
|
||||
return @formParam(@$('.modal form'))
|
||||
|
||||
showAlert: (message, suffix = 'danger') ->
|
||||
alert = $('<div>')
|
||||
.addClass("alert alert--#{suffix}")
|
||||
.text(message)
|
||||
|
||||
@$('.modal-alerts-container').html(alert)
|
||||
|
||||
clearAlerts: ->
|
||||
@$('.modal-alerts-container').empty()
|
||||
|
||||
localOnShow: (e) =>
|
||||
@onShow(e)
|
||||
|
||||
onShow: (e) ->
|
||||
# do nothing
|
||||
|
||||
localOnShown: (e) =>
|
||||
@onShown(e)
|
||||
|
||||
onShown: (e) =>
|
||||
if @autoFocusOnFirstInput
|
||||
|
||||
# select generated form
|
||||
form = @$('.form-group').first()
|
||||
|
||||
# if not exists, use whole @el
|
||||
if !form.get(0)
|
||||
form = @el
|
||||
|
||||
# focus first input, select or textarea
|
||||
form.find('input:not([disabled]):not([type="hidden"]):not(".btn"), select:not([disabled]), textarea:not([disabled])').first().focus()
|
||||
|
||||
@initalFormParams = @formParams()
|
||||
|
||||
localOnClose: (e) =>
|
||||
diff = difference(@initalFormParams, @formParams())
|
||||
if @initalFormParamsIgnore is false && !_.isEmpty(diff)
|
||||
if !confirm(App.i18n.translateContent('The form content has been changed. Do you want to close it and lose your changes?'))
|
||||
e.preventDefault()
|
||||
return
|
||||
@onClose(e)
|
||||
|
||||
onClose: ->
|
||||
# do nothing
|
||||
|
||||
localOnClosed: (e) =>
|
||||
@onClosed(e)
|
||||
@el.modal('remove')
|
||||
|
||||
onClosed: (e) ->
|
||||
# do nothing
|
||||
|
||||
localOnCancel: (e) =>
|
||||
@onCancel(e)
|
||||
|
||||
onCancel: (e) ->
|
||||
# do nothing
|
||||
|
||||
cancel: (e) =>
|
||||
@close(e)
|
||||
@onCancel(e)
|
||||
|
||||
onSubmit: (e) ->
|
||||
# do nothing
|
||||
|
||||
submit: (e) =>
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
@clearAlerts()
|
||||
@onSubmit(e)
|
||||
|
||||
startLoading: =>
|
||||
@$('.modal-body').addClass('hide')
|
||||
@$('.modal-loader').removeClass('hide')
|
||||
|
||||
stopLoading: =>
|
||||
@$('.modal-body').removeClass('hide')
|
||||
@$('.modal-loader').addClass('hide')
|
||||
|
||||
class App.SessionMessage extends App.ControllerModal
|
||||
showTrySupport: true
|
||||
|
||||
onCancel: (e) =>
|
||||
if @forceReload
|
||||
@windowReload(e)
|
||||
|
||||
onClose: (e) =>
|
||||
if @forceReload
|
||||
@windowReload(e)
|
||||
|
||||
onSubmit: (e) =>
|
||||
if @forceReload
|
||||
@windowReload(e)
|
||||
else
|
||||
@close()
|
||||
|
||||
class App.UpdateHeader extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# subscribe and reload data / fetch new data if triggered
|
||||
@subscribeId = @genericObject.subscribe(@render)
|
||||
|
||||
release: =>
|
||||
App[ @genericObject.constructor.className ].unsubscribe(@subscribeId)
|
||||
|
||||
render: (genericObject) =>
|
||||
@el.find('.page-header h1').html(genericObject.displayName())
|
||||
|
||||
|
||||
class App.UpdateTastbar extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# subscribe and reload data / fetch new data if triggered
|
||||
@subscribeId = @genericObject.subscribe(@update)
|
||||
|
||||
release: =>
|
||||
App[ @genericObject.constructor.className ].unsubscribe(@subscribeId)
|
||||
|
||||
update: (genericObject) =>
|
||||
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@taskKey)
|
||||
|
||||
class App.ControllerWidgetPermanent extends App.Controller
|
||||
constructor: (params) ->
|
||||
if params.el
|
||||
params.el.append('<div id="' + params.key + '"></div>')
|
||||
params.el = ("##{params.key}")
|
||||
|
||||
super(params)
|
||||
|
||||
class App.ControllerWidgetOnDemand extends App.Controller
|
||||
constructor: (params) ->
|
||||
params.el = $("##{params.key}")
|
||||
super
|
||||
|
||||
element: =>
|
||||
$("##{@key}")
|
||||
|
||||
html: (raw) =>
|
||||
|
||||
# check if parent exists
|
||||
if !$("##{@key}").get(0)
|
||||
$('#app').before("<div id=\"#{@key}\" class=\"#{@className}\"></div>")
|
||||
$("##{@key}").html raw
|
|
@ -0,0 +1,229 @@
|
|||
class App.ControllerModal extends App.Controller
|
||||
authenticateRequired: false
|
||||
backdrop: true
|
||||
keyboard: true
|
||||
large: false
|
||||
small: false
|
||||
veryLarge: false
|
||||
head: '?'
|
||||
autoFocusOnFirstInput: true
|
||||
container: null
|
||||
buttonClass: 'btn--success'
|
||||
centerButtons: []
|
||||
leftButtons: []
|
||||
buttonClose: true
|
||||
buttonCancel: false
|
||||
buttonCancelClass: 'btn--text btn--subtle'
|
||||
buttonSubmit: true
|
||||
includeForm: true
|
||||
headPrefix: ''
|
||||
shown: true
|
||||
closeOnAnyClick: false
|
||||
initalFormParams: {}
|
||||
initalFormParamsIgnore: false
|
||||
showTrySupport: false
|
||||
showTryMax: 10
|
||||
showTrydelay: 1000
|
||||
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
'click .js-submit:not(.is-disabled)': 'submit'
|
||||
'click .js-cancel': 'cancel'
|
||||
'click .js-close': 'cancel'
|
||||
|
||||
className: 'modal fade'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@showTryCount = 0
|
||||
|
||||
if @authenticateRequired
|
||||
return if !@authenticateCheckRedirect()
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@controllerBind('ui:rerender', =>
|
||||
@update()
|
||||
'modal'
|
||||
)
|
||||
if @shown
|
||||
@render()
|
||||
|
||||
showDelayed: =>
|
||||
delay = =>
|
||||
@showTryCount += 1
|
||||
@render()
|
||||
@delay(delay, @showTrydelay)
|
||||
|
||||
modalAlreadyExists: ->
|
||||
return true if $('.modal').length > 0
|
||||
false
|
||||
|
||||
content: ->
|
||||
'You need to implement a one @content()!'
|
||||
|
||||
update: =>
|
||||
if @message
|
||||
content = App.i18n.translateContent(@message)
|
||||
else if @contentInline
|
||||
content = @contentInline
|
||||
else
|
||||
content = @content()
|
||||
modal = $(App.view('modal')(
|
||||
head: @head
|
||||
headPrefix: @headPrefix
|
||||
message: @message
|
||||
detail: @detail
|
||||
buttonClose: @buttonClose
|
||||
buttonCancel: @buttonCancel
|
||||
buttonCancelClass: @buttonCancelClass
|
||||
buttonSubmit: @buttonSubmit
|
||||
buttonClass: @buttonClass
|
||||
centerButtons: @centerButtons
|
||||
leftButtons: @leftButtons
|
||||
includeForm: @includeForm
|
||||
))
|
||||
modal.find('.modal-body').html(content)
|
||||
if !@initRenderingDone
|
||||
@initRenderingDone = true
|
||||
@html(modal)
|
||||
else
|
||||
@$('.modal-dialog').replaceWith(modal)
|
||||
@post()
|
||||
|
||||
post: ->
|
||||
# nothing
|
||||
|
||||
element: =>
|
||||
@el
|
||||
|
||||
render: =>
|
||||
if @showTrySupport is true && @modalAlreadyExists() && @showTryCount <= @showTryMax
|
||||
@showDelayed()
|
||||
return
|
||||
|
||||
@initalFormParamsIgnore = false
|
||||
|
||||
if @buttonSubmit is true
|
||||
@buttonSubmit = 'Submit'
|
||||
if @buttonCancel is true
|
||||
@buttonCancel = 'Cancel & Go Back'
|
||||
|
||||
@update()
|
||||
|
||||
if @container
|
||||
@el.addClass('modal--local')
|
||||
if @veryLarge
|
||||
@el.addClass('modal--veryLarge')
|
||||
if @large
|
||||
@el.addClass('modal--large')
|
||||
if @small
|
||||
@el.addClass('modal--small')
|
||||
|
||||
@el
|
||||
.on(
|
||||
'show.bs.modal': @localOnShow
|
||||
'shown.bs.modal': @localOnShown
|
||||
'hide.bs.modal': @localOnClose
|
||||
'hidden.bs.modal': @localOnClosed
|
||||
'dismiss.bs.modal': @localOnCancel
|
||||
).modal(
|
||||
keyboard: @keyboard
|
||||
show: true
|
||||
backdrop: @backdrop
|
||||
container: @container
|
||||
)
|
||||
|
||||
if @closeOnAnyClick
|
||||
@el.on('click', =>
|
||||
@close()
|
||||
)
|
||||
|
||||
close: (e) =>
|
||||
if e
|
||||
e.preventDefault()
|
||||
@initalFormParamsIgnore = true
|
||||
@el.modal('hide')
|
||||
|
||||
formParams: =>
|
||||
if @container
|
||||
return @formParam(@container.find('.modal form'))
|
||||
return @formParam(@$('.modal form'))
|
||||
|
||||
showAlert: (message, suffix = 'danger') ->
|
||||
alert = $('<div>')
|
||||
.addClass("alert alert--#{suffix}")
|
||||
.text(message)
|
||||
|
||||
@$('.modal-alerts-container').html(alert)
|
||||
|
||||
clearAlerts: ->
|
||||
@$('.modal-alerts-container').empty()
|
||||
|
||||
localOnShow: (e) =>
|
||||
@onShow(e)
|
||||
|
||||
onShow: (e) ->
|
||||
# do nothing
|
||||
|
||||
localOnShown: (e) =>
|
||||
@onShown(e)
|
||||
|
||||
onShown: (e) =>
|
||||
if @autoFocusOnFirstInput
|
||||
|
||||
# select generated form
|
||||
form = @$('.form-group').first()
|
||||
|
||||
# if not exists, use whole @el
|
||||
if !form.get(0)
|
||||
form = @el
|
||||
|
||||
# focus first input, select or textarea
|
||||
form.find('input:not([disabled]):not([type="hidden"]):not(".btn"), select:not([disabled]), textarea:not([disabled])').first().focus()
|
||||
|
||||
@initalFormParams = @formParams()
|
||||
|
||||
localOnClose: (e) =>
|
||||
diff = difference(@initalFormParams, @formParams())
|
||||
if @initalFormParamsIgnore is false && !_.isEmpty(diff)
|
||||
if !confirm(App.i18n.translateContent('The form content has been changed. Do you want to close it and lose your changes?'))
|
||||
e.preventDefault()
|
||||
return
|
||||
@onClose(e)
|
||||
|
||||
onClose: ->
|
||||
# do nothing
|
||||
|
||||
localOnClosed: (e) =>
|
||||
@onClosed(e)
|
||||
@el.modal('remove')
|
||||
|
||||
onClosed: (e) ->
|
||||
# do nothing
|
||||
|
||||
localOnCancel: (e) =>
|
||||
@onCancel(e)
|
||||
|
||||
onCancel: (e) ->
|
||||
# do nothing
|
||||
|
||||
cancel: (e) =>
|
||||
@close(e)
|
||||
@onCancel(e)
|
||||
|
||||
onSubmit: (e) ->
|
||||
# do nothing
|
||||
|
||||
submit: (e) =>
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
@clearAlerts()
|
||||
@onSubmit(e)
|
||||
|
||||
startLoading: =>
|
||||
@$('.modal-body').addClass('hide')
|
||||
@$('.modal-loader').removeClass('hide')
|
||||
|
||||
stopLoading: =>
|
||||
@$('.modal-body').removeClass('hide')
|
||||
@$('.modal-loader').addClass('hide')
|
|
@ -0,0 +1,15 @@
|
|||
class App.ControllerAppContent extends App.Controller
|
||||
constructor: (params) ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission)
|
||||
|
||||
# hide tasks
|
||||
App.TaskManager.hideAll()
|
||||
|
||||
params.el = params.appEl.find('#content')
|
||||
params.el.removeClass('hide').removeClass('active')
|
||||
if !params.el.get(0)
|
||||
params.appEl.append('<div id="content" class="content flex horizontal"></div>')
|
||||
params.el = $('#content')
|
||||
|
||||
super(params)
|
|
@ -0,0 +1,331 @@
|
|||
class App.CollectionController extends App.Controller
|
||||
events:
|
||||
'click .js-remove': 'remove'
|
||||
'click .js-item': 'click'
|
||||
'click .js-locationVerify': 'location'
|
||||
observe:
|
||||
field1: true
|
||||
field2: false
|
||||
#currentItems: {}
|
||||
#1:
|
||||
# a: 123
|
||||
# b: 'some string'
|
||||
#2:
|
||||
# a: 123
|
||||
# b: 'some string'
|
||||
#renderList: {}
|
||||
#1: ..dom..ref..
|
||||
#2: ..dom..ref..
|
||||
template: '_need_to_be_defined_'
|
||||
uniqKey: 'id'
|
||||
model: '_need_to_be_defined_'
|
||||
sortBy: 'name'
|
||||
order: 'ASC',
|
||||
insertPosition: 'after'
|
||||
globalRerender: true
|
||||
|
||||
constructor: ->
|
||||
@events = @constructor.events unless @events
|
||||
@observe = @constructor.observe unless @observe
|
||||
@currentItems = {}
|
||||
@renderList = {}
|
||||
@queue = []
|
||||
@queueRunning = false
|
||||
@lastOrder = []
|
||||
|
||||
super
|
||||
|
||||
@queue.push ['renderAll']
|
||||
@uIRunner()
|
||||
|
||||
# bind to changes
|
||||
if @model
|
||||
@subscribeId = App[@model].subscribe(@collectionSync)
|
||||
|
||||
# render on generic ui call
|
||||
if @globalRerender
|
||||
@controllerBind('ui:rerender', =>
|
||||
@queue.push ['renderAll']
|
||||
@uIRunner()
|
||||
)
|
||||
|
||||
# render on login
|
||||
@controllerBind('auth:login', =>
|
||||
@queue.push ['renderAll']
|
||||
@uIRunner()
|
||||
)
|
||||
|
||||
# reset current tasks on logout
|
||||
@controllerBind('auth:logout', =>
|
||||
@queue.push ['renderAll']
|
||||
@uIRunner()
|
||||
)
|
||||
|
||||
@log 'debug', 'Init @uniqKey', @uniqKey
|
||||
@log 'debug', 'Init @observe', @observe
|
||||
@log 'debug', 'Init @model', @model
|
||||
|
||||
release: =>
|
||||
if @subscribeId
|
||||
App[@model].unsubscribe(@subscribeId)
|
||||
|
||||
uIRunner: =>
|
||||
return if !@queue[0]
|
||||
return if @queueRunning
|
||||
@queueRunning = true
|
||||
loop
|
||||
param = @queue.shift()
|
||||
if param[0] is 'domChange'
|
||||
@domChange(param[1])
|
||||
else if param[0] is 'domRemove'
|
||||
@domRemove(param[1])
|
||||
else if param[0] is 'change'
|
||||
@collectionSync(param[1])
|
||||
else if param[0] is 'destroy'
|
||||
@collectionSync(param[1], 'destroy')
|
||||
else if param[0] is 'renderAll'
|
||||
@renderAll()
|
||||
else
|
||||
@log 'error', "Unknown type #{param[0]}", param[1]
|
||||
if !@queue[0]
|
||||
@onRenderEnd()
|
||||
@queueRunning = false
|
||||
break
|
||||
|
||||
collectionOrderGet: =>
|
||||
newOrder = []
|
||||
all = @itemsAll()
|
||||
for item in all
|
||||
newOrder.push item[@uniqKey]
|
||||
newOrder
|
||||
|
||||
collectionOrderSet: (newOrder = false) =>
|
||||
if !newOrder
|
||||
newOrder = @collectionOrderGet()
|
||||
@lastOrder = newOrder
|
||||
|
||||
collectionSync: (items, type) =>
|
||||
|
||||
# remove items
|
||||
if type is 'destroy'
|
||||
ids = []
|
||||
for item in items
|
||||
ids.push item[@uniqKey]
|
||||
@queue.push ['domRemove', ids]
|
||||
@uIRunner()
|
||||
return
|
||||
|
||||
# inital render
|
||||
if _.isEmpty(@renderList)
|
||||
@queue.push ['renderAll']
|
||||
@uIRunner()
|
||||
return
|
||||
|
||||
# check if item order is the same
|
||||
newOrder = @collectionOrderGet()
|
||||
removedIds = _.difference(@lastOrder, newOrder)
|
||||
addedIds = _.difference(newOrder, @lastOrder)
|
||||
|
||||
@log 'debug', 'collectionSync removedIds', removedIds
|
||||
@log 'debug', 'collectionSync addedIds', addedIds
|
||||
@log 'debug', 'collectionSync @lastOrder', @lastOrder
|
||||
@log 'debug', 'collectionSync newOrder', newOrder
|
||||
|
||||
# add items
|
||||
alreadyRemoved = false
|
||||
if !_.isEmpty(addedIds)
|
||||
lastOrderNew = []
|
||||
for id in @lastOrder
|
||||
if !_.contains(removedIds, id)
|
||||
lastOrderNew.push id
|
||||
|
||||
# try to find positions of new items
|
||||
@log 'debug', 'collectionSync lastOrderNew', lastOrderNew
|
||||
applyOrder = App.Utils.diffPositionAdd(lastOrderNew, newOrder)
|
||||
@log 'debug', 'collectionSync applyOrder', applyOrder
|
||||
if !applyOrder
|
||||
@queue.push ['renderAll']
|
||||
@uIRunner()
|
||||
return
|
||||
|
||||
if !_.isEmpty(removedIds)
|
||||
alreadyRemoved = true
|
||||
@queue.push ['domRemove', removedIds]
|
||||
@uIRunner()
|
||||
|
||||
newItems = []
|
||||
for apply in applyOrder
|
||||
item = @itemGet(apply.id)
|
||||
item.meta_position = apply.position
|
||||
newItems.push item
|
||||
@queue.push ['domChange', newItems]
|
||||
@uIRunner()
|
||||
|
||||
# remove items
|
||||
if !alreadyRemoved && !_.isEmpty(removedIds)
|
||||
@queue.push ['domRemove', removedIds]
|
||||
@uIRunner()
|
||||
|
||||
# update items
|
||||
newItems = []
|
||||
for item in items
|
||||
if !_.contains(removedIds, item.id) && !_.contains(addedIds, item.id)
|
||||
newItems.push item
|
||||
return if _.isEmpty(newItems)
|
||||
@queue.push ['domChange', newItems]
|
||||
@uIRunner()
|
||||
#return
|
||||
|
||||
# rerender all items
|
||||
#@queue.push ['renderAll']
|
||||
#@uIRunner()
|
||||
|
||||
domRemove: (ids) =>
|
||||
@log 'debug', 'domRemove', ids
|
||||
for id in ids
|
||||
@itemAttributesDelete(id)
|
||||
if @renderList[id]
|
||||
@renderList[id].remove()
|
||||
delete @renderList[id]
|
||||
@onRemoved(id)
|
||||
@collectionOrderSet()
|
||||
|
||||
domChange: (items) =>
|
||||
@log 'debug', 'domChange items', items
|
||||
@log 'debug', 'domChange @currentItems', @currentItems
|
||||
changedItems = []
|
||||
for item in items
|
||||
@log 'debug', 'domChange|item', item
|
||||
attributes = @itemAttributes(item)
|
||||
currentItem = @itemAttributesGet(item[@uniqKey])
|
||||
if !currentItem
|
||||
@log 'debug', 'domChange|add', item
|
||||
changedItems.push item
|
||||
@itemAttributesSet(item[@uniqKey], attributes)
|
||||
else
|
||||
@log 'debug', 'domChange|change', item
|
||||
@log 'debug', 'domChange|change|observe attributes', @observe
|
||||
@log 'debug', 'domChange|change|current', currentItem
|
||||
@log 'debug', 'domChange|change|new', attributes
|
||||
for field of @observe
|
||||
@log 'debug', 'domChange|change|compare', field, currentItem[field], attributes[field]
|
||||
diff = !_.isEqual(currentItem[field], attributes[field])
|
||||
@log 'debug', 'domChange|diff', diff
|
||||
if diff
|
||||
changedItems.push item
|
||||
@itemAttributesSet(item[@uniqKey], attributes)
|
||||
break
|
||||
return if _.isEmpty(changedItems)
|
||||
@renderParts(changedItems)
|
||||
|
||||
renderAll: =>
|
||||
items = @itemsAll()
|
||||
@log 'debug', 'renderAll', items
|
||||
localeEls = []
|
||||
for item in items
|
||||
attributes = @itemAttributes(item)
|
||||
@itemAttributesSet(item[@uniqKey], attributes)
|
||||
localeEls.push @renderItem(item, false)
|
||||
@html localeEls
|
||||
@collectionOrderSet()
|
||||
@onRenderEnd()
|
||||
|
||||
itemDestroy: (id) =>
|
||||
App[@model].destroy(id)
|
||||
|
||||
itemsAll: =>
|
||||
App[@model].search(sortBy: @sortBy, order: @order)
|
||||
|
||||
itemAttributesDiff: (item) =>
|
||||
attributes = @itemAttributes(item)
|
||||
currentItem = @itemAttributesGet(item[@uniqKey])
|
||||
for field of @observe
|
||||
@log 'debug', 'itemAttributesDiff|compare', field, currentItem[field], attributes[field]
|
||||
diff = !_.isEqual(currentItem[field], attributes[field])
|
||||
if diff
|
||||
@log 'debug', 'itemAttributesDiff|diff', diff
|
||||
return true
|
||||
false
|
||||
|
||||
itemAttributesDelete: (id) =>
|
||||
delete @currentItems[id]
|
||||
|
||||
itemAttributesGet: (id) =>
|
||||
@currentItems[id]
|
||||
|
||||
itemAttributesSet: (id, attributes) =>
|
||||
@currentItems[id] = attributes
|
||||
|
||||
itemAttributes: (item) =>
|
||||
attributes = {}
|
||||
for field of @observe
|
||||
attributes[field] = item[field]
|
||||
attributes
|
||||
|
||||
itemGet: (id) =>
|
||||
App[@model].find(id)
|
||||
|
||||
renderParts: (items) =>
|
||||
@log 'debug', 'renderParts', items
|
||||
for item in items
|
||||
if !@renderList[item[@uniqKey]]
|
||||
@renderItem(item)
|
||||
else
|
||||
@renderItem(item, @renderList[item[@uniqKey]])
|
||||
@collectionOrderSet()
|
||||
|
||||
renderItem: (item, el) =>
|
||||
if @prepareForObjectListItemSupport
|
||||
item = @prepareForObjectListItem(item)
|
||||
@log 'debug', 'renderItem', item, @template, el, @renderList[item[@uniqKey]]
|
||||
html = $(App.view(@template)(
|
||||
item: item
|
||||
))
|
||||
if @onRenderItemEnd
|
||||
@onRenderItemEnd(item, html)
|
||||
itemCount = Object.keys(@renderList).length
|
||||
@renderList[item[@uniqKey]] = html
|
||||
if el is false
|
||||
return html
|
||||
else if !el
|
||||
position = item.meta_position
|
||||
if itemCount > position
|
||||
position += 1
|
||||
element = @el.find(".js-item:nth-child(#{position})")
|
||||
if !element.get(0)
|
||||
@el.append(html)
|
||||
return
|
||||
if @insertPosition is 'before'
|
||||
element.before(html)
|
||||
else
|
||||
element.after(html)
|
||||
else
|
||||
el.replaceWith(html)
|
||||
|
||||
onRenderEnd: ->
|
||||
# nothing
|
||||
|
||||
location: (e) =>
|
||||
@locationVerify(e)
|
||||
|
||||
click: (e) =>
|
||||
row = $(e.target).closest('.js-item')
|
||||
id = row.data('id')
|
||||
@onClick(id, e)
|
||||
|
||||
onClick: (id, e) ->
|
||||
# nothing
|
||||
|
||||
remove: (e) =>
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
row = $(e.target).closest('.js-item')
|
||||
id = row.data('id')
|
||||
@onRemove(id,e)
|
||||
@itemDestroy(id)
|
||||
|
||||
onRemove: (id, e) ->
|
||||
# nothing
|
||||
|
||||
onRemoved: (id) ->
|
||||
# nothing
|
|
@ -0,0 +1,19 @@
|
|||
class App.ControllerDrox extends App.Controller
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
if params.data && ( params.data.text || params.data.html )
|
||||
@inline(params.data)
|
||||
|
||||
inline: (data) ->
|
||||
@html App.view('generic/drox')(data)
|
||||
if data.text
|
||||
@$('.drox-body').text(data.text)
|
||||
if data.html
|
||||
@$('.drox-body').html(data.html)
|
||||
|
||||
template: (data) ->
|
||||
drox = $( App.view('generic/drox')(data) )
|
||||
content = App.view(data.file)(data.params)
|
||||
drox.find('.drox-body').append(content)
|
||||
drox
|
|
@ -0,0 +1,20 @@
|
|||
class App.ControllerFullPage extends App.Controller
|
||||
constructor: (params) ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission)
|
||||
super
|
||||
|
||||
replaceWith: (localElement) =>
|
||||
@appEl.find('>').not(".#{@className}").remove() if @className
|
||||
@appEl.find('>').filter(".#{@className}").remove() if @forceRender
|
||||
@el = $(localElement)
|
||||
container = @appEl.find('>').filter(".#{@className}")
|
||||
if !container.get(0)
|
||||
@el.addClass(@className)
|
||||
@appEl.append(@el)
|
||||
@delegateEvents(@events)
|
||||
@refreshElements()
|
||||
@el.on('remove', @releaseController)
|
||||
@el.on('remove', @release)
|
||||
else
|
||||
container.html(@el.children())
|
|
@ -0,0 +1,11 @@
|
|||
class App.ControllerGenericDescription extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: false
|
||||
buttonSubmit: 'Close'
|
||||
head: 'Description'
|
||||
|
||||
content: =>
|
||||
marked(App.i18n.translateContent(@description))
|
||||
|
||||
onSubmit: =>
|
||||
@close()
|
|
@ -0,0 +1,37 @@
|
|||
class App.ControllerGenericDestroyConfirm extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: 'delete'
|
||||
buttonClass: 'btn--danger'
|
||||
head: 'Confirm'
|
||||
small: true
|
||||
|
||||
content: ->
|
||||
App.i18n.translateContent('Sure to delete this object?')
|
||||
|
||||
onSubmit: =>
|
||||
options = @options || {}
|
||||
options.done = =>
|
||||
@close()
|
||||
if @callback
|
||||
@callback()
|
||||
options.fail = =>
|
||||
@log 'errors'
|
||||
@close()
|
||||
@item.destroy(options)
|
||||
|
||||
class App.ControllerConfirm extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: 'yes'
|
||||
buttonClass: 'btn--danger'
|
||||
head: 'Confirm'
|
||||
small: true
|
||||
|
||||
content: ->
|
||||
App.i18n.translateContent(@message)
|
||||
|
||||
onSubmit: =>
|
||||
@close()
|
||||
if @callback
|
||||
@callback()
|
|
@ -0,0 +1,53 @@
|
|||
class App.ControllerGenericEdit extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: true
|
||||
headPrefix: 'Edit'
|
||||
|
||||
content: =>
|
||||
@item = App[ @genericObject ].find( @id )
|
||||
@head = @pageData.head || @pageData.object
|
||||
|
||||
@controller = new App.ControllerForm(
|
||||
model: App[ @genericObject ]
|
||||
params: @item
|
||||
screen: @screen || 'edit'
|
||||
autofocus: true
|
||||
handlers: @handlers
|
||||
)
|
||||
@controller.form
|
||||
|
||||
onSubmit: (e) ->
|
||||
params = @formParam(e.target)
|
||||
@item.load(params)
|
||||
|
||||
# validate form using HTML5 validity check
|
||||
element = $(e.target).closest('form').get(0)
|
||||
if element && element.reportValidity && !element.reportValidity()
|
||||
return false
|
||||
|
||||
# validate
|
||||
errors = @item.validate()
|
||||
if errors
|
||||
@log 'error', errors
|
||||
@formValidate( form: e.target, errors: errors )
|
||||
return false
|
||||
|
||||
# disable form
|
||||
@formDisable(e)
|
||||
|
||||
# save object
|
||||
ui = @
|
||||
@item.save(
|
||||
done: ->
|
||||
if ui.callback
|
||||
item = App[ ui.genericObject ].fullLocal(@id)
|
||||
ui.callback(item)
|
||||
ui.close()
|
||||
|
||||
fail: (settings, details) ->
|
||||
App[ ui.genericObject ].fetch(id: @id)
|
||||
ui.log 'errors'
|
||||
ui.formEnable(e)
|
||||
ui.controller.showAlert(details.error_human || details.error || 'Unable to update object!')
|
||||
)
|
|
@ -0,0 +1,17 @@
|
|||
class App.ControllerErrorModal extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: false
|
||||
buttonSubmit: 'Close'
|
||||
#buttonClass: 'btn--danger'
|
||||
head: 'Error'
|
||||
#small: true
|
||||
#shown: true
|
||||
showTrySupport: true
|
||||
|
||||
content: ->
|
||||
@message
|
||||
|
||||
onSubmit: =>
|
||||
@close()
|
||||
if @callback
|
||||
@callback()
|
|
@ -0,0 +1,112 @@
|
|||
class App.GenericHistory extends App.ControllerModal
|
||||
@extend App.PopoverProvidable
|
||||
@registerPopovers 'User'
|
||||
|
||||
buttonClose: true
|
||||
buttonCancel: false
|
||||
buttonSubmit: false
|
||||
head: 'History'
|
||||
shown: false
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@fetch()
|
||||
|
||||
content: =>
|
||||
localItem = @reworkItems(@items)
|
||||
|
||||
content = $ App.view('generic/history')(
|
||||
items: localItem
|
||||
)
|
||||
content.find('a[data-type="sortorder"]').bind('click', (e) =>
|
||||
e.preventDefault()
|
||||
@sortorder()
|
||||
)
|
||||
content
|
||||
|
||||
onShown: =>
|
||||
@renderPopovers()
|
||||
|
||||
sortorder: =>
|
||||
@items = @items.reverse()
|
||||
@update()
|
||||
|
||||
T: (name) ->
|
||||
App.i18n.translateInline(name)
|
||||
|
||||
reworkItems: (items) ->
|
||||
newItems = []
|
||||
newItem = {}
|
||||
lastUserId = undefined
|
||||
lastTime = undefined
|
||||
items = clone(items)
|
||||
for item in items
|
||||
|
||||
if item.object is 'Ticket::Article'
|
||||
item.object = 'Article'
|
||||
|
||||
data = item
|
||||
data.created_by = App.User.find( item.created_by_id )
|
||||
|
||||
currentItemTime = new Date( item.created_at )
|
||||
lastItemTime = new Date( new Date( lastTime ).getTime() + (15 * 1000) )
|
||||
|
||||
# start new section if user or time has changed
|
||||
if lastUserId isnt item.created_by_id || currentItemTime > lastItemTime
|
||||
lastTime = item.created_at
|
||||
lastUserId = item.created_by_id
|
||||
if !_.isEmpty(newItem)
|
||||
newItems.push newItem
|
||||
newItem =
|
||||
created_at: item.created_at
|
||||
created_by: App.User.find( item.created_by_id )
|
||||
records: []
|
||||
|
||||
# build content
|
||||
content = ''
|
||||
if item.type is 'notification' || item.type is 'email'
|
||||
content = "#{ @T( item.type ) } #{ @T( 'sent to' ) } '#{ item.value_to }'"
|
||||
else if item.type is 'received_merge'
|
||||
ticket = App.Ticket.find( item.id_from )
|
||||
ticket_link = if ticket
|
||||
"<a href=\"#ticket/zoom/#{ item.id_from }\">##{ ticket.number }</a>"
|
||||
else
|
||||
item.value_from
|
||||
content = "#{ @T( 'Ticket' ) } #{ ticket_link } #{ @T( 'was merged into this ticket' ) }"
|
||||
else if item.type is 'merged_into'
|
||||
ticket = App.Ticket.find( item.id_to )
|
||||
ticket_link = if ticket
|
||||
"<a href=\"#ticket/zoom/#{ item.id_to }\">##{ ticket.number }</a>"
|
||||
else
|
||||
item.value_to
|
||||
content = "#{ @T( 'This ticket was merged into' ) } #{ @T( 'ticket' ) } #{ ticket_link }"
|
||||
else
|
||||
content = "#{ @T( item.type ) } #{ @T(item.object) } "
|
||||
if item.attribute
|
||||
content += "#{ @T(item.attribute) }"
|
||||
|
||||
# convert time stamps
|
||||
if item.object is 'User' && item.attribute is 'last_login'
|
||||
if item.value_from
|
||||
item.value_from = App.i18n.translateTimestamp( item.value_from )
|
||||
if item.value_to
|
||||
item.value_to = App.i18n.translateTimestamp( item.value_to )
|
||||
|
||||
if item.value_from
|
||||
if item.value_to
|
||||
content += " #{ @T( 'from' ) }"
|
||||
content += " '#{ App.Utils.htmlEscape(item.value_from) }'"
|
||||
|
||||
if item.value_to
|
||||
if item.value_from
|
||||
content += ' →'
|
||||
content += " '#{ App.Utils.htmlEscape(item.value_to) }'"
|
||||
else if item.value_from
|
||||
content += " → '-'"
|
||||
|
||||
newItem.records.push content
|
||||
|
||||
if !_.isEmpty(newItem)
|
||||
newItems.push newItem
|
||||
|
||||
newItems
|
|
@ -0,0 +1,192 @@
|
|||
class App.ControllerGenericIndex extends App.Controller
|
||||
events:
|
||||
'click [data-type=edit]': 'edit'
|
||||
'click [data-type=new]': 'new'
|
||||
'click [data-type=import]': 'import'
|
||||
'click .js-description': 'description'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# set title
|
||||
if @pageData.title
|
||||
@title @pageData.title, true
|
||||
|
||||
# set nav bar
|
||||
if @pageData.navupdate
|
||||
@navupdate @pageData.navupdate
|
||||
|
||||
# bind render after a change is done
|
||||
if !@disableRender
|
||||
@subscribeId = App[ @genericObject ].subscribe(@render)
|
||||
|
||||
App[ @genericObject ].bind 'ajaxError', (rec, msg) =>
|
||||
@log 'error', 'ajax', msg.status
|
||||
if msg.status is 401
|
||||
@log 'error', 'ajax', rec, msg, msg.status
|
||||
@navigate 'login'
|
||||
|
||||
# execute fetch
|
||||
@render()
|
||||
|
||||
# fetch all
|
||||
if !@disableInitFetch && !@pageData.pagerAjax
|
||||
App[ @genericObject ].fetchFull(
|
||||
->
|
||||
clear: true
|
||||
)
|
||||
|
||||
show: =>
|
||||
if @table
|
||||
@table.show()
|
||||
|
||||
hide: =>
|
||||
if @table
|
||||
@table.hide()
|
||||
|
||||
release: =>
|
||||
if @subscribeId
|
||||
App[ @genericObject ].unsubscribe(@subscribeId)
|
||||
|
||||
paginate: (page) =>
|
||||
return if page is @pageData.pagerSelected
|
||||
@pageData.pagerSelected = page
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
if @pageData.pagerAjax
|
||||
sortBy = @table?.customOrderBy || @table?.orderBy || @defaultSortBy || 'id'
|
||||
orderBy = @table?.customOrderDirection || @table?.orderDirection || @defaultOrder || 'ASC'
|
||||
|
||||
fallbackSortBy = sortBy
|
||||
fallbackOrderBy = orderBy
|
||||
if sortBy isnt 'id'
|
||||
fallbackSortBy = "#{sortBy}, id"
|
||||
fallbackOrderBy = "#{orderBy}, ASC"
|
||||
|
||||
@startLoading()
|
||||
App[@genericObject].indexFull(
|
||||
(collection, data) =>
|
||||
@pageData.pagerTotalCount = data.total_count
|
||||
@stopLoading()
|
||||
@renderObjects(collection)
|
||||
{
|
||||
refresh: false
|
||||
sort_by: fallbackSortBy
|
||||
order_by: fallbackOrderBy
|
||||
page: @pageData.pagerSelected
|
||||
per_page: @pageData.pagerPerPage
|
||||
}
|
||||
)
|
||||
return
|
||||
|
||||
objects = App[@genericObject].search(
|
||||
sortBy: @defaultSortBy || 'name'
|
||||
order: @defaultOrder
|
||||
)
|
||||
@renderObjects(objects)
|
||||
|
||||
renderObjects: (objects) =>
|
||||
|
||||
# remove ignored items from collection
|
||||
if @ignoreObjectIDs
|
||||
objects = _.filter( objects, (item) ->
|
||||
return if item.id is 1
|
||||
return item
|
||||
)
|
||||
|
||||
if !@table
|
||||
|
||||
# show description button, only if content exists
|
||||
showDescription = false
|
||||
if App[ @genericObject ].description && !_.isEmpty(objects)
|
||||
showDescription = true
|
||||
|
||||
@html App.view('generic/admin/index')(
|
||||
head: @pageData.objects
|
||||
notes: @pageData.notes
|
||||
buttons: @pageData.buttons
|
||||
menus: @pageData.menus
|
||||
showDescription: showDescription
|
||||
)
|
||||
|
||||
# show description in content if no no content exists
|
||||
if _.isEmpty(objects) && App[ @genericObject ].description
|
||||
description = marked(App[ @genericObject ].description)
|
||||
@$('.table-overview').html(description)
|
||||
return
|
||||
|
||||
# append content table
|
||||
params = _.extend(
|
||||
{
|
||||
tableId: "#{@genericObject}-generic-overview"
|
||||
el: @$('.table-overview')
|
||||
model: App[ @genericObject ]
|
||||
objects: objects
|
||||
bindRow:
|
||||
events:
|
||||
click: @edit
|
||||
container: @container
|
||||
explanation: @pageData.explanation
|
||||
groupBy: @groupBy
|
||||
dndCallback: @dndCallback
|
||||
},
|
||||
@pageData.tableExtend
|
||||
)
|
||||
|
||||
if @pageData.pagerAjax
|
||||
params = _.extend(
|
||||
{
|
||||
pagerAjax: @pageData.pagerAjax
|
||||
pagerBaseUrl: @pageData.pagerBaseUrl
|
||||
pagerSelected: @pageData.pagerSelected
|
||||
pagerPerPage: @pageData.pagerPerPage
|
||||
pagerTotalCount: @pageData.pagerTotalCount
|
||||
sortRenderCallback: @render
|
||||
},
|
||||
params
|
||||
)
|
||||
|
||||
if !@table
|
||||
@table = new App.ControllerTable(params)
|
||||
else
|
||||
@table.update(objects: objects, pagerSelected: @pageData.pagerSelected, pagerTotalCount: @pageData.pagerTotalCount)
|
||||
|
||||
edit: (id, e) =>
|
||||
e.preventDefault()
|
||||
item = App[ @genericObject ].find(id)
|
||||
|
||||
if @editCallback
|
||||
@editCallback(item)
|
||||
return
|
||||
|
||||
new App.ControllerGenericEdit(
|
||||
id: item.id
|
||||
pageData: @pageData
|
||||
genericObject: @genericObject
|
||||
container: @container
|
||||
small: @small
|
||||
large: @large
|
||||
veryLarge: @veryLarge
|
||||
)
|
||||
|
||||
new: (e) ->
|
||||
e.preventDefault()
|
||||
new App.ControllerGenericNew(
|
||||
pageData: @pageData
|
||||
genericObject: @genericObject
|
||||
container: @container
|
||||
small: @small
|
||||
large: @large
|
||||
veryLarge: @veryLarge
|
||||
)
|
||||
|
||||
import: (e) ->
|
||||
e.preventDefault()
|
||||
@importCallback()
|
||||
|
||||
description: (e) =>
|
||||
new App.ControllerGenericDescription(
|
||||
description: App[ @genericObject ].description
|
||||
container: @container
|
||||
)
|
|
@ -0,0 +1,53 @@
|
|||
class App.ControllerGenericNew extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: true
|
||||
headPrefix: 'New'
|
||||
showTrySupport: true
|
||||
|
||||
content: =>
|
||||
@head = @pageData.head || @pageData.object
|
||||
@controller = new App.ControllerForm(
|
||||
model: App[ @genericObject ]
|
||||
params: @item
|
||||
screen: @screen || 'edit'
|
||||
autofocus: true
|
||||
handlers: @handlers
|
||||
)
|
||||
@controller.form
|
||||
|
||||
onSubmit: (e) ->
|
||||
params = @formParam(e.target)
|
||||
|
||||
object = new App[ @genericObject ]
|
||||
object.load(params)
|
||||
|
||||
# validate form using HTML5 validity check
|
||||
element = $(e.target).closest('form').get(0)
|
||||
if element && element.reportValidity && !element.reportValidity()
|
||||
return false
|
||||
|
||||
# validate
|
||||
errors = object.validate()
|
||||
if errors
|
||||
@log 'error', errors
|
||||
@formValidate( form: e.target, errors: errors )
|
||||
return false
|
||||
|
||||
# disable form
|
||||
@formDisable(e)
|
||||
|
||||
# save object
|
||||
ui = @
|
||||
object.save(
|
||||
done: ->
|
||||
if ui.callback
|
||||
item = App[ ui.genericObject ].fullLocal(@id)
|
||||
ui.callback(item)
|
||||
ui.close()
|
||||
|
||||
fail: (settings, details) ->
|
||||
ui.log 'errors', details
|
||||
ui.formEnable(e)
|
||||
ui.controller.showAlert(details.error_human || details.error || 'Unable to create object!')
|
||||
)
|
|
@ -0,0 +1,48 @@
|
|||
class App.ControllerModalLoading extends App.Controller
|
||||
className: 'modal fade'
|
||||
showTrySupport: true
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
if @container
|
||||
@el.addClass('modal--local')
|
||||
|
||||
@render()
|
||||
|
||||
@el.modal(
|
||||
keyboard: false
|
||||
show: true
|
||||
backdrop: 'static'
|
||||
container: @container
|
||||
).on(
|
||||
'hidden.bs.modal': @localOnClosed
|
||||
)
|
||||
|
||||
render: ->
|
||||
@html App.view('generic/modal_loader')(
|
||||
head: @head
|
||||
message: App.i18n.translateContent(@message)
|
||||
)
|
||||
|
||||
update: (message, translate = true) =>
|
||||
if translate
|
||||
message = App.i18n.translateContent(message)
|
||||
@$('.js-loading').html(message)
|
||||
|
||||
hideIcon: =>
|
||||
@$('.js-loadingIcon').addClass('hide')
|
||||
|
||||
showIcon: =>
|
||||
@$('.js-loadingIcon').removeClass('hide')
|
||||
|
||||
localOnClosed: =>
|
||||
@el.remove()
|
||||
|
||||
hide: (delay) =>
|
||||
remove = =>
|
||||
@el.modal('hide')
|
||||
if !delay
|
||||
remove()
|
||||
return
|
||||
App.Delay.set(remove, delay * 1000)
|
|
@ -0,0 +1,135 @@
|
|||
class App.ControllerNavSidbar extends App.Controller
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
if @authenticateRequired
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
@render(true)
|
||||
|
||||
@controllerBind('ui:rerender',
|
||||
=>
|
||||
@render(true)
|
||||
@updateNavigation(true, params)
|
||||
)
|
||||
|
||||
show: (params = {}) =>
|
||||
@navupdate ''
|
||||
@shown = true
|
||||
if params
|
||||
for key, value of params
|
||||
if key isnt 'el' && key isnt 'shown' && key isnt 'match'
|
||||
@[key] = value
|
||||
@updateNavigation(false, params)
|
||||
if @activeController && _.isFunction(@activeController.show)
|
||||
@activeController.show(params)
|
||||
|
||||
hide: =>
|
||||
@shown = false
|
||||
if @activeController && _.isFunction(@activeController.hide)
|
||||
@activeController.hide()
|
||||
|
||||
render: (force = false) =>
|
||||
groups = @groupsSorted()
|
||||
selectedItem = @selectedItem(groups)
|
||||
|
||||
@html App.view('generic/navbar_level2/index')(
|
||||
className: @configKey
|
||||
)
|
||||
@$('.sidebar').html App.view('generic/navbar_level2/navbar')(
|
||||
groups: groups
|
||||
className: @configKey
|
||||
selectedItem: selectedItem
|
||||
)
|
||||
|
||||
updateNavigation: (force, params) =>
|
||||
groups = @groupsSorted()
|
||||
selectedItem = @selectedItem(groups)
|
||||
return if !selectedItem
|
||||
return if !force && @lastTarget && selectedItem.target is @lastTarget
|
||||
@lastTarget = selectedItem.target
|
||||
@$('.sidebar li').removeClass('active')
|
||||
@$(".sidebar li a[href=\"#{selectedItem.target}\"]").parent().addClass('active')
|
||||
|
||||
@executeController(selectedItem, params)
|
||||
|
||||
groupsSorted: =>
|
||||
|
||||
# get accessable groups
|
||||
groups = App.Config.get(@configKey)
|
||||
groupsUnsorted = []
|
||||
for key, item of groups
|
||||
if !item.controller
|
||||
if !item.permission
|
||||
groupsUnsorted.push item
|
||||
else
|
||||
match = false
|
||||
for permissionName in item.permission
|
||||
if !match && @permissionCheck(permissionName)
|
||||
match = true
|
||||
groupsUnsorted.push item
|
||||
_.sortBy(groupsUnsorted, (item) -> return item.prio)
|
||||
|
||||
selectedItem: (groups) =>
|
||||
|
||||
# get items of group
|
||||
for group in groups
|
||||
items = App.Config.get(@configKey)
|
||||
itemsUnsorted = []
|
||||
for key, item of items
|
||||
if item.parent is group.target
|
||||
if item.controller
|
||||
if !item.permission
|
||||
itemsUnsorted.push item
|
||||
else
|
||||
match = false
|
||||
for permissionName in item.permission
|
||||
if !match && @permissionCheck(permissionName)
|
||||
match = true
|
||||
itemsUnsorted.push item
|
||||
|
||||
group.items = _.sortBy(itemsUnsorted, (item) -> return item.prio)
|
||||
|
||||
# set active item
|
||||
selectedItem = undefined
|
||||
for group in groups
|
||||
if group.items
|
||||
for item in group.items
|
||||
if item.target.match("/#{@target}$")
|
||||
item.active = true
|
||||
selectedItem = item
|
||||
else
|
||||
item.active = false
|
||||
|
||||
if !selectedItem
|
||||
for group in groups
|
||||
break if selectedItem
|
||||
if group.items
|
||||
for item in group.items
|
||||
item.active = true
|
||||
selectedItem = item
|
||||
break
|
||||
|
||||
selectedItem
|
||||
|
||||
executeController: (selectedItem, params) =>
|
||||
|
||||
if @activeController
|
||||
@activeController.el.remove()
|
||||
@activeController = undefined
|
||||
|
||||
@$('.main').append('<div>')
|
||||
@activeController = new selectedItem.controller(_.extend(params, el: @$('.main div')))
|
||||
|
||||
setPosition: (position) =>
|
||||
return if @shown
|
||||
return if !position
|
||||
if position.main
|
||||
@$('.main').scrollTop(position.main)
|
||||
if position.sidebar
|
||||
@$('.sidebar').scrollTop(position.sidebar)
|
||||
|
||||
currentPosition: =>
|
||||
data =
|
||||
main: @$('.main').scrollTop()
|
||||
sidebar: @$('.sidebar').scrollTop()
|
|
@ -0,0 +1,82 @@
|
|||
class App.ControllerObserver extends App.Controller
|
||||
model: 'Ticket'
|
||||
template: 'tba'
|
||||
globalRerender: true
|
||||
|
||||
###
|
||||
observe:
|
||||
title: true
|
||||
|
||||
observeNot:
|
||||
title: true
|
||||
|
||||
###
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
#console.trace()
|
||||
@log 'debug', 'new', @object_id, @model
|
||||
|
||||
if App[@model].exists(@object_id)
|
||||
@maybeRender(App[@model].fullLocal(@object_id))
|
||||
else
|
||||
App[@model].full(@object_id, @maybeRender)
|
||||
|
||||
# rerender, e. g. on language change
|
||||
if @globalRerender
|
||||
@controllerBind('ui:rerender', =>
|
||||
@lastAttributres = undefined
|
||||
@maybeRender(App[@model].fullLocal(@object_id))
|
||||
)
|
||||
|
||||
subscribe: (object, typeOfChange) =>
|
||||
@maybeRender(object, typeOfChange)
|
||||
|
||||
maybeRender: (object, typeOfChange) =>
|
||||
if typeOfChange is 'remove'
|
||||
@release()
|
||||
@el.remove()
|
||||
return
|
||||
|
||||
@log 'debug', 'maybeRender', @object_id, object, @model
|
||||
|
||||
if !@subscribeId
|
||||
@subscribeId = object.subscribe(@subscribe)
|
||||
|
||||
# remember current attributes
|
||||
currentAttributes = {}
|
||||
if @observe
|
||||
for key, active of @observe
|
||||
if active
|
||||
currentAttributes[key] = object[key]
|
||||
if @observeNot
|
||||
for key, value of object
|
||||
if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
|
||||
currentAttributes[key] = value
|
||||
|
||||
if !@lastAttributres
|
||||
@lastAttributres = {}
|
||||
else
|
||||
diff = difference(currentAttributes, @lastAttributres)
|
||||
if _.isEmpty(diff)
|
||||
@log 'debug', 'maybeRender no diff, no rerender'
|
||||
return
|
||||
|
||||
@log 'debug', 'maybeRender.diff', diff, @observe, @model
|
||||
@lastAttributres = currentAttributes
|
||||
|
||||
@render(object, diff)
|
||||
|
||||
render: (object, diff) =>
|
||||
@log 'debug', 'render', @template, object, diff
|
||||
@html App.view(@template)(
|
||||
object: object
|
||||
)
|
||||
|
||||
if @renderPost
|
||||
@renderPost(object)
|
||||
|
||||
release: =>
|
||||
#console.trace()
|
||||
@log 'debug', 'release', @object_id, @model, @subscribeId
|
||||
App[@model].unsubscribe(@subscribeId)
|
|
@ -0,0 +1,20 @@
|
|||
class App.ControllerObserverActionRow extends App.ControllerObserver
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
render: (object) =>
|
||||
return if _.isEmpty(object)
|
||||
actions = @actions(object)
|
||||
@html App.view('generic/actions')(
|
||||
items: actions
|
||||
type: @type
|
||||
)
|
||||
|
||||
for item in actions
|
||||
do (item) =>
|
||||
@$("[data-type=\"#{item.name}\"]").on(
|
||||
'click'
|
||||
(e) ->
|
||||
e.preventDefault()
|
||||
item.callback(object)
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
class App.ControllerPermanent extends App.Controller
|
||||
constructor: ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission, true)
|
||||
super
|
|
@ -0,0 +1,16 @@
|
|||
class App.ControllerSubContent extends App.Controller
|
||||
constructor: ->
|
||||
if @requiredPermission
|
||||
@permissionCheckRedirect(@requiredPermission)
|
||||
|
||||
super
|
||||
|
||||
show: =>
|
||||
if @genericController && @genericController.show
|
||||
@genericController.show()
|
||||
return if !@header
|
||||
@title @header, true
|
||||
|
||||
hide: =>
|
||||
if @genericController && @genericController.hide
|
||||
@genericController.hide()
|
|
@ -0,0 +1,61 @@
|
|||
class App.ControllerTabs extends App.Controller
|
||||
events:
|
||||
'click .nav-tabs [data-toggle="tab"]': 'tabRemember'
|
||||
|
||||
constructor: (params) ->
|
||||
@originParams = params # remember params for sub-controller
|
||||
super(params)
|
||||
|
||||
# check authentication
|
||||
if @requiredPermission
|
||||
if !@permissionCheckRedirect(@requiredPermission)
|
||||
throw "No permission for #{@requiredPermission}"
|
||||
|
||||
show: =>
|
||||
return if !@controllerList
|
||||
for localeController in @controllerList
|
||||
if localeController && localeController.show
|
||||
localeController.show()
|
||||
|
||||
hide: =>
|
||||
return if !@controllerList
|
||||
for localeController in @controllerList
|
||||
if localeController && localeController.hide
|
||||
localeController.hide()
|
||||
|
||||
render: ->
|
||||
@html App.view('generic/tabs')(
|
||||
header: @header
|
||||
subHeader: @subHeader
|
||||
tabs: @tabs
|
||||
addTab: @addTab
|
||||
headerSwitchName: @headerSwitchName
|
||||
headerSwitchChecked: @headerSwitchChecked
|
||||
)
|
||||
|
||||
# insert content
|
||||
for tab in @tabs
|
||||
@$('.tab-content').append("<div class=\"tab-pane\" id=\"#{tab.target}\"></div>")
|
||||
if tab.controller
|
||||
params = tab.params || {}
|
||||
params.name = tab.name
|
||||
params.target = tab.target
|
||||
params.el = @$("##{tab.target}")
|
||||
@controllerList ||= []
|
||||
@controllerList.push new tab.controller(_.extend(@originParams, params))
|
||||
|
||||
# check if tabs need to be show / cant' use .tab(), because tabs are note shown (only one tab exists)
|
||||
if @tabs.length <= 1
|
||||
@$('.tab-pane').addClass('active')
|
||||
return
|
||||
|
||||
# set last or first tab to active
|
||||
@lastActiveTab = @Config.get('lastTab')
|
||||
if @lastActiveTab && @$(".nav-tabs li a[href='#{@lastActiveTab}']")[0]
|
||||
@$(".nav-tabs li a[href='#{@lastActiveTab}']").tab('show')
|
||||
else
|
||||
@$('.nav-tabs li:first a').tab('show')
|
||||
|
||||
tabRemember: (e) =>
|
||||
@lastActiveTab = $(e.target).attr('href')
|
||||
@Config.set('lastTab', @lastActiveTab)
|
|
@ -0,0 +1,52 @@
|
|||
class App.ControllerWizardModal extends App.ControllerFullPage
|
||||
className: 'modal fade'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@controllerBind('ui:rerender', =>
|
||||
@render()
|
||||
'wizard'
|
||||
)
|
||||
|
||||
goToSlide: (e) =>
|
||||
e.preventDefault()
|
||||
slide = $(e.target).data('slide')
|
||||
return if !slide
|
||||
@showSlide(slide)
|
||||
|
||||
showSlide: (name) =>
|
||||
@hideAlert(name)
|
||||
@$('.setup.wizard').addClass('hide')
|
||||
@$(".setup.wizard.#{name}").removeClass('hide')
|
||||
@$(".setup.wizard.#{name} input, .setup.wizard.#{name} select").first().focus()
|
||||
|
||||
showAlert: (screen, message) =>
|
||||
@$(".#{screen}").find('.alert').first().removeClass('hide').text(App.i18n.translatePlain(message))
|
||||
|
||||
hideAlert: (screen) =>
|
||||
@$(".#{screen}").find('.alert').first().addClass('hide')
|
||||
|
||||
disable: (e) =>
|
||||
@formDisable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', true)
|
||||
|
||||
enable: (e) =>
|
||||
@formEnable(e)
|
||||
@$('.wizard-controls .btn').attr('disabled', false)
|
||||
|
||||
hide: (e) =>
|
||||
e.preventDefault()
|
||||
@el.modal('hide')
|
||||
|
||||
showInvalidField: (screen, fields) =>
|
||||
@$(".#{screen}").find('.form-group').removeClass('has-error')
|
||||
return if !fields
|
||||
for field, type of fields
|
||||
if type
|
||||
@$(".#{screen}").find("[name=\"options::#{field}\"]").closest('.form-group').addClass('has-error')
|
||||
|
||||
render: ->
|
||||
# do nothing
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
class App.ControllerWizardFullScreen extends App.ControllerWizardModal
|
||||
forceRender: true
|
||||
className: 'getstarted'
|
||||
|
||||
# login check / get session user
|
||||
redirectToLogin: =>
|
||||
App.Auth.loginCheck()
|
||||
@el.remove()
|
||||
App.Plugin.init()
|
||||
@navigate '#', { removeEl: true }
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
class App.ChannelChat extends App.ControllerSubContent
|
||||
class ChannelChat extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_chat'
|
||||
header: 'Chat'
|
||||
events:
|
||||
|
@ -353,7 +353,7 @@ class App.ChannelChat extends App.ControllerSubContent
|
|||
@code.each (i, block) ->
|
||||
hljs.highlightBlock block
|
||||
|
||||
App.Config.set('Chat', { prio: 4000, name: 'Chat', parent: '#channels', target: '#channels/chat', controller: App.ChannelChat, permission: ['admin.channel_chat'] }, 'NavBarAdmin')
|
||||
App.Config.set('Chat', { prio: 4000, name: 'Chat', parent: '#channels', target: '#channels/chat', controller: ChannelChat, permission: ['admin.channel_chat'] }, 'NavBarAdmin')
|
||||
|
||||
class Topics extends App.Controller
|
||||
events:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class App.ChannelEmail extends App.ControllerTabs
|
||||
class ChannelEmail extends App.ControllerTabs
|
||||
requiredPermission: 'admin.channel_email'
|
||||
header: 'Email'
|
||||
constructor: ->
|
||||
|
@ -10,17 +10,17 @@ class App.ChannelEmail extends App.ControllerTabs
|
|||
{
|
||||
name: 'Accounts',
|
||||
target: 'c-account',
|
||||
controller: App.ChannelEmailAccountOverview,
|
||||
controller: ChannelEmailAccountOverview,
|
||||
},
|
||||
{
|
||||
name: 'Filter',
|
||||
target: 'c-filter',
|
||||
controller: App.ChannelEmailFilter,
|
||||
controller: ChannelEmailFilter,
|
||||
},
|
||||
{
|
||||
name: 'Signatures',
|
||||
target: 'c-signature',
|
||||
controller: App.ChannelEmailSignature,
|
||||
controller: ChannelEmailSignature,
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
|
@ -32,7 +32,7 @@ class App.ChannelEmail extends App.ControllerTabs
|
|||
|
||||
@render()
|
||||
|
||||
class App.ChannelEmailFilter extends App.Controller
|
||||
class ChannelEmailFilter extends App.Controller
|
||||
events:
|
||||
'click [data-type=new]': 'new'
|
||||
|
||||
|
@ -79,7 +79,7 @@ class App.ChannelEmailFilter extends App.Controller
|
|||
callback: @load
|
||||
)
|
||||
|
||||
class App.ChannelEmailSignature extends App.Controller
|
||||
class ChannelEmailSignature extends App.Controller
|
||||
events:
|
||||
'click [data-type=new]': 'new'
|
||||
|
||||
|
@ -111,19 +111,19 @@ Once you have created a signature here, you need also to edit the groups where y
|
|||
|
||||
new: (e) =>
|
||||
e.preventDefault()
|
||||
new App.ChannelEmailSignatureEdit(
|
||||
new ChannelEmailSignatureEdit(
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
edit: (id, e) =>
|
||||
e.preventDefault()
|
||||
item = App.Signature.find(id)
|
||||
new App.ChannelEmailSignatureEdit(
|
||||
new ChannelEmailSignatureEdit(
|
||||
object: item
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
class App.ChannelEmailSignatureEdit extends App.ControllerModal
|
||||
class ChannelEmailSignatureEdit extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: true
|
||||
|
@ -174,7 +174,7 @@ class App.ChannelEmailSignatureEdit extends App.ControllerModal
|
|||
@form.showAlert(details.error_human || details.error || 'Unable to create object!')
|
||||
)
|
||||
|
||||
class App.ChannelEmailAccountOverview extends App.Controller
|
||||
class ChannelEmailAccountOverview extends App.Controller
|
||||
events:
|
||||
'click .js-channelNew': 'wizard'
|
||||
'click .js-channelDelete': 'delete'
|
||||
|
@ -248,7 +248,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
|||
|
||||
wizard: (e) =>
|
||||
e.preventDefault()
|
||||
new App.ChannelEmailAccountWizard(
|
||||
new ChannelEmailAccountWizard(
|
||||
container: @el.closest('.content')
|
||||
callback: @load
|
||||
channelDriver: @channelDriver
|
||||
|
@ -259,7 +259,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
|||
id = $(e.target).closest('.action').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
slide = 'js-inbound'
|
||||
new App.ChannelEmailAccountWizard(
|
||||
new ChannelEmailAccountWizard(
|
||||
container: @el.closest('.content')
|
||||
slide: slide
|
||||
channel: channel
|
||||
|
@ -272,7 +272,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
|||
id = $(e.target).closest('.action').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
slide = 'js-outbound'
|
||||
new App.ChannelEmailAccountWizard(
|
||||
new ChannelEmailAccountWizard(
|
||||
container: @el.closest('.content')
|
||||
slide: slide
|
||||
channel: channel
|
||||
|
@ -328,7 +328,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
|||
e.preventDefault()
|
||||
id = $(e.target).closest('.action').data('id')
|
||||
item = App.Channel.find(id)
|
||||
new App.ChannelEmailEdit(
|
||||
new ChannelEmailEdit(
|
||||
container: @el.closest('.content')
|
||||
item: item
|
||||
callback: @load
|
||||
|
@ -374,7 +374,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
|||
id = $(e.target).closest('.action').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
slide = 'js-outbound'
|
||||
new App.ChannelEmailNotificationWizard(
|
||||
new ChannelEmailNotificationWizard(
|
||||
container: @el.closest('.content')
|
||||
channel: channel
|
||||
callback: @load
|
||||
|
@ -391,7 +391,8 @@ class App.ChannelEmailAccountOverview extends App.Controller
|
|||
id = $(e.target).closest('.action').data('id')
|
||||
@navigate "#channels/microsoft365/#{id}"
|
||||
|
||||
class App.ChannelEmailEdit extends App.ControllerModal
|
||||
|
||||
class ChannelEmailEdit extends App.ControllerModal
|
||||
buttonClose: true
|
||||
buttonCancel: true
|
||||
buttonSubmit: true
|
||||
|
@ -442,7 +443,7 @@ class App.ChannelEmailEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||
)
|
||||
|
||||
class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||
class ChannelEmailAccountWizard extends App.ControllerWizardModal
|
||||
elements:
|
||||
'.modal-body': 'body'
|
||||
events:
|
||||
|
@ -896,7 +897,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
|||
e.preventDefault()
|
||||
@el.modal('hide')
|
||||
|
||||
class App.ChannelEmailNotificationWizard extends App.WizardModal
|
||||
class ChannelEmailNotificationWizard extends App.ControllerWizardModal
|
||||
elements:
|
||||
'.modal-body': 'body'
|
||||
events:
|
||||
|
@ -1030,4 +1031,4 @@ class App.ChannelEmailNotificationWizard extends App.WizardModal
|
|||
@enable(e)
|
||||
)
|
||||
|
||||
App.Config.set('Email', { prio: 3000, name: 'Email', parent: '#channels', target: '#channels/email', controller: App.ChannelEmail, permission: ['admin.channel_email'] }, 'NavBarAdmin')
|
||||
App.Config.set('Email', { prio: 3000, name: 'Email', parent: '#channels', target: '#channels/email', controller: ChannelEmail, permission: ['admin.channel_email'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ChannelFacebook extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_facebook'
|
||||
header: 'Facebook'
|
||||
events:
|
||||
|
@ -254,4 +254,4 @@ class AccountEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||
)
|
||||
|
||||
App.Config.set('Facebook', { prio: 5100, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: Index, permission: ['admin.channel_facebook'] }, 'NavBarAdmin')
|
||||
App.Config.set('Facebook', { prio: 5100, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: ChannelFacebook, permission: ['admin.channel_facebook'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# coffeelint: disable=no_unnecessary_double_quotes
|
||||
class App.ChannelForm extends App.ControllerSubContent
|
||||
class ChannelForm extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_formular'
|
||||
header: 'Form'
|
||||
events:
|
||||
|
@ -88,4 +88,4 @@ class App.ChannelForm extends App.ControllerSubContent
|
|||
value = @paramsSetting.find('[name=group_id]').val()
|
||||
App.Setting.set('form_ticket_create_group_id', value)
|
||||
|
||||
App.Config.set('Form', { prio: 2000, name: 'Form', parent: '#channels', target: '#channels/form', controller: App.ChannelForm, permission: ['admin.formular'] }, 'NavBarAdmin')
|
||||
App.Config.set('Form', { prio: 2000, name: 'Form', parent: '#channels', target: '#channels/form', controller: ChannelForm, permission: ['admin.formular'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class App.ChannelSms extends App.ControllerTabs
|
||||
class ChannelSms extends App.ControllerTabs
|
||||
requiredPermission: 'admin.channel_sms'
|
||||
header: 'SMS'
|
||||
constructor: ->
|
||||
|
@ -9,13 +9,13 @@ class App.ChannelSms extends App.ControllerTabs
|
|||
{
|
||||
name: 'Accounts',
|
||||
target: 'c-account',
|
||||
controller: App.ChannelSmsAccountOverview,
|
||||
controller: ChannelSmsAccountOverview,
|
||||
},
|
||||
]
|
||||
|
||||
@render()
|
||||
|
||||
class App.ChannelSmsAccountOverview extends App.Controller
|
||||
class ChannelSmsAccountOverview extends App.Controller
|
||||
events:
|
||||
'click .js-channelEdit': 'change'
|
||||
'click .js-channelDelete': 'delete'
|
||||
|
@ -76,7 +76,7 @@ class App.ChannelSmsAccountOverview extends App.Controller
|
|||
channel = new App.Channel(active: true)
|
||||
else
|
||||
channel = App.Channel.find(id)
|
||||
new App.ChannelSmsAccount(
|
||||
new ChannelSmsAccount(
|
||||
container: @el.closest('.content')
|
||||
channel: channel
|
||||
callback: @load
|
||||
|
@ -127,7 +127,7 @@ class App.ChannelSmsAccountOverview extends App.Controller
|
|||
e.preventDefault()
|
||||
id = $(e.target).closest('.action').data('id')
|
||||
channel = App.Channel.find(id)
|
||||
new App.ChannelSmsNotification(
|
||||
new ChannelSmsNotification(
|
||||
container: @el.closest('.content')
|
||||
channel: channel
|
||||
callback: @load
|
||||
|
@ -135,7 +135,7 @@ class App.ChannelSmsAccountOverview extends App.Controller
|
|||
config: @config
|
||||
)
|
||||
|
||||
class App.ChannelSmsAccount extends App.ControllerModal
|
||||
class ChannelSmsAccount extends App.ControllerModal
|
||||
head: 'SMS Account'
|
||||
buttonCancel: true
|
||||
centerButtons: [
|
||||
|
@ -272,7 +272,7 @@ class App.ChannelSmsAccount extends App.ControllerModal
|
|||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
class App.ChannelSmsNotification extends App.ControllerModal
|
||||
class ChannelSmsNotification extends App.ControllerModal
|
||||
head: 'SMS Notification'
|
||||
buttonCancel: true
|
||||
centerButtons: [
|
||||
|
@ -439,4 +439,4 @@ class TestModal extends App.ControllerModal
|
|||
.removeClass('hide')
|
||||
)
|
||||
|
||||
App.Config.set('SMS', { prio: 3100, name: 'SMS', parent: '#channels', target: '#channels/sms', controller: App.ChannelSms, permission: ['admin.channel_sms'] }, 'NavBarAdmin')
|
||||
App.Config.set('SMS', { prio: 3100, name: 'SMS', parent: '#channels', target: '#channels/sms', controller: ChannelSms, permission: ['admin.channel_sms'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ChannelTelegram extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_telegram'
|
||||
events:
|
||||
'click .js-new': 'new'
|
||||
|
@ -201,4 +201,4 @@ class BotEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(error_message)
|
||||
)
|
||||
|
||||
App.Config.set('Telegram', { prio: 5100, name: 'Telegram', parent: '#channels', target: '#channels/telegram', controller: Index, permission: ['admin.channel_telegram'] }, 'NavBarAdmin')
|
||||
App.Config.set('Telegram', { prio: 5100, name: 'Telegram', parent: '#channels', target: '#channels/telegram', controller: ChannelTelegram, permission: ['admin.channel_telegram'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ChannelTwitter extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_twitter'
|
||||
events:
|
||||
'click .js-new': 'new'
|
||||
|
@ -299,4 +299,4 @@ class AccountEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to save changes.')
|
||||
)
|
||||
|
||||
App.Config.set('Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: Index, permission: ['admin.channel_twitter'] }, 'NavBarAdmin')
|
||||
App.Config.set('Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: ChannelTwitter, permission: ['admin.channel_twitter'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class App.ChannelWeb extends App.ControllerTabs
|
||||
class ChannelWeb extends App.ControllerTabs
|
||||
requiredPermission: 'admin.channel_web'
|
||||
header: 'Web'
|
||||
constructor: ->
|
||||
|
@ -16,4 +16,4 @@ class App.ChannelWeb extends App.ControllerTabs
|
|||
|
||||
@render()
|
||||
|
||||
App.Config.set('Web', { prio: 1000, name: 'Web', parent: '#channels', target: '#channels/web', controller: App.ChannelWeb, permission: ['admin.channel_web'] }, 'NavBarAdmin')
|
||||
App.Config.set('Web', { prio: 1000, name: 'Web', parent: '#channels', target: '#channels/web', controller: ChannelWeb, permission: ['admin.channel_web'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -13,7 +13,7 @@ class App.DashboardActivityStream extends App.CollectionController
|
|||
@fetch()
|
||||
|
||||
# bind to rebuild view event
|
||||
@bind('activity_stream_rebuild', @load)
|
||||
@controllerBind('activity_stream_rebuild', @load)
|
||||
|
||||
fetch: =>
|
||||
|
||||
|
|
|
@ -54,8 +54,9 @@ class App.FirstStepsClues extends App.Controller
|
|||
|
||||
constructor: (params) ->
|
||||
|
||||
$('#app').append('<div class="js-modal--clue"></div>')
|
||||
params.el = $('#app .js-modal--clue')
|
||||
el = $('<div class="js-modal--clue"></div>')
|
||||
params.appEl.append(el)
|
||||
params.el = el
|
||||
|
||||
super params
|
||||
|
||||
|
@ -69,7 +70,7 @@ class App.FirstStepsClues extends App.Controller
|
|||
@position = 0
|
||||
@render()
|
||||
|
||||
@bind('ui:rerender', =>
|
||||
@controllerBind('ui:rerender', =>
|
||||
@render()
|
||||
'clues'
|
||||
)
|
||||
|
@ -106,7 +107,7 @@ class App.FirstStepsClues extends App.Controller
|
|||
cleanUp: (callback) ->
|
||||
@hideWindow =>
|
||||
clue = @clues[@position]
|
||||
container = $("#app #{clue.container}")
|
||||
container = @appEl.find(clue.container)
|
||||
container.removeClass('selected-clue')
|
||||
|
||||
# undo click perform by doing it again
|
||||
|
@ -128,7 +129,7 @@ class App.FirstStepsClues extends App.Controller
|
|||
|
||||
showClue: =>
|
||||
clue = @clues[@position]
|
||||
container = $("#app #{clue.container}")
|
||||
container = @appEl.find(clue.container)
|
||||
container.addClass('selected-clue')
|
||||
|
||||
if clue.actions
|
||||
|
@ -324,7 +325,7 @@ class App.FirstStepsClues extends App.Controller
|
|||
when 'hover'
|
||||
|
||||
# disable active navbar elements
|
||||
$('#app .navigation .is-active').removeClass('is-active')
|
||||
@appEl.find('.navigation .is-active').removeClass('is-active')
|
||||
|
||||
if type is 'show'
|
||||
target.addClass('is-hovered')
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
class App.DashboardStats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
@bind('dashboard_stats_rebuild', @load)
|
||||
@setupStatsWidgets()
|
||||
@controllerBind('dashboard_stats_rebuild', @setupStatsWidgets)
|
||||
|
||||
load: =>
|
||||
setupStatsWidgets: =>
|
||||
@setupStatsWidget('Stats', 'stats', @el)
|
||||
|
||||
setupStatsWidget: (config, event, el) ->
|
||||
|
@ -20,11 +20,11 @@ class App.DashboardStats extends App.Controller
|
|||
if @permissionCheck(widget.permission)
|
||||
try
|
||||
new widget.controller(
|
||||
el: el
|
||||
parentEl: @el
|
||||
className: widget.className
|
||||
)
|
||||
@$('.js-stat-help').tooltip()
|
||||
catch e
|
||||
@log 'error', "statsWidgets #{widget}:", e
|
||||
|
||||
|
||||
App.Event.trigger(event + ':ready')
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
class App.ControllerDashboardStatsBase extends App.Controller
|
||||
constructor: (params) ->
|
||||
if params.parentEl
|
||||
el = params.parentEl.find(".column.#{params.className}")
|
||||
if !el.get(0)
|
||||
el = $("<div class=\"column #{params.className}\"></div>")
|
||||
params.parentEl.append(el)
|
||||
params.el = el
|
||||
super(params)
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
|
@ -1,15 +1,4 @@
|
|||
class Stats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
||||
|
||||
class Stats extends App.ControllerDashboardStatsBase
|
||||
render: (data = {}) ->
|
||||
if !data.StatsTicketChannelDistribution
|
||||
data.StatsTicketChannelDistribution =
|
||||
|
@ -44,4 +33,4 @@ class Stats extends App.Controller
|
|||
else
|
||||
@el.append(content)
|
||||
|
||||
App.Config.set('ticket_channel_distribution', {controller: Stats, permission: 'ticket.agent', prio: 300 }, 'Stats')
|
||||
App.Config.set('ticket_channel_distribution', { controller: Stats, permission: 'ticket.agent', prio: 300, className: 'ticket_channel_distribution' }, 'Stats')
|
||||
|
|
|
@ -1,15 +1,4 @@
|
|||
class Stats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
||||
|
||||
class Stats extends App.ControllerDashboardStatsBase
|
||||
render: (data = {}) ->
|
||||
if !data.StatsTicketEscalation
|
||||
data.StatsTicketEscalation =
|
||||
|
@ -26,4 +15,4 @@ class Stats extends App.Controller
|
|||
else
|
||||
@el.append(content)
|
||||
|
||||
App.Config.set('ticket_escalation', {controller: Stats, permission: 'ticket.agent', prio: 200 }, 'Stats')
|
||||
App.Config.set('ticket_escalation', { controller: Stats, permission: 'ticket.agent', prio: 200, className: 'ticket_escalation' }, 'Stats')
|
||||
|
|
|
@ -1,20 +1,10 @@
|
|||
class Stats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
||||
|
||||
class Stats extends App.ControllerDashboardStatsBase
|
||||
render: (data = {}) ->
|
||||
if !data.StatsTicketInProcess
|
||||
data.StatsTicketInProcess =
|
||||
state: 'supergood'
|
||||
percent: 0
|
||||
in_process: 0
|
||||
average_per_agent: 0
|
||||
|
||||
data.StatsTicketInProcess.description = 'What percentage of your tickets have you responded to, updated, or modified in some way today?'
|
||||
|
@ -26,5 +16,4 @@ class Stats extends App.Controller
|
|||
else
|
||||
@el.append(content)
|
||||
|
||||
|
||||
App.Config.set('ticket_in_process', {controller: Stats, permission: 'ticket.agent', prio: 500 }, 'Stats')
|
||||
App.Config.set('ticket_in_process', { controller: Stats, permission: 'ticket.agent', prio: 500, className: 'ticket_in_process' }, 'Stats')
|
||||
|
|
|
@ -1,15 +1,4 @@
|
|||
class Stats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
||||
|
||||
class Stats extends App.ControllerDashboardStatsBase
|
||||
render: (data = {}) ->
|
||||
if !data.StatsTicketLoadMeasure
|
||||
data.StatsTicketLoadMeasure =
|
||||
|
@ -28,4 +17,4 @@ class Stats extends App.Controller
|
|||
else
|
||||
@el.append(content)
|
||||
|
||||
App.Config.set('ticket_load_measure', {controller: Stats, permission: 'ticket.agent', prio: 400 }, 'Stats')
|
||||
App.Config.set('ticket_load_measure', { controller: Stats, permission: 'ticket.agent', prio: 400, className: 'ticket_load_measure' }, 'Stats')
|
||||
|
|
|
@ -1,15 +1,4 @@
|
|||
class Stats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
||||
|
||||
class Stats extends App.ControllerDashboardStatsBase
|
||||
render: (data = {}) ->
|
||||
if !data.StatsTicketReopen
|
||||
data.StatsTicketReopen =
|
||||
|
@ -25,4 +14,4 @@ class Stats extends App.Controller
|
|||
else
|
||||
@el.append(content)
|
||||
|
||||
App.Config.set('ticket_reopen', {controller: Stats, permission: 'ticket.agent', prio: 600 }, 'Stats')
|
||||
App.Config.set('ticket_reopen', { controller: Stats, permission: 'ticket.agent', prio: 600, className: 'ticket_reopen' }, 'Stats')
|
||||
|
|
|
@ -1,15 +1,4 @@
|
|||
class Stats extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@load()
|
||||
|
||||
load: =>
|
||||
stats_store = App.StatsStore.first()
|
||||
if stats_store
|
||||
@render(stats_store.data)
|
||||
else
|
||||
@render()
|
||||
|
||||
class Stats extends App.ControllerDashboardStatsBase
|
||||
render: (data = {}) ->
|
||||
if !data.StatsTicketWaitingTime
|
||||
data.StatsTicketWaitingTime =
|
||||
|
@ -75,4 +64,4 @@ class Stats extends App.Controller
|
|||
ctx.closePath()
|
||||
ctx.fill()
|
||||
|
||||
App.Config.set('ticket_waiting_time', {controller: Stats, permission: 'ticket.agent', prio: 100 }, 'Stats')
|
||||
App.Config.set('ticket_waiting_time', { controller: Stats, permission: 'ticket.agent', prio: 100, className: 'ticket_waiting_time' }, 'Stats')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class CheckMk extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'check_mk_integration'
|
||||
featureName: 'Checkmk'
|
||||
featureConfig: 'check_mk_config'
|
||||
|
@ -55,7 +55,7 @@ App.Config.set(
|
|||
name: 'Checkmk'
|
||||
target: '#system/integration/check_mk'
|
||||
description: 'An open source monitoring tool.'
|
||||
controller: Index
|
||||
controller: CheckMk
|
||||
state: State
|
||||
permission: ['admin.integration.check_mk']
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Clearbit extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'clearbit_integration'
|
||||
featureName: 'Clearbit'
|
||||
featureConfig: 'clearbit_config'
|
||||
|
@ -155,7 +155,7 @@ App.Config.set(
|
|||
name: 'Clearbit'
|
||||
target: '#system/integration/clearbit'
|
||||
description: 'A powerful service to get more information about your customers.'
|
||||
controller: Index
|
||||
controller: Clearbit
|
||||
state: State
|
||||
permission: ['admin.integration.clearbit']
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Cti extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'cti_integration'
|
||||
featureName: 'CTI (generic)'
|
||||
featureConfig: 'cti_config'
|
||||
|
@ -234,7 +234,7 @@ App.Config.set(
|
|||
name: 'CTI (generic)'
|
||||
target: '#system/integration/cti'
|
||||
description: 'Generic API to integrate VoIP service provider with realtime push.'
|
||||
controller: Index
|
||||
controller: Cti
|
||||
state: State
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Exchange extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'exchange_integration'
|
||||
featureName: 'Exchange'
|
||||
featureConfig: 'exchange_config'
|
||||
|
@ -166,7 +166,7 @@ class State
|
|||
@current: ->
|
||||
App.Setting.get('exchange_integration')
|
||||
|
||||
class ConnectionWizard extends App.WizardModal
|
||||
class ConnectionWizard extends App.ControllerWizardModal
|
||||
wizardConfig: {}
|
||||
slideMethod:
|
||||
'js-folders': 'foldersShow'
|
||||
|
@ -557,7 +557,7 @@ App.Config.set(
|
|||
name: 'Exchange'
|
||||
target: '#system/integration/exchange'
|
||||
description: 'Exchange integration for contacts management.'
|
||||
controller: Index
|
||||
controller: Exchange
|
||||
state: State
|
||||
permission: ['admin.integration.exchange']
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Icinga extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'icinga_integration'
|
||||
featureName: 'Icinga'
|
||||
featureConfig: 'icinga_config'
|
||||
|
@ -24,7 +24,7 @@ App.Config.set(
|
|||
name: 'Icinga'
|
||||
target: '#system/integration/icinga'
|
||||
description: 'An open source monitoring tool.'
|
||||
controller: Index
|
||||
controller: Icinga
|
||||
state: State
|
||||
permission: ['admin.integration.icinga']
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Idoit extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'idoit_integration'
|
||||
featureName: 'i-doit'
|
||||
featureConfig: 'idoit_config'
|
||||
|
@ -58,7 +58,7 @@ class Form extends App.Controller
|
|||
)
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'failed'
|
||||
new App.ControllerErrorModal(
|
||||
new App.ErrorModal(
|
||||
message: data.message
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
@ -87,7 +87,7 @@ App.Config.set(
|
|||
name: 'i-doit'
|
||||
target: '#system/integration/idoit'
|
||||
description: 'CMDB to document complex relations of your network components.'
|
||||
controller: Index
|
||||
controller: Idoit
|
||||
state: State
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Ldap extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'ldap_integration'
|
||||
featureName: 'LDAP'
|
||||
featureConfig: 'ldap_config'
|
||||
|
@ -71,6 +71,7 @@ class Form extends App.Controller
|
|||
group_role_map = {}
|
||||
for source, dests of @config.group_role_map
|
||||
group_role_map[source] = dests.map((dest) ->
|
||||
return '?' if !App.Role.exists(dest)
|
||||
App.Role.find(dest).displayName()
|
||||
).join ', '
|
||||
|
||||
|
@ -135,8 +136,9 @@ class Form extends App.Controller
|
|||
if !job.result.roles
|
||||
job.result.roles = {}
|
||||
for role_id, statistic of job.result.role_ids
|
||||
role = App.Role.find(role_id)
|
||||
job.result.roles[role.displayName()] = statistic
|
||||
if App.Role.exists(role_id)
|
||||
role = App.Role.find(role_id)
|
||||
job.result.roles[role.displayName()] = statistic
|
||||
el = $(App.view('integration/ldap_last_import')(job: job))
|
||||
@lastImport.html(el)
|
||||
|
||||
|
@ -167,9 +169,7 @@ class State
|
|||
@current: ->
|
||||
App.Setting.get('ldap_integration')
|
||||
|
||||
class ConnectionWizard extends App.WizardModal
|
||||
className: 'modal fade modal--large'
|
||||
|
||||
class ConnectionWizard extends App.ControllerWizardModal
|
||||
wizardConfig: {}
|
||||
slideMethod:
|
||||
'js-bind': 'bindShow'
|
||||
|
@ -562,8 +562,9 @@ class ConnectionWizard extends App.WizardModal
|
|||
if !job.result.roles
|
||||
job.result.roles = {}
|
||||
for role_id, statistic of job.result.role_ids
|
||||
role = App.Role.find(role_id)
|
||||
job.result.roles[role.displayName()] = statistic
|
||||
if App.Role.find(role_id)
|
||||
role = App.Role.find(role_id)
|
||||
job.result.roles[role.displayName()] = statistic
|
||||
@showSlide('js-try')
|
||||
el = $(App.view('integration/ldap_summary')(job: job))
|
||||
@el.find('.js-summary').html(el)
|
||||
|
@ -574,7 +575,7 @@ App.Config.set(
|
|||
name: 'LDAP'
|
||||
target: '#system/integration/ldap'
|
||||
description: 'LDAP integration for user management.'
|
||||
controller: Index
|
||||
controller: Ldap
|
||||
state: State
|
||||
permission: ['admin.integration.ldap']
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Monit extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'monit_integration'
|
||||
featureName: 'Monit'
|
||||
featureConfig: 'monit_config'
|
||||
|
@ -24,7 +24,7 @@ App.Config.set(
|
|||
name: 'Monit'
|
||||
target: '#system/integration/monit'
|
||||
description: 'An open source monitoring tool.'
|
||||
controller: Index
|
||||
controller: Monit
|
||||
state: State
|
||||
permission: ['admin.integration.monit']
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Nagios extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'nagios_integration'
|
||||
featureName: 'Nagios'
|
||||
featureConfig: 'nagios_config'
|
||||
|
@ -24,7 +24,7 @@ App.Config.set(
|
|||
name: 'Nagios'
|
||||
target: '#system/integration/nagios'
|
||||
description: 'An open source monitoring tool.'
|
||||
controller: Index
|
||||
controller: Nagios
|
||||
state: State
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Placetel extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'placetel_integration'
|
||||
featureName: 'Placetel'
|
||||
featureConfig: 'placetel_config'
|
||||
|
@ -188,7 +188,7 @@ App.Config.set(
|
|||
name: 'Placetel'
|
||||
target: '#system/integration/placetel'
|
||||
description: 'VoIP service provider with realtime push.'
|
||||
controller: Index
|
||||
controller: Placetel
|
||||
state: State
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class SipgateIo extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'sipgate_integration'
|
||||
featureName: 'sipgate.io'
|
||||
featureConfig: 'sipgate_config'
|
||||
|
@ -188,7 +188,7 @@ App.Config.set(
|
|||
name: 'sipgate.io'
|
||||
target: '#system/integration/sipgate'
|
||||
description: 'VoIP service provider with realtime push.'
|
||||
controller: Index
|
||||
controller: SipgateIo
|
||||
state: State
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerIntegrationBase
|
||||
class Slack extends App.ControllerIntegrationBase
|
||||
featureIntegration: 'slack_integration'
|
||||
featureName: 'Slack'
|
||||
featureConfig: 'slack_config'
|
||||
|
@ -85,7 +85,7 @@ App.Config.set(
|
|||
target: '#system/integration/slack'
|
||||
description: 'A team communication tool for the 21st century. Compatible with tools like %s.'
|
||||
descriptionSubstitute: 'Mattermost, RocketChat'
|
||||
controller: Index
|
||||
controller: Slack
|
||||
state: State
|
||||
}
|
||||
'NavBarIntegrations'
|
||||
|
|
|
@ -99,11 +99,9 @@ class Certificate extends App.ControllerModal
|
|||
cache: false
|
||||
data: params
|
||||
success: (data, status, xhr) =>
|
||||
console.log('success')
|
||||
@close()
|
||||
@callback()
|
||||
error: (data) =>
|
||||
console.log('error')
|
||||
@close()
|
||||
details = data.responseJSON || {}
|
||||
@notify
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
class Widget extends App.Controller
|
||||
class AppConfigUpdate
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
App.Event.bind(
|
||||
'config_update'
|
||||
(data) ->
|
||||
|
@ -9,4 +7,7 @@ class Widget extends App.Controller
|
|||
App.Event.trigger('config_update_local', data)
|
||||
)
|
||||
|
||||
App.Config.set('app_config_update', Widget, 'Widgets')
|
||||
release: ->
|
||||
App.Event.unbind('config_update')
|
||||
|
||||
App.Config.set('app_config_update', AppConfigUpdate, 'Plugins')
|
|
@ -16,8 +16,8 @@ class DefaultLocale extends App.Controller
|
|||
processData: true
|
||||
)
|
||||
|
||||
App.Event.bind('auth:login', (session) =>
|
||||
@controllerBind('auth:login', (session) =>
|
||||
@delay(check, 3500, 'default_locale')
|
||||
)
|
||||
|
||||
App.Config.set('default_locale', DefaultLocale, 'Widgets')
|
||||
App.Config.set('default_locale', DefaultLocale, 'Plugins')
|
|
@ -26,11 +26,11 @@ class DefaultTimezone extends App.Controller
|
|||
# processData: true
|
||||
#)
|
||||
|
||||
App.Event.bind('auth:login', (session) =>
|
||||
@controllerBind('auth:login', (session) =>
|
||||
@delay(check, 8500, 'default_timezone')
|
||||
)
|
||||
|
||||
updateSetting: (timezone) ->
|
||||
App.Setting.set('timezone_default', timezone)
|
||||
|
||||
App.Config.set('default_timezone', DefaultTimezone, 'Widgets')
|
||||
App.Config.set('default_timezone', DefaultTimezone, 'Plugins')
|
|
@ -1,4 +1,4 @@
|
|||
class Widget
|
||||
class DevBanner
|
||||
constructor: ->
|
||||
return if !App.Config.get('developer_mode')
|
||||
return if App.Log.config('banner') is false
|
||||
|
@ -17,4 +17,4 @@ class Widget
|
|||
"""
|
||||
console.log(banner)
|
||||
|
||||
App.Config.set('dev_banner', Widget, 'Widgets')
|
||||
App.Config.set('dev_banner', DevBanner, 'Plugins')
|
|
@ -1,18 +1,19 @@
|
|||
class Widget
|
||||
class ElectronEvents extends App.Controller
|
||||
constructor: ->
|
||||
return if !window.require
|
||||
electron = window.require('electron')
|
||||
return if !electron
|
||||
remote = electron.remote
|
||||
ipc = electron.ipcRenderer
|
||||
super
|
||||
|
||||
App.Event.bind('window-title-set', (arg) ->
|
||||
@controllerBind('window-title-set', (arg) ->
|
||||
ipc.send('window-title-set', arg)
|
||||
)
|
||||
App.Event.bind('online_notification_counter', (e) ->
|
||||
@controllerBind('online_notification_counter', (e) ->
|
||||
setBadge(e)
|
||||
)
|
||||
ipc.on('global-shortcut', (e, arg) ->
|
||||
ipc.off('global-shortcut').on('global-shortcut', (e, arg) ->
|
||||
App.Event.trigger('global-shortcut', arg)
|
||||
)
|
||||
|
||||
|
@ -91,4 +92,4 @@ class Widget
|
|||
else if process.platform is 'darwin'
|
||||
setBadgeOSX(content)
|
||||
|
||||
App.Config.set('aaa_electron_events', Widget, 'Navigations')
|
||||
App.Config.set('aaa_electron_events', ElectronEvents, 'Plugins')
|
|
@ -1,12 +1,13 @@
|
|||
class App.GlobalSearchWidget extends Spine.Module
|
||||
class App.GlobalSearchWidget extends App.Controller
|
||||
shiftHeld = false
|
||||
|
||||
constructor: ->
|
||||
$('body').on('mousedown', (e) =>
|
||||
super
|
||||
$('body').off('mousedown.globalsearch').on('mousedown.globalsearch', (e) =>
|
||||
@shiftHeldToogle(e)
|
||||
true
|
||||
)
|
||||
App.Event.bind('global:search:set', (data) =>
|
||||
@controllerBind('global:search:set', (data) =>
|
||||
item = data[0]
|
||||
attribute = data[1]
|
||||
item = item.replace('"', '')
|
||||
|
@ -36,4 +37,4 @@ class App.GlobalSearchWidget extends Spine.Module
|
|||
@search: (item, attribute) ->
|
||||
App.Event.trigger('global:search:set', [item, attribute])
|
||||
|
||||
App.Config.set('global_navigation', App.GlobalSearchWidget, 'Widgets')
|
||||
App.Config.set('global_navigation', App.GlobalSearchWidget, 'Plugins')
|
|
@ -1,4 +1,4 @@
|
|||
class Widget
|
||||
class HelloBanner
|
||||
constructor: ->
|
||||
return if App.Config.get('developer_mode')
|
||||
banner = """
|
||||
|
@ -17,4 +17,4 @@ class Widget
|
|||
"""
|
||||
console.log(banner, 'text-decoration: underline;', 'text-decoration: none;')
|
||||
|
||||
App.Config.set('hello_banner', Widget, 'Widgets')
|
||||
App.Config.set('hello_banner', HelloBanner, 'Plugins')
|
|
@ -8,7 +8,7 @@ class App.KeyboardShortcutModal extends App.ControllerModal
|
|||
|
||||
constructor: ->
|
||||
super
|
||||
@bind('keyboard_shortcuts_close', @close)
|
||||
@controllerBind('keyboard_shortcuts_close', @close)
|
||||
|
||||
content: ->
|
||||
App.view('keyboard_shortcuts')(
|
||||
|
@ -25,10 +25,11 @@ class App.KeyboardShortcutModal extends App.ControllerModal
|
|||
return if window.location.hash isnt '#keyboard_shortcuts'
|
||||
window.history.back()
|
||||
|
||||
class App.KeyboardShortcutWidget extends Spine.Module
|
||||
class App.KeyboardShortcutWidget extends App.Controller
|
||||
@include App.LogInclude
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@observerKeys()
|
||||
@lastKey = undefined
|
||||
|
||||
|
@ -38,6 +39,7 @@ class App.KeyboardShortcutWidget extends Spine.Module
|
|||
)
|
||||
|
||||
observerKeys: =>
|
||||
$(document).unbind('keydown.shortcuts')
|
||||
navigationHotkeys = App.Browser.hotkeys()
|
||||
|
||||
areas = App.Config.get('keyboard_shortcuts')
|
||||
|
@ -54,7 +56,7 @@ class App.KeyboardShortcutWidget extends Spine.Module
|
|||
modifier += shortcut.key
|
||||
if shortcut.callback
|
||||
@log 'debug', 'bind for', modifier
|
||||
$(document).bind('keydown', modifier, (e) =>
|
||||
$(document).bind('keydown.shortcuts', modifier, (e) =>
|
||||
e.preventDefault()
|
||||
if @lastKey && @lastKey.modifier is modifier && @lastKey.time + 5500 > new Date().getTime()
|
||||
@lastKey.count += 1
|
||||
|
@ -67,7 +69,7 @@ class App.KeyboardShortcutWidget extends Spine.Module
|
|||
shortcut.callback(shortcut, @lastKey, modifier)
|
||||
)
|
||||
|
||||
App.Event.bind('global-shortcut', (e) ->
|
||||
@controllerBind('global-shortcut', (e) ->
|
||||
for area in areas
|
||||
for item in area.content
|
||||
for shortcut in item.shortcuts
|
||||
|
@ -75,7 +77,7 @@ class App.KeyboardShortcutWidget extends Spine.Module
|
|||
shortcut.callback(shortcut)
|
||||
)
|
||||
|
||||
App.Config.set('keyboard_shortcuts', App.KeyboardShortcutWidget, 'Widgets')
|
||||
App.Config.set('keyboard_shortcuts', App.KeyboardShortcutWidget, 'Plugins')
|
||||
App.Config.set(
|
||||
'keyboard_shortcuts',
|
||||
[
|
|
@ -1,9 +1,8 @@
|
|||
class Widget extends App.Controller
|
||||
class Maintenance extends App.Controller
|
||||
serverRestarted: false
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
App.Event.bind(
|
||||
@controllerBind(
|
||||
'maintenance'
|
||||
(data) =>
|
||||
if data.type is 'message'
|
||||
|
@ -18,7 +17,6 @@ class Widget extends App.Controller
|
|||
@maintanaceRestartAuto(data)
|
||||
if data.type is 'restart_manual'
|
||||
@maintanaceRestartManual(data)
|
||||
'maintenance'
|
||||
)
|
||||
|
||||
showMessage: (message = {}) =>
|
||||
|
@ -129,4 +127,4 @@ class Widget extends App.Controller
|
|||
timeout ?= 1000
|
||||
@delay(delay, timeout)
|
||||
|
||||
App.Config.set('maintenance', Widget, 'Widgets')
|
||||
App.Config.set('maintenance', Maintenance, 'Plugins')
|
|
@ -1,9 +1,7 @@
|
|||
class App.Navigation extends App.ControllerWidgetPermanent
|
||||
class Navigation extends App.Controller
|
||||
@extend App.PopoverProvidable
|
||||
@registerAllPopovers()
|
||||
|
||||
className: 'navigation vertical'
|
||||
|
||||
elements:
|
||||
'#global-search': 'searchInput'
|
||||
'.search': 'searchContainer'
|
||||
|
@ -33,36 +31,37 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
)
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@bind 'ui:rerender', =>
|
||||
@controllerBind('ui:rerender', =>
|
||||
@renderMenu()
|
||||
@renderPersonal()
|
||||
)
|
||||
|
||||
# rerender menu
|
||||
@bind 'menu:render', =>
|
||||
@controllerBind('menu:render', =>
|
||||
@renderMenu()
|
||||
)
|
||||
|
||||
# rerender menu
|
||||
@bind 'personal:render', =>
|
||||
@controllerBind('personal:render', =>
|
||||
@renderPersonal()
|
||||
)
|
||||
|
||||
# update selected item
|
||||
@bind 'navupdate', (params) =>
|
||||
@controllerBind('navupdate', (params) =>
|
||||
@update(params)
|
||||
|
||||
# rebuild nav bar with given user data
|
||||
@bind 'auth', (user) =>
|
||||
@render()
|
||||
)
|
||||
|
||||
# fetch new recent viewed after collection change
|
||||
@bind 'RecentView::changed', =>
|
||||
@controllerBind('RecentView::changed', =>
|
||||
@delay(
|
||||
=> @fetchRecentView()
|
||||
1000
|
||||
'recent-view-changed'
|
||||
)
|
||||
)
|
||||
|
||||
# bell on / bell off
|
||||
@bind 'bell', (data) =>
|
||||
@controllerBind('bell', (data) =>
|
||||
if data is 'on'
|
||||
@$('.bell').addClass('show')
|
||||
App.Audio.play( 'https://www.sounddogs.com/previews/2193/mp3/219024_SOUNDDOGS__be.mp3' )
|
||||
|
@ -72,6 +71,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
)
|
||||
else
|
||||
@$('.bell').removeClass('show')
|
||||
)
|
||||
|
||||
release: =>
|
||||
if @notificationWidget
|
||||
|
@ -187,13 +187,27 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
@renderPopovers()
|
||||
|
||||
render: ->
|
||||
|
||||
user = App.Session.get()
|
||||
@html App.view('navigation')(
|
||||
user: user
|
||||
)
|
||||
if _.isEmpty(user)
|
||||
@appEl.find('#navigation').remove()
|
||||
return
|
||||
|
||||
@taskbar = new App.TaskbarWidget( el: @$('.tasks') )
|
||||
navigation = $(App.view('navigation')(
|
||||
user: user
|
||||
))
|
||||
|
||||
@taskbar = new App.TaskbarWidget(el: navigation.find('.tasks'))
|
||||
|
||||
@el = navigation
|
||||
if !@appEl.find('#navigation').get(0)
|
||||
@appEl.prepend(navigation)
|
||||
@delegateEvents(@events)
|
||||
@refreshElements()
|
||||
@el.on('remove', @releaseController)
|
||||
@el.on('remove', @release)
|
||||
else
|
||||
@el = @appEl.find('#navigation')
|
||||
@html(navigation)
|
||||
|
||||
# renderMenu
|
||||
@renderMenu()
|
||||
|
@ -204,7 +218,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
if @notificationWidget
|
||||
@notificationWidget.remove()
|
||||
@notificationWidget = new App.OnlineNotificationWidget()
|
||||
$('#app').append @notificationWidget.el
|
||||
@appEl.append @notificationWidget.el
|
||||
|
||||
searchFocus: (e) =>
|
||||
@clearDelay('emptyAndCloseDelayed')
|
||||
|
@ -490,6 +504,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
App.RecentView.fetchFull(load, clear: true)
|
||||
|
||||
toggleNotifications: (e) ->
|
||||
console.log('toggleNotifications', @notificationWidget)
|
||||
e.stopPropagation()
|
||||
@notificationWidget.toggle()
|
||||
|
||||
|
@ -503,4 +518,4 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
return
|
||||
@navigate('#search')
|
||||
|
||||
App.Config.set('navigation', App.Navigation, 'Navigations')
|
||||
App.Config.set('aaa_navigation', Navigation, 'Plugins')
|
|
@ -1,4 +1,4 @@
|
|||
class App.Notify extends App.ControllerWidgetPermanent
|
||||
class App.Notify extends App.Controller
|
||||
desktopNotify: {}
|
||||
desktopNotifyCounter: 0
|
||||
|
||||
|
@ -8,14 +8,14 @@ class App.Notify extends App.ControllerWidgetPermanent
|
|||
constructor: ->
|
||||
super
|
||||
|
||||
@bind 'notify', (data) =>
|
||||
@controllerBind('notify', (data) =>
|
||||
@render(data)
|
||||
|
||||
@bind 'notify:removeall', =>
|
||||
)
|
||||
@controllerBind('notify:removeall', =>
|
||||
@log 'notify:removeall', @
|
||||
@destroyAll()
|
||||
|
||||
@bind 'notifyDesktop', (data) =>
|
||||
)
|
||||
@controllerBind('notifyDesktop', (data) =>
|
||||
return if !window.Notification
|
||||
|
||||
if !data['icon']
|
||||
|
@ -48,13 +48,14 @@ class App.Notify extends App.ControllerWidgetPermanent
|
|||
-> notification.close()
|
||||
data.timeout || timeout
|
||||
)
|
||||
)
|
||||
|
||||
# request desktop notification after login
|
||||
@bind 'auth', (data) ->
|
||||
@controllerBind('auth', (data) ->
|
||||
if !_.isEmpty(data)
|
||||
return if !window.Notification
|
||||
window.Notification.requestPermission()
|
||||
|
||||
)
|
||||
$(window).focus(
|
||||
=>
|
||||
for counter, notification of @desktopNotify
|
||||
|
@ -63,6 +64,9 @@ class App.Notify extends App.ControllerWidgetPermanent
|
|||
|
||||
render: (data) ->
|
||||
|
||||
if !$('#notify').get(0)
|
||||
$('body').append('<div id="notify"></div>')
|
||||
|
||||
# map noty naming
|
||||
if data['type'] is 'info'
|
||||
data['type'] = 'information'
|
||||
|
@ -73,7 +77,8 @@ class App.Notify extends App.ControllerWidgetPermanent
|
|||
$.noty.closeAll()
|
||||
if data.link
|
||||
data.msg = '<a href="' + data.link + '">' + data.msg + '</a>'
|
||||
$('#notify').noty
|
||||
|
||||
$('#notify').noty(
|
||||
text: data.msg
|
||||
type: data.type
|
||||
template: App.view('notify')
|
||||
|
@ -83,6 +88,7 @@ class App.Notify extends App.ControllerWidgetPermanent
|
|||
close: 'animated fadeOutDown'
|
||||
timeout: data.timeout || 3800
|
||||
closeWith: ['click']
|
||||
)
|
||||
|
||||
destroy: (e) ->
|
||||
e.preventDefault()
|
||||
|
@ -90,4 +96,4 @@ class App.Notify extends App.ControllerWidgetPermanent
|
|||
destroyAll: ->
|
||||
$.noty.closeAll()
|
||||
|
||||
App.Config.set('notify', App.Notify, 'Widgets')
|
||||
App.Config.set('notify', App.Notify, 'Plugins')
|
|
@ -1,4 +1,4 @@
|
|||
class Widget extends App.Controller
|
||||
class RemoteTask extends App.Controller
|
||||
serverRestarted: false
|
||||
constructor: ->
|
||||
super
|
||||
|
@ -12,4 +12,4 @@ class Widget extends App.Controller
|
|||
'remote_task'
|
||||
)
|
||||
|
||||
App.Config.set('remote_task', Widget, 'Widgets')
|
||||
App.Config.set('remote_task', RemoteTask, 'Plugins')
|
|
@ -1,12 +1,9 @@
|
|||
class Widget extends App.Controller
|
||||
class SessionTakeOver extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@bind()
|
||||
|
||||
bind: ->
|
||||
|
||||
# only do takeover check after spool messages are finished
|
||||
App.Event.bind(
|
||||
@controllerBind(
|
||||
'spool:sent'
|
||||
=>
|
||||
@spoolSent = true
|
||||
|
@ -22,11 +19,10 @@ class Widget extends App.Controller
|
|||
data:
|
||||
taskbar_id: App.TaskManager.TaskbarId()
|
||||
)
|
||||
'maintenance'
|
||||
)
|
||||
|
||||
# session take over message
|
||||
App.Event.bind(
|
||||
@controllerBind(
|
||||
'session:takeover'
|
||||
(data) =>
|
||||
|
||||
|
@ -48,7 +44,6 @@ class Widget extends App.Controller
|
|||
forceReload: true
|
||||
)
|
||||
@disconnectClient()
|
||||
'maintenance'
|
||||
)
|
||||
|
||||
App.Config.set('session_taken_over', Widget, 'Widgets')
|
||||
App.Config.set('session_taken_over', SessionTakeOver, 'Plugins')
|
|
@ -1,20 +1,24 @@
|
|||
class Widget extends App.ControllerWidgetOnDemand
|
||||
class SwitchBackToUser extends App.Controller
|
||||
className: 'switchBackToUser'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# start widget
|
||||
@bind 'app:ready', =>
|
||||
@controllerBind('app:ready', =>
|
||||
@render()
|
||||
)
|
||||
|
||||
# e.g. if language has changed
|
||||
@bind 'ui:rerender', =>
|
||||
@controllerBind('ui:rerender', =>
|
||||
@render()
|
||||
)
|
||||
|
||||
# remove widget
|
||||
@bind 'auth:logout', =>
|
||||
@controllerBind('auth:logout', =>
|
||||
App.Config.set('switch_back_to_possible', false)
|
||||
@render()
|
||||
)
|
||||
|
||||
render: (user) ->
|
||||
|
||||
|
@ -47,4 +51,14 @@ class Widget extends App.ControllerWidgetOnDemand
|
|||
800
|
||||
)
|
||||
|
||||
App.Config.set('switch_back_to_user', Widget, 'Widgets')
|
||||
element: =>
|
||||
$("##{@key}")
|
||||
|
||||
html: (raw) =>
|
||||
|
||||
# check if parent exists
|
||||
if !$("##{@key}").get(0)
|
||||
$('#app').before("<div id=\"#{@key}\" class=\"#{@className}\"></div>")
|
||||
$("##{@key}").html raw
|
||||
|
||||
App.Config.set('switch_back_to_user', SwitchBackToUser, 'Plugins')
|
|
@ -1,9 +1,9 @@
|
|||
class Widget extends App.Controller
|
||||
class TranslationInline extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@rebind()
|
||||
App.Event.bind('auth', => @rebind())
|
||||
App.Event.bind('i18n:inline_translation', => @toogle())
|
||||
@controllerBind('auth', => @rebind())
|
||||
@controllerBind('i18n:inline_translation', => @toogle())
|
||||
|
||||
rebind: =>
|
||||
$(document).off('keydown.translation')
|
||||
|
@ -130,4 +130,4 @@ class Widget extends App.Controller
|
|||
# rerender controllers
|
||||
App.Event.trigger('ui:rerender')
|
||||
|
||||
App.Config.set('translation_inline', Widget, 'Widgets')
|
||||
App.Config.set('translation_inline', TranslationInline, 'Plugins')
|
|
@ -24,13 +24,14 @@ class TranslationSupport extends App.Controller
|
|||
# show message
|
||||
new Modal(percent: percent)
|
||||
|
||||
@bind 'i18n:language:change', =>
|
||||
@controllerBind('i18n:language:change', =>
|
||||
@delay(check, 2500, 'translation_support')
|
||||
|
||||
@bind 'auth:login', =>
|
||||
)
|
||||
@controllerBind('auth:login', =>
|
||||
@delay(check, 2500, 'translation_support')
|
||||
)
|
||||
|
||||
App.Config.set( 'translaton_support', TranslationSupport, 'Widgets' )
|
||||
App.Config.set( 'translaton_support', TranslationSupport, 'Plugins' )
|
||||
|
||||
class Modal extends App.ControllerModal
|
||||
buttonClose: true
|
|
@ -0,0 +1,81 @@
|
|||
class UserSignupCheck extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# for browser test
|
||||
@controllerBind('user_signup_verify', (user) ->
|
||||
new Modal(user: user)
|
||||
)
|
||||
|
||||
@controllerBind('auth:login', (user) =>
|
||||
return if !user
|
||||
@verifyLater(user.id)
|
||||
)
|
||||
user = App.User.current()
|
||||
@verifyLater(user.id) if user?
|
||||
|
||||
verifyLater: (userId) =>
|
||||
delay = =>
|
||||
@verify(userId)
|
||||
@delay(delay, 5000, 'user_signup_verify_dialog')
|
||||
|
||||
verify: (userId) ->
|
||||
return if !userId
|
||||
return if !App.User.exists(userId)
|
||||
user = App.User.find(userId)
|
||||
return if user.source isnt 'signup'
|
||||
return if user.verified is true
|
||||
currentTime = new Date().getTime()
|
||||
createdAt = Date.parse(user.created_at)
|
||||
diff = currentTime - createdAt
|
||||
max = 1000 * 60 * 30 # show message if account is older then 30 minutes
|
||||
return if diff < max
|
||||
new Modal(user: user)
|
||||
|
||||
class Modal extends App.ControllerModal
|
||||
backdrop: false
|
||||
keyboard: false
|
||||
head: 'Account not verified'
|
||||
small: true
|
||||
buttonClose: false
|
||||
buttonCancel: false
|
||||
buttonSubmit: 'Resend verification email'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
content: =>
|
||||
if !@sent
|
||||
return App.i18n.translateContent('Your account has not been verified. Please click the link in the verification email.')
|
||||
content = App.i18n.translateContent('We\'ve sent an email to _%s_. Click the link in the email to verify your account.', @user.email)
|
||||
content += '<br><br>'
|
||||
content += App.i18n.translateContent('If you don\'t see the email, check other places it might be, like your junk, spam, social, or other folders.')
|
||||
content
|
||||
|
||||
onSubmit: =>
|
||||
@ajax(
|
||||
id: 'email_verify_send'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/users/email_verify_send'
|
||||
data: JSON.stringify(email: @user.email)
|
||||
processData: true
|
||||
success: @success
|
||||
error: @error
|
||||
)
|
||||
|
||||
success: (data) =>
|
||||
@sent = true
|
||||
@update()
|
||||
|
||||
# if in developer mode, redirect to verify
|
||||
if data.token && @Config.get('developer_mode') is true
|
||||
redirect = =>
|
||||
@close()
|
||||
@navigate "#email_verify/#{data.token}"
|
||||
App.Delay.set(redirect, 4000)
|
||||
|
||||
error: =>
|
||||
@contentInline = App.i18n.translateContent('Unable to send verify email.')
|
||||
@update()
|
||||
|
||||
App.Config.set('user_signup', UserSignupCheck, 'Plugins')
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileAvatar extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.avatar'
|
||||
header: 'Avatar'
|
||||
elements:
|
||||
|
@ -145,7 +145,7 @@ class Index extends App.ControllerSubContent
|
|||
|
||||
reader.readAsDataURL(@)
|
||||
|
||||
App.Config.set('Avatar', { prio: 1100, name: 'Avatar', parent: '#profile', target: '#profile/avatar', controller: Index, permission: ['user_preferences.avatar'] }, 'NavBarProfile')
|
||||
App.Config.set('Avatar', { prio: 1100, name: 'Avatar', parent: '#profile', target: '#profile/avatar', controller: ProfileAvatar, permission: ['user_preferences.avatar'] }, 'NavBarProfile')
|
||||
|
||||
class ImageCropper extends App.ControllerModal
|
||||
buttonClose: true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class CalendarSubscriptions extends App.ControllerSubContent
|
||||
class ProfileCalendarSubscriptions extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.calendar+ticket.agent'
|
||||
header: 'Calendar'
|
||||
elements:
|
||||
|
@ -90,4 +90,4 @@ class CalendarSubscriptions extends App.ControllerSubContent
|
|||
msg: App.i18n.translateContent(data.message)
|
||||
)
|
||||
|
||||
App.Config.set('CalendarSubscriptions', { prio: 3000, name: 'Calendar', parent: '#profile', target: '#profile/calendar_subscriptions', permission: ['user_preferences.calendar+ticket.agent'], controller: CalendarSubscriptions }, 'NavBarProfile')
|
||||
App.Config.set('CalendarSubscriptions', { prio: 3000, name: 'Calendar', parent: '#profile', target: '#profile/calendar_subscriptions', permission: ['user_preferences.calendar+ticket.agent'], controller: ProfileCalendarSubscriptions }, 'NavBarProfile')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileDevices extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.device'
|
||||
header: 'Devices'
|
||||
events:
|
||||
|
@ -55,4 +55,4 @@ class Index extends App.ControllerSubContent
|
|||
msg: App.i18n.translateContent(data.message)
|
||||
)
|
||||
|
||||
App.Config.set('Devices', { prio: 3100, name: 'Devices', parent: '#profile', target: '#profile/devices', controller: Index, permission: ['user_preferences.device'] }, 'NavBarProfile')
|
||||
App.Config.set('Devices', { prio: 3100, name: 'Devices', parent: '#profile', target: '#profile/devices', controller: ProfileDevices, permission: ['user_preferences.device'] }, 'NavBarProfile')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileLanguage extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.language'
|
||||
header: 'Language'
|
||||
events:
|
||||
|
@ -19,7 +19,7 @@ class Index extends App.ControllerSubContent
|
|||
]
|
||||
|
||||
@form = new App.ControllerForm(
|
||||
el: html.find('.language_item')
|
||||
el: html.find('.js-language')
|
||||
model: { configure_attributes: configure_attributes }
|
||||
autofocus: false
|
||||
)
|
||||
|
@ -69,4 +69,4 @@ class Index extends App.ControllerSubContent
|
|||
msg: App.i18n.translateContent(data.message)
|
||||
)
|
||||
|
||||
App.Config.set('Language', { prio: 1000, name: 'Language', parent: '#profile', target: '#profile/language', controller: Index, permission: ['user_preferences.language'] }, 'NavBarProfile')
|
||||
App.Config.set('Language', { prio: 1000, name: 'Language', parent: '#profile', target: '#profile/language', controller: ProfileLanguage, permission: ['user_preferences.language'] }, 'NavBarProfile')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileLinkedAccounts extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.linked_accounts'
|
||||
header: 'Linked Accounts'
|
||||
events:
|
||||
|
@ -59,7 +59,7 @@ class Index extends App.ControllerSubContent
|
|||
msg: App.i18n.translateContent(data.message)
|
||||
)
|
||||
|
||||
App.Config.set('LinkedAccounts', { prio: 4000, name: 'Linked Accounts', parent: '#profile', target: '#profile/linked', controller: Index, permission: ['user_preferences.linked_accounts'] }, 'NavBarProfile')
|
||||
App.Config.set('LinkedAccounts', { prio: 4000, name: 'Linked Accounts', parent: '#profile', target: '#profile/linked', controller: ProfileLinkedAccounts, permission: ['user_preferences.linked_accounts'] }, 'NavBarProfile')
|
||||
App.Config.set('auth_provider_all', {
|
||||
facebook:
|
||||
url: '/auth/facebook'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileNotification extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.notifications+ticket.agent'
|
||||
header: 'Notifications'
|
||||
events:
|
||||
|
@ -192,4 +192,4 @@ class Index extends App.ControllerSubContent
|
|||
return if !params.notification_sound.file
|
||||
App.OnlineNotification.play(params.notification_sound.file)
|
||||
|
||||
App.Config.set('Notifications', { prio: 2600, name: 'Notifications', parent: '#profile', target: '#profile/notifications', permission: ['user_preferences.notifications+ticket.agent'], controller: Index }, 'NavBarProfile')
|
||||
App.Config.set('Notifications', { prio: 2600, name: 'Notifications', parent: '#profile', target: '#profile/notifications', permission: ['user_preferences.notifications+ticket.agent'], controller: ProfileNotification }, 'NavBarProfile')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileOutOfOffice extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.out_of_office+ticket.agent'
|
||||
header: 'Out of Office'
|
||||
events:
|
||||
|
@ -161,4 +161,4 @@ class Index extends App.ControllerSubContent
|
|||
msg: App.i18n.translateContent(message)
|
||||
removeAll: true
|
||||
|
||||
App.Config.set('OutOfOffice', { prio: 2800, name: 'Out of Office', parent: '#profile', target: '#profile/out_of_office', permission: ['user_preferences.out_of_office+ticket.agent'], controller: Index }, 'NavBarProfile')
|
||||
App.Config.set('OutOfOffice', { prio: 2800, name: 'Out of Office', parent: '#profile', target: '#profile/out_of_office', permission: ['user_preferences.out_of_office+ticket.agent'], controller: ProfileOutOfOffice }, 'NavBarProfile')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfilePassword extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.password'
|
||||
header: 'Password'
|
||||
events:
|
||||
|
@ -78,4 +78,4 @@ class Index extends App.ControllerSubContent
|
|||
removeAll: true
|
||||
@formEnable( @$('form') )
|
||||
|
||||
App.Config.set('Password', { prio: 2000, name: 'Password', parent: '#profile', target: '#profile/password', controller: Index, permission: ['user_preferences.password'] }, 'NavBarProfile')
|
||||
App.Config.set('Password', { prio: 2000, name: 'Password', parent: '#profile', target: '#profile/password', controller: ProfilePassword, permission: ['user_preferences.password'] }, 'NavBarProfile')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ProfileTokenAccess extends App.ControllerSubContent
|
||||
requiredPermission: 'user_preferences.access_token'
|
||||
header: 'Token Access'
|
||||
events:
|
||||
|
@ -144,4 +144,4 @@ class Create extends App.ControllerModal
|
|||
msg: App.i18n.translateContent(data.message || data.error)
|
||||
)
|
||||
|
||||
App.Config.set('Token Access', { prio: 3200, name: 'Token Access', parent: '#profile', target: '#profile/token_access', controller: Index, permission: ['user_preferences.access_token'] }, 'NavBarProfile')
|
||||
App.Config.set('Token Access', { prio: 3200, name: 'Token Access', parent: '#profile', target: '#profile/token_access', controller: ProfileTokenAccess, permission: ['user_preferences.access_token'] }, 'NavBarProfile')
|
||||
|
|
|
@ -76,19 +76,19 @@ class App.SettingsForm extends App.Controller
|
|||
ui.formEnable(e)
|
||||
count -= 1
|
||||
if count == 0
|
||||
App.Event.trigger 'notify', {
|
||||
App.Event.trigger('notify', {
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent('Update successful!')
|
||||
timeout: 2000
|
||||
}
|
||||
})
|
||||
|
||||
# rerender ui || get new collections and session data
|
||||
App.Setting.preferencesPost(@)
|
||||
|
||||
fail: (settings, details) ->
|
||||
App.Event.trigger 'notify', {
|
||||
App.Event.trigger('notify', {
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
|
||||
timeout: 2000
|
||||
}
|
||||
})
|
||||
)
|
||||
|
|
|
@ -494,7 +494,6 @@ class App.UiElement.ticket_perform_action
|
|||
elementRow.find('.js-setArticle').empty()
|
||||
|
||||
name = "#{attribute.name}::article.#{articleType}"
|
||||
console.log('meta', meta)
|
||||
selection = App.UiElement.select.render(
|
||||
name: "#{name}::internal"
|
||||
multiple: false
|
||||
|
|
|
@ -84,8 +84,6 @@ class App.UiElement.user_permission
|
|||
input = $(@).find('input')
|
||||
upcoming_state = !input.prop('checked')
|
||||
value = input.val()
|
||||
console.log(upcoming_state)
|
||||
console.log(value)
|
||||
|
||||
if value is 'full' and upcoming_state is true
|
||||
$(@).closest('tr').find('input:not([value=full])').prop('checked', false)
|
||||
|
|
|
@ -54,14 +54,14 @@ class App.TicketCreate extends App.Controller
|
|||
@bindId = App.TicketCreateCollection.one(load)
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@bind('ui:rerender', =>
|
||||
@controllerBind('ui:rerender', =>
|
||||
return if !@authenticateCheck()
|
||||
@renderQueue()
|
||||
@tokanice()
|
||||
)
|
||||
|
||||
# listen to rerender sidebars
|
||||
@bind('ui::ticket::sidebarRerender', (data) =>
|
||||
@controllerBind('ui::ticket::sidebarRerender', (data) =>
|
||||
return if data.taskKey isnt @taskKey
|
||||
return if !@sidebarWidget
|
||||
@sidebarWidget.render(@params())
|
||||
|
@ -169,11 +169,11 @@ class App.TicketCreate extends App.Controller
|
|||
show: =>
|
||||
@navupdate("#ticket/create/id/#{@id}#{@split}", type: 'menu')
|
||||
@autosaveStart()
|
||||
@bind('ticket_create_rerender', (template) => @renderQueue(template))
|
||||
@controllerBind('ticket_create_rerender', (template) => @renderQueue(template))
|
||||
|
||||
hide: =>
|
||||
@autosaveStop()
|
||||
@unbind('ticket_create_rerender', (template) => @renderQueue(template))
|
||||
@controllerUnbind('ticket_create_rerender', (template) => @renderQueue(template))
|
||||
|
||||
changed: =>
|
||||
formCurrent = @formParam( @$('.ticket-create') )
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class Api extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.api'
|
||||
header: 'API'
|
||||
events:
|
||||
|
@ -193,4 +193,4 @@ class ViewAppTokenModal extends App.ControllerModal
|
|||
@$('.js-submit').remove()
|
||||
)
|
||||
|
||||
App.Config.set('API', { prio: 1200, name: 'API', parent: '#system', target: '#system/api', controller: Index, permission: ['admin.api'] }, 'NavBarAdmin')
|
||||
App.Config.set('API', { prio: 1200, name: 'API', parent: '#system', target: '#system/api', controller: Api, permission: ['admin.api'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class Calendar extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.calendar'
|
||||
header: 'Calendars'
|
||||
events:
|
||||
|
@ -121,4 +121,4 @@ class Index extends App.ControllerSubContent
|
|||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
App.Config.set('Calendars', { prio: 2400, name: 'Calendars', parent: '#manage', target: '#manage/calendars', controller: Index, permission: ['admin.calendar'] }, 'NavBarAdmin')
|
||||
App.Config.set('Calendars', { prio: 2400, name: 'Calendars', parent: '#manage', target: '#manage/calendars', controller: Calendar, permission: ['admin.calendar'] }, 'NavBarAdmin')
|
||||
|
|
|
@ -42,7 +42,7 @@ class App.CustomerChat extends App.Controller
|
|||
@on('layout-has-changed', @propagateLayoutChange)
|
||||
|
||||
# update navbar on new status
|
||||
@bind('chat_status_agent', (data) =>
|
||||
@controllerBind('chat_status_agent', (data) =>
|
||||
if data.assets
|
||||
App.Collection.loadAssets(data.assets)
|
||||
@meta = data
|
||||
|
@ -52,19 +52,19 @@ class App.CustomerChat extends App.Controller
|
|||
)
|
||||
|
||||
# add new chat window
|
||||
@bind('chat_session_start', (data) =>
|
||||
@controllerBind('chat_session_start', (data) =>
|
||||
if data.session
|
||||
@addChat(data.session)
|
||||
)
|
||||
|
||||
# on new login or on
|
||||
@bind('ws:login chat_agent_state', ->
|
||||
@controllerBind('ws:login chat_agent_state', ->
|
||||
App.WebSocket.send(event:'chat_status_agent')
|
||||
)
|
||||
App.WebSocket.send(event:'chat_status_agent')
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@bind('ui:rerender chat:rerender', =>
|
||||
@controllerBind('ui:rerender chat:rerender', =>
|
||||
return if !@authenticateCheck()
|
||||
for session_id, chat of @chatWindows
|
||||
chat.el.remove()
|
||||
|
@ -122,8 +122,8 @@ class App.CustomerChat extends App.Controller
|
|||
|
||||
|
||||
show: (params) =>
|
||||
@title 'Customer Chat', true
|
||||
@navupdate '#customer_chat'
|
||||
@title('Customer Chat', true)
|
||||
@navupdate('#customer_chat')
|
||||
|
||||
if params.session_id
|
||||
callback = (session) =>
|
||||
|
@ -433,34 +433,34 @@ class ChatWindow extends App.Controller
|
|||
|
||||
@on('layout-change', @onLayoutChange)
|
||||
|
||||
@bind('chat_session_typing', (data) =>
|
||||
@controllerBind('chat_session_typing', (data) =>
|
||||
return if data.session_id isnt @session.session_id
|
||||
return if data.self_written
|
||||
@showWritingLoader()
|
||||
)
|
||||
@bind('chat_session_message', (data) =>
|
||||
@controllerBind('chat_session_message', (data) =>
|
||||
return if data.session_id isnt @session.session_id
|
||||
return if data.self_written
|
||||
@receiveMessage(data.message.content)
|
||||
)
|
||||
@bind('chat_session_notice', (data) =>
|
||||
@controllerBind('chat_session_notice', (data) =>
|
||||
return if data.session_id isnt @session.session_id
|
||||
return if data.self_written
|
||||
@addNoticeMessage(data.message)
|
||||
)
|
||||
@bind('chat_session_left', (data) =>
|
||||
@controllerBind('chat_session_left', (data) =>
|
||||
return if data.session_id isnt @session.session_id
|
||||
return if data.self_written
|
||||
@addStatusMessage("<strong>#{data.realname}</strong> left the conversation")
|
||||
@goOffline()
|
||||
)
|
||||
@bind('chat_session_closed', (data) =>
|
||||
@controllerBind('chat_session_closed', (data) =>
|
||||
return if data.session_id isnt @session.session_id
|
||||
return if data.self_written
|
||||
@addStatusMessage("<strong>#{data.realname}</strong> closed the conversation")
|
||||
@goOffline()
|
||||
)
|
||||
@bind('chat_focus', (data) =>
|
||||
@controllerBind('chat_focus', (data) =>
|
||||
return if data.session_id isnt @session.session_id
|
||||
@focus()
|
||||
)
|
||||
|
@ -572,7 +572,7 @@ class ChatWindow extends App.Controller
|
|||
onTransitionend: (event) =>
|
||||
# chat window is done with animation - adjust scroll-bars
|
||||
# of sibling chat windows
|
||||
@trigger 'layout-has-changed'
|
||||
@trigger('layout-has-changed')
|
||||
|
||||
if event.data and event.data.callback
|
||||
event.data.callback()
|
||||
|
@ -601,7 +601,7 @@ class ChatWindow extends App.Controller
|
|||
@removeCallback(@session.session_id)
|
||||
|
||||
release: =>
|
||||
@trigger 'closed'
|
||||
@trigger('closed')
|
||||
@el.remove()
|
||||
super
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.Controller
|
||||
class Clues extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@navupdate '#', true
|
||||
|
@ -6,7 +6,7 @@ class Index extends App.Controller
|
|||
|
||||
clues: =>
|
||||
new App.FirstStepsClues(
|
||||
el: @el
|
||||
appEl: @appEl
|
||||
onComplete: =>
|
||||
App.Ajax.request(
|
||||
id: 'preferences'
|
||||
|
@ -18,4 +18,4 @@ class Index extends App.Controller
|
|||
@navigate '#'
|
||||
)
|
||||
|
||||
App.Config.set('clues', Index, 'Routes')
|
||||
App.Config.set('clues', Clues, 'Routes')
|
||||
|
|
|
@ -23,13 +23,13 @@ class App.CTI extends App.Controller
|
|||
@meta.active = preferences.cti || false
|
||||
|
||||
@load()
|
||||
@bind('cti_list_push', (data) =>
|
||||
@controllerBind('cti_list_push', (data) =>
|
||||
delay = =>
|
||||
@load()
|
||||
@delay(delay, 500, 'cti_list_push_render')
|
||||
'cti_list_push'
|
||||
)
|
||||
@bind('cti_event', (data) =>
|
||||
@controllerBind('cti_event', (data) =>
|
||||
return if data.state isnt 'newCall'
|
||||
return if data.direction isnt 'in'
|
||||
return if @switch() isnt true
|
||||
|
@ -37,7 +37,7 @@ class App.CTI extends App.Controller
|
|||
@notify(data)
|
||||
'cti_event'
|
||||
)
|
||||
@bind('menu:render', (data) =>
|
||||
@controllerBind('menu:render', (data) =>
|
||||
return if @switch() isnt true
|
||||
localHtml = ''
|
||||
for item in @ringingCalls()
|
||||
|
@ -53,26 +53,25 @@ class App.CTI extends App.Controller
|
|||
user_id = $(e.currentTarget).data('user-id')
|
||||
if user_id
|
||||
user = App.User.find(user_id)
|
||||
console.log('user_id', user_id, user)
|
||||
@newTicket(user)
|
||||
)
|
||||
)
|
||||
@bind('auth', (data) =>
|
||||
@controllerBind('auth', (data) =>
|
||||
@meta.counter = 0
|
||||
)
|
||||
@bind('cti:reload', =>
|
||||
@controllerBind('cti:reload', =>
|
||||
@load()
|
||||
'cti_reload'
|
||||
)
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@bind('ui:rerender', =>
|
||||
@controllerBind('ui:rerender', =>
|
||||
@render()
|
||||
'cti_rerender'
|
||||
)
|
||||
|
||||
# after a new websocket connection, load again
|
||||
@bind('spool:sent', =>
|
||||
@controllerBind('spool:sent', =>
|
||||
if @initSpoolSent
|
||||
@load()
|
||||
return
|
||||
|
@ -280,7 +279,7 @@ class App.CTI extends App.Controller
|
|||
currentPosition: =>
|
||||
@$('.main').scrollTop()
|
||||
|
||||
class WidgetAvatar extends App.ObserverController
|
||||
class WidgetAvatar extends App.ControllerObserver
|
||||
@extend App.PopoverProvidable
|
||||
@registerPopovers 'User'
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerContent
|
||||
class CustomerTicketCreate extends App.ControllerAppContent
|
||||
requiredPermission: 'ticket.customer'
|
||||
events:
|
||||
'submit form': 'submit',
|
||||
|
@ -211,7 +211,7 @@ class Index extends App.ControllerContent
|
|||
return
|
||||
@formEnable(@$('.js-submit'), 'button')
|
||||
|
||||
App.Config.set('customer_ticket_new', Index, 'Routes')
|
||||
App.Config.set('customer_ticket_new', CustomerTicketCreate, 'Routes')
|
||||
App.Config.set('CustomerTicketNew', {
|
||||
prio: 8003,
|
||||
parent: '#new',
|
||||
|
|
|
@ -15,9 +15,10 @@ class App.Dashboard extends App.Controller
|
|||
@render()
|
||||
|
||||
# rerender view, e. g. on language change
|
||||
@bind 'ui:rerender', =>
|
||||
@controllerBind('ui:rerender', =>
|
||||
return if !@authenticateCheck()
|
||||
@render()
|
||||
)
|
||||
|
||||
@mayBeClues()
|
||||
|
||||
|
@ -71,12 +72,12 @@ class App.Dashboard extends App.Controller
|
|||
|
||||
# incase of being only customer, redirect to default router
|
||||
if @permissionCheck('ticket.customer') && !@permissionCheck('ticket.agent')
|
||||
@navigate '#ticket/view', true
|
||||
@navigate '#ticket/view', { hideCurrentLocationFromHistory: true }
|
||||
return
|
||||
|
||||
# incase of being only admin, redirect to admin interface (show no empty white content page)
|
||||
if !@permissionCheck('ticket.customer') && !@permissionCheck('ticket.agent') && @permissionCheck('admin')
|
||||
@navigate '#manage', true
|
||||
@navigate '#manage', { hideCurrentLocationFromHistory: true }
|
||||
return
|
||||
|
||||
# set title
|
||||
|
|
|
@ -9,19 +9,19 @@ class DefaultRouter extends App.Controller
|
|||
|
||||
# check if import is active
|
||||
if !@Config.get('system_init_done') && @Config.get('import_mode')
|
||||
@navigate '#import', true
|
||||
@navigate '#import', { hideCurrentLocationFromHistory: true }
|
||||
return
|
||||
|
||||
# route to getting started screen
|
||||
if !@Config.get('system_init_done')
|
||||
@navigate '#getting_started', true
|
||||
@navigate '#getting_started', { hideCurrentLocationFromHistory: true }
|
||||
return
|
||||
|
||||
if @Config.get('default_controller')
|
||||
@navigate @Config.get('default_controller'), true
|
||||
@navigate @Config.get('default_controller'), { hideCurrentLocationFromHistory: true }
|
||||
return
|
||||
|
||||
@navigate '#dashboard', true
|
||||
@navigate '#dashboard', { hideCurrentLocationFromHistory: true }
|
||||
|
||||
App.Config.set('', DefaultRouter, 'Routes')
|
||||
App.Config.set('/', DefaultRouter, 'Routes')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.Controller
|
||||
class EmailVerify extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@verifyCall()
|
||||
|
@ -10,23 +10,47 @@ class Index extends App.Controller
|
|||
url: "#{@apiPath}/users/email_verify"
|
||||
data: JSON.stringify(token: @token)
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
App.Auth.loginCheck()
|
||||
@navigate '#'
|
||||
|
||||
@notify
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent('Woo hoo! Your email address has been verified!')
|
||||
removeAll: true
|
||||
timeout: 2000
|
||||
|
||||
error: (data, status, xhr) =>
|
||||
@navigate '#'
|
||||
|
||||
@notify
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent('Unable to verify email. Please contact your administrator.')
|
||||
removeAll: true
|
||||
success: @success
|
||||
error: @error
|
||||
)
|
||||
|
||||
App.Config.set('email_verify/:token', Index, 'Routes')
|
||||
success: =>
|
||||
new Success(el: @el, appEl: @appEl)
|
||||
|
||||
error: =>
|
||||
new Fail(el: @el, appEl: @appEl)
|
||||
|
||||
class Success extends App.ControllerAppContent
|
||||
constructor: ->
|
||||
super
|
||||
@render()
|
||||
|
||||
# rerender view, e. g. on language change
|
||||
@controllerBind('ui:rerender', =>
|
||||
@render()
|
||||
)
|
||||
|
||||
render: =>
|
||||
@renderScreenSuccess(
|
||||
detail: 'Woo hoo! Your email address has been verified!'
|
||||
)
|
||||
delay = =>
|
||||
@navigate '#'
|
||||
@delay(delay, 2000)
|
||||
|
||||
class Fail extends App.ControllerAppContent
|
||||
constructor: ->
|
||||
super
|
||||
@render()
|
||||
|
||||
# rerender view, e. g. on language change
|
||||
@controllerBind('ui:rerender', =>
|
||||
@render()
|
||||
)
|
||||
|
||||
render: =>
|
||||
@renderScreenError(
|
||||
detail: 'Unable to verify email. Please contact your administrator.'
|
||||
)
|
||||
|
||||
App.Config.set('email_verify/:token', EmailVerify, 'Routes')
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,112 @@
|
|||
class GettingStartedAdmin extends App.ControllerWizardFullScreen
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
if @authenticateCheck() && !@permissionCheck('admin.wizard')
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Create Admin'
|
||||
|
||||
# redirect to login if master user already exists
|
||||
if @Config.get('system_init_done')
|
||||
@navigate '#login'
|
||||
return
|
||||
|
||||
@fetch()
|
||||
|
||||
fetch: ->
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: 'getting_started'
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/getting_started"
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# check if user got created right now
|
||||
#if true
|
||||
# @navigate '#getting_started/base', { emptyEl: true }
|
||||
# return
|
||||
|
||||
# check if import is active
|
||||
if data.import_mode == true
|
||||
@navigate "#import/#{data.import_backend}", { emptyEl: true }
|
||||
return
|
||||
|
||||
# load group collection
|
||||
App.Collection.load(type: 'Group', data: data.groups)
|
||||
|
||||
# render page
|
||||
@render()
|
||||
)
|
||||
|
||||
render: ->
|
||||
|
||||
@replaceWith(App.view('getting_started/admin')())
|
||||
|
||||
@form = new App.ControllerForm(
|
||||
el: @$('.js-admin-form')
|
||||
model: App.User
|
||||
screen: 'signup'
|
||||
autofocus: true
|
||||
)
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
@formDisable(e)
|
||||
@params = @formParam(e.target)
|
||||
@params.role_ids = []
|
||||
|
||||
user = new App.User
|
||||
user.load(@params)
|
||||
|
||||
errors = user.validate(
|
||||
screen: 'signup'
|
||||
)
|
||||
if errors
|
||||
@log 'error new', errors
|
||||
|
||||
# Only highlight, but don't add message. Error text breaks layout.
|
||||
Object.keys(errors).forEach (key) ->
|
||||
errors[key] = null
|
||||
|
||||
@formValidate(form: e.target, errors: errors)
|
||||
@formEnable(e)
|
||||
return false
|
||||
else
|
||||
@formValidate(form: e.target, errors: errors)
|
||||
|
||||
# save user
|
||||
user.save(
|
||||
done: (r) =>
|
||||
App.Auth.login(
|
||||
data:
|
||||
username: @params.email
|
||||
password: @params.password
|
||||
success: @relogin
|
||||
error: ->
|
||||
App.Event.trigger('notify', {
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent('Signin failed! Please contact the support team!')
|
||||
timeout: 2500
|
||||
})
|
||||
)
|
||||
@Config.set('system_init_done', true)
|
||||
|
||||
fail: (settings, details) =>
|
||||
@formEnable(e)
|
||||
@form.showAlert(details.error_human || details.error || 'Unable to create user!')
|
||||
)
|
||||
|
||||
relogin: (data, status, xhr) =>
|
||||
@log 'notice', 'relogin:success', data
|
||||
App.Event.trigger('notify:removeall')
|
||||
@navigate('getting_started/base', { emptyEl: true })
|
||||
|
||||
App.Config.set('getting_started/admin', GettingStartedAdmin, 'Routes')
|
|
@ -0,0 +1,89 @@
|
|||
class GettingStartedAgent extends App.ControllerWizardFullScreen
|
||||
events:
|
||||
'submit form': 'submit'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
# set title
|
||||
@title 'Invite Agents'
|
||||
@fetch()
|
||||
|
||||
fetch: ->
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: 'getting_started'
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/getting_started"
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# check if import is active
|
||||
if data.import_mode == true
|
||||
@navigate "#import/#{data.import_backend}", { emptyEl: true }
|
||||
return
|
||||
|
||||
# load group collection
|
||||
App.Collection.load(type: 'Group', data: data.groups)
|
||||
|
||||
# render page
|
||||
@render()
|
||||
)
|
||||
|
||||
render: ->
|
||||
|
||||
@replaceWith App.view('getting_started/agent')()
|
||||
|
||||
@form = new App.ControllerForm(
|
||||
el: @$('.js-agent-form')
|
||||
model: App.User
|
||||
screen: 'invite_agent'
|
||||
autofocus: true
|
||||
)
|
||||
|
||||
submit: (e) =>
|
||||
e.preventDefault()
|
||||
@formDisable(e)
|
||||
@params = @formParam(e.target)
|
||||
@params.role_ids = []
|
||||
|
||||
# set invite flag
|
||||
@params.invite = true
|
||||
|
||||
# find agent role
|
||||
role = App.Role.findByAttribute('name', 'Agent')
|
||||
if role
|
||||
@params.role_ids = role.id
|
||||
|
||||
user = new App.User
|
||||
user.load(@params)
|
||||
|
||||
errors = user.validate(
|
||||
screen: 'invite_agent'
|
||||
)
|
||||
if errors
|
||||
@log 'error new', errors
|
||||
@formValidate(form: e.target, errors: errors)
|
||||
@formEnable(e)
|
||||
return false
|
||||
|
||||
# save user
|
||||
user.save(
|
||||
done: (r) =>
|
||||
App.Event.trigger('notify', {
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent('Invitation sent!')
|
||||
timeout: 3500
|
||||
})
|
||||
|
||||
# rerender page
|
||||
@render()
|
||||
|
||||
fail: (settings, details) =>
|
||||
@formEnable(e)
|
||||
@form.showAlert(details.error_human || 'Can\'t create user!')
|
||||
)
|
||||
|
||||
App.Config.set('getting_started/agents', GettingStartedAgent, 'Routes')
|
|
@ -0,0 +1,65 @@
|
|||
class GettingStartedAutoWizard extends App.ControllerWizardFullScreen
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# if already logged in, got to #
|
||||
if @authenticateCheck() && !@permissionCheck('admin.wizard')
|
||||
@navigate '#'
|
||||
return
|
||||
|
||||
# redirect to login if master user already exists
|
||||
if @Config.get('system_init_done')
|
||||
@navigate '#login'
|
||||
return
|
||||
|
||||
# set title
|
||||
@title 'Auto Wizard'
|
||||
@renderSplash()
|
||||
@fetch()
|
||||
|
||||
fetch: ->
|
||||
|
||||
url = "#{@apiPath}/getting_started/auto_wizard"
|
||||
if @token
|
||||
url += "/#{@token}"
|
||||
|
||||
# get data
|
||||
@ajax(
|
||||
id: 'auto_wizard'
|
||||
type: 'GET'
|
||||
url: url
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# check if auto wizard enabled
|
||||
if data.auto_wizard is false
|
||||
@redirectToLogin()
|
||||
return
|
||||
|
||||
# auto wizard setup was successful
|
||||
if data.auto_wizard_success is true
|
||||
@delay(@redirectToLogin, 800)
|
||||
return
|
||||
|
||||
if data.auto_wizard_success is false
|
||||
if data.message
|
||||
@renderFailed(data)
|
||||
else
|
||||
@renderToken()
|
||||
return
|
||||
|
||||
# redirect to login if master user already exists
|
||||
@redirectToLogin()
|
||||
)
|
||||
|
||||
renderFailed: (data) ->
|
||||
@replaceWith App.view('getting_started/auto_wizard_failed')(data)
|
||||
|
||||
renderSplash: ->
|
||||
@replaceWith App.view('getting_started/auto_wizard_splash')()
|
||||
|
||||
renderToken: ->
|
||||
@replaceWith App.view('getting_started/auto_wizard_enabled')()
|
||||
|
||||
App.Config.set('getting_started/auto_wizard', GettingStartedAutoWizard, 'Routes')
|
||||
App.Config.set('getting_started/auto_wizard/:token', GettingStartedAutoWizard, 'Routes')
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue