Reduced rerendering of object (introduction of App.ObserverController).
This commit is contained in:
parent
dfc5900234
commit
08c5ca3e62
23 changed files with 292 additions and 225 deletions
|
@ -260,7 +260,7 @@ class App.Controller extends Spine.Controller
|
||||||
|
|
||||||
# open ticket in new task if curent user agent
|
# open ticket in new task if curent user agent
|
||||||
if @isRole('Agent')
|
if @isRole('Agent')
|
||||||
@el.find('div.ticket-popover, span.ticket-popover').bind('click', (e) =>
|
@$('div.ticket-popover, span.ticket-popover').bind('click', (e) =>
|
||||||
id = $(e.target).data('id')
|
id = $(e.target).data('id')
|
||||||
if id
|
if id
|
||||||
ticket = App.Ticket.find(id)
|
ticket = App.Ticket.find(id)
|
||||||
|
@ -304,8 +304,7 @@ class App.Controller extends Spine.Controller
|
||||||
|
|
||||||
# open user in new task if current user is agent
|
# open user in new task if current user is agent
|
||||||
return if !@isRole('Agent')
|
return if !@isRole('Agent')
|
||||||
|
@$('div.user-popover, span.user-popover').bind('click', (e) =>
|
||||||
@el.find('div.user-popover, span.user-popover').bind('click', (e) =>
|
|
||||||
id = $(e.target).data('id')
|
id = $(e.target).data('id')
|
||||||
if id
|
if id
|
||||||
user = App.User.find(id)
|
user = App.User.find(id)
|
||||||
|
@ -363,7 +362,7 @@ class App.Controller extends Spine.Controller
|
||||||
# open org in new task if current user agent
|
# open org in new task if current user agent
|
||||||
return if !@isRole('Agent')
|
return if !@isRole('Agent')
|
||||||
|
|
||||||
@el.find('div.organization-popover, span.organization-popover').bind('click', (e) =>
|
@$('div.organization-popover, span.organization-popover').bind('click', (e) =>
|
||||||
id = $(e.target).data('id')
|
id = $(e.target).data('id')
|
||||||
if id
|
if id
|
||||||
organization = App.Organization.find(id)
|
organization = App.Organization.find(id)
|
||||||
|
|
|
@ -1068,3 +1068,83 @@ class App.CollectionController extends App.Controller
|
||||||
|
|
||||||
onRemoved: (id) ->
|
onRemoved: (id) ->
|
||||||
# nothing
|
# nothing
|
||||||
|
|
||||||
|
class App.ObserverController extends App.Controller
|
||||||
|
model: 'Ticket'
|
||||||
|
template: 'ticket_zoom/title'
|
||||||
|
|
||||||
|
###
|
||||||
|
observe:
|
||||||
|
title: true
|
||||||
|
|
||||||
|
observeNot:
|
||||||
|
title: true
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
#console.trace()
|
||||||
|
@log 'debug', 'new', @object_id, @model
|
||||||
|
|
||||||
|
object = App[@model].fullLocal(@object_id)
|
||||||
|
if !object
|
||||||
|
App[@model].full(@object_id, @maybeRender)
|
||||||
|
else
|
||||||
|
@maybeRender(object)
|
||||||
|
|
||||||
|
# rerender, e. g. on language change
|
||||||
|
@bind('ui:rerender', =>
|
||||||
|
@lastAttributres = undefined
|
||||||
|
object = App[@model].fullLocal(@object_id)
|
||||||
|
@maybeRender(object)
|
||||||
|
)
|
||||||
|
|
||||||
|
subscribe: (object) =>
|
||||||
|
console.log('subscribe', object)
|
||||||
|
@maybeRender(object)
|
||||||
|
|
||||||
|
maybeRender: (object) =>
|
||||||
|
@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
|
||||||
|
attributes = object.attributes()
|
||||||
|
for key, value of attributes
|
||||||
|
if !@observeNot[key]
|
||||||
|
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
|
||||||
|
@lastAttributres = currentAttributes
|
||||||
|
|
||||||
|
@render(object)
|
||||||
|
|
||||||
|
render: (object) =>
|
||||||
|
@log 'debug', 'render', @template, object
|
||||||
|
@html App.view(@template)(
|
||||||
|
object: object
|
||||||
|
)
|
||||||
|
|
||||||
|
if @renderPost
|
||||||
|
@renderPost(object)
|
||||||
|
|
||||||
|
release: =>
|
||||||
|
#console.trace()
|
||||||
|
@log 'debug', 'release', @object_id, @model
|
||||||
|
App[@model].unsubscribe(@subscribeId)
|
||||||
|
|
|
@ -60,7 +60,7 @@ class App.DashboardActivityStream extends App.Controller
|
||||||
))
|
))
|
||||||
new App.WidgetAvatar(
|
new App.WidgetAvatar(
|
||||||
el: html.find('.js-avatar')
|
el: html.find('.js-avatar')
|
||||||
user_id: item.created_by_id
|
object_id: item.created_by_id
|
||||||
size: 40
|
size: 40
|
||||||
)
|
)
|
||||||
html
|
html
|
|
@ -126,7 +126,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||||
if App.Session.get('id')
|
if App.Session.get('id')
|
||||||
new App.WidgetAvatar(
|
new App.WidgetAvatar(
|
||||||
el: @$('.js-avatar')
|
el: @$('.js-avatar')
|
||||||
user_id: App.Session.get('id')
|
object_id: App.Session.get('id')
|
||||||
type: 'personal'
|
type: 'personal'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class App.OrganizationProfile extends App.Controller
|
||||||
|
|
||||||
new Object(
|
new Object(
|
||||||
el: elLocal.find('.js-object-container')
|
el: elLocal.find('.js-object-container')
|
||||||
organization: organization
|
object_id: organization.id
|
||||||
task_key: @task_key
|
task_key: @task_key
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -65,19 +65,20 @@ class App.OrganizationProfile extends App.Controller
|
||||||
genericObject: organization
|
genericObject: organization
|
||||||
)
|
)
|
||||||
|
|
||||||
class Object extends App.Controller
|
class Object extends App.ObserverController
|
||||||
|
model: 'Organization'
|
||||||
|
observeNot:
|
||||||
|
created_at: true
|
||||||
|
created_by_id: true
|
||||||
|
updated_at: true
|
||||||
|
updated_by_id: true
|
||||||
|
preferences: true
|
||||||
|
source: true
|
||||||
|
image_source: true
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'focusout [contenteditable]': 'update'
|
'focusout [contenteditable]': 'update'
|
||||||
|
|
||||||
constructor: (params) ->
|
|
||||||
super
|
|
||||||
|
|
||||||
# subscribe and reload data / fetch new data if triggered
|
|
||||||
@subscribeId = App.Organization.full(@organization.id, @render, false, true)
|
|
||||||
|
|
||||||
release: =>
|
|
||||||
App.Organization.unsubscribe(@subscribeId)
|
|
||||||
|
|
||||||
render: (organization) =>
|
render: (organization) =>
|
||||||
|
|
||||||
# update taskbar with new meta data
|
# update taskbar with new meta data
|
||||||
|
@ -111,6 +112,17 @@ class Object extends App.Controller
|
||||||
maxlength: 250
|
maxlength: 250
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# show members
|
||||||
|
members = []
|
||||||
|
for userId in organization.member_ids
|
||||||
|
el = $('<div></div>')
|
||||||
|
new Member(
|
||||||
|
object_id: userId
|
||||||
|
el: el
|
||||||
|
)
|
||||||
|
members.push el
|
||||||
|
@$('.js-userList').html(members)
|
||||||
|
|
||||||
# start action controller
|
# start action controller
|
||||||
showHistory = ->
|
showHistory = ->
|
||||||
new App.OrganizationHistory(
|
new App.OrganizationHistory(
|
||||||
|
@ -151,13 +163,26 @@ class Object extends App.Controller
|
||||||
update: (e) =>
|
update: (e) =>
|
||||||
name = $(e.target).attr('data-name')
|
name = $(e.target).attr('data-name')
|
||||||
value = $(e.target).html()
|
value = $(e.target).html()
|
||||||
org = App.Organization.find(@organization.id)
|
org = App.Organization.find(@object_id)
|
||||||
if org[name] isnt value
|
if org[name] isnt value
|
||||||
|
@lastAttributres[name] = value
|
||||||
data = {}
|
data = {}
|
||||||
data[name] = value
|
data[name] = value
|
||||||
org.updateAttributes(data)
|
org.updateAttributes(data)
|
||||||
@log 'notice', 'update', name, value, org
|
@log 'notice', 'update', name, value, org
|
||||||
|
|
||||||
|
class Member extends App.ObserverController
|
||||||
|
model: 'User'
|
||||||
|
observe:
|
||||||
|
firstname: true
|
||||||
|
lastname: true
|
||||||
|
login: true
|
||||||
|
email: true
|
||||||
|
|
||||||
|
render: (user) =>
|
||||||
|
@html App.view('organization_profile/member')(
|
||||||
|
user: user
|
||||||
|
)
|
||||||
|
|
||||||
class Router extends App.ControllerPermanent
|
class Router extends App.ControllerPermanent
|
||||||
constructor: (params) ->
|
constructor: (params) ->
|
||||||
|
|
|
@ -300,14 +300,14 @@ class App.TicketZoom extends App.Controller
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.TicketZoomTitle(
|
new App.TicketZoomTitle(
|
||||||
ticket: @ticket
|
object_id: @ticket.id
|
||||||
overview_id: @overview_id
|
overview_id: @overview_id
|
||||||
el: elLocal.find('.ticket-title')
|
el: elLocal.find('.ticket-title')
|
||||||
task_key: @task_key
|
task_key: @task_key
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.TicketZoomMeta(
|
new App.TicketZoomMeta(
|
||||||
ticket: @ticket
|
object_id: @ticket.id
|
||||||
el: elLocal.find('.ticket-meta')
|
el: elLocal.find('.ticket-meta')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ class App.TicketZoom extends App.Controller
|
||||||
el = @el
|
el = @el
|
||||||
new App.WidgetAvatar(
|
new App.WidgetAvatar(
|
||||||
el: el.find('.ticketZoom-header .js-avatar')
|
el: el.find('.ticketZoom-header .js-avatar')
|
||||||
user_id: @ticket.customer_id
|
object_id: @ticket.customer_id
|
||||||
size: 50
|
size: 50
|
||||||
)
|
)
|
||||||
@sidebar = new App.TicketZoomSidebar(
|
@sidebar = new App.TicketZoomSidebar(
|
||||||
|
|
|
@ -23,7 +23,7 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
else
|
else
|
||||||
@html ''
|
@html ''
|
||||||
|
|
||||||
publicInternal: (e) ->
|
publicInternal: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
articleContainer = $(e.target).closest('.ticket-article-item')
|
articleContainer = $(e.target).closest('.ticket-article-item')
|
||||||
article_id = $(e.target).parents('[data-id]').data('id')
|
article_id = $(e.target).parents('[data-id]').data('id')
|
||||||
|
@ -33,9 +33,8 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
internal = true
|
internal = true
|
||||||
if article.internal == true
|
if article.internal == true
|
||||||
internal = false
|
internal = false
|
||||||
article.updateAttributes(
|
@lastAttributres.internal = internal
|
||||||
internal: internal
|
article.updateAttributes(internal: internal)
|
||||||
)
|
|
||||||
|
|
||||||
# runntime update
|
# runntime update
|
||||||
if internal
|
if internal
|
||||||
|
|
|
@ -176,10 +176,9 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||||
|
|
||||||
new App.WidgetAvatar(
|
new App.WidgetAvatar(
|
||||||
el: @$('.js-avatar')
|
el: @$('.js-avatar')
|
||||||
user_id: App.Session.get('id')
|
object_id: App.Session.get('id')
|
||||||
size: 40
|
size: 40
|
||||||
position: 'right'
|
position: 'right'
|
||||||
class: 'zIndex-5'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_attributes = [
|
configure_attributes = [
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class App.TicketZoomArticleView extends App.Controller
|
class App.TicketZoomArticleView extends App.Controller
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
@article_controller = {}
|
@articleController = {}
|
||||||
@run()
|
@run()
|
||||||
|
|
||||||
execute: (params) =>
|
execute: (params) =>
|
||||||
|
@ -11,11 +11,12 @@ class App.TicketZoomArticleView extends App.Controller
|
||||||
run: =>
|
run: =>
|
||||||
all = []
|
all = []
|
||||||
for ticket_article_id in @ticket_article_ids
|
for ticket_article_id in @ticket_article_ids
|
||||||
if !@article_controller[ticket_article_id]
|
controllerKey = ticket_article_id.toString()
|
||||||
|
if !@articleController[controllerKey]
|
||||||
el = $('<div></div>')
|
el = $('<div></div>')
|
||||||
@article_controller[ticket_article_id] = new ArticleViewItem(
|
@articleController[controllerKey] = new ArticleViewItem(
|
||||||
ticket: @ticket
|
ticket: @ticket
|
||||||
ticket_article_id: ticket_article_id
|
object_id: ticket_article_id
|
||||||
el: el
|
el: el
|
||||||
ui: @ui
|
ui: @ui
|
||||||
highligher: @highligher
|
highligher: @highligher
|
||||||
|
@ -23,8 +24,26 @@ class App.TicketZoomArticleView extends App.Controller
|
||||||
all.push el
|
all.push el
|
||||||
@el.append(all)
|
@el.append(all)
|
||||||
|
|
||||||
class ArticleViewItem extends App.Controller
|
# check elements to remove
|
||||||
hasChangedAttributes: ['from', 'to', 'cc', 'subject', 'body', 'preferences']
|
for article_id, controller of @articleController
|
||||||
|
exists = false
|
||||||
|
for localArticleId in @ticket_article_ids
|
||||||
|
if localArticleId.toString() is article_id.toString()
|
||||||
|
exists = true
|
||||||
|
if !exists
|
||||||
|
controller.remove()
|
||||||
|
delete @articleController[article_id.toString()]
|
||||||
|
|
||||||
|
class ArticleViewItem extends App.ObserverController
|
||||||
|
model: 'TicketArticle'
|
||||||
|
observe:
|
||||||
|
from: true
|
||||||
|
to: true
|
||||||
|
cc: true
|
||||||
|
subject: true
|
||||||
|
body: true
|
||||||
|
internal: true
|
||||||
|
preferences: true
|
||||||
|
|
||||||
elements:
|
elements:
|
||||||
'.textBubble-content': 'textBubbleContent'
|
'.textBubble-content': 'textBubbleContent'
|
||||||
|
@ -36,12 +55,7 @@ class ArticleViewItem extends App.Controller
|
||||||
'click .js-unfold': 'unfold'
|
'click .js-unfold': 'unfold'
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
|
||||||
|
|
||||||
@seeMore = false
|
@seeMore = false
|
||||||
@force = true
|
|
||||||
|
|
||||||
@render()
|
|
||||||
|
|
||||||
# set expand of text area only once
|
# set expand of text area only once
|
||||||
@bind('ui::ticket::shown', (data) =>
|
@bind('ui::ticket::shown', (data) =>
|
||||||
|
@ -54,112 +68,75 @@ class ArticleViewItem extends App.Controller
|
||||||
@setSeeMore()
|
@setSeeMore()
|
||||||
)
|
)
|
||||||
|
|
||||||
# rerender, e. g. on language change
|
super
|
||||||
@bind('ui:rerender', =>
|
|
||||||
@force = true
|
|
||||||
@render(undefined)
|
|
||||||
)
|
|
||||||
|
|
||||||
# subscribe to changes
|
|
||||||
@subscribeId = App.TicketArticle.full(@ticket_article_id, @render, false, true)
|
|
||||||
|
|
||||||
release: =>
|
|
||||||
App.TicketArticle.unsubscribe(@subscribeId)
|
|
||||||
|
|
||||||
setHighlighter: =>
|
setHighlighter: =>
|
||||||
return if @el.is(':hidden')
|
return if @el.is(':hidden')
|
||||||
# use delay do no ui blocking
|
# use delay do no ui blocking
|
||||||
#@highligher.loadHighlights(@ticket_article_id)
|
#@highligher.loadHighlights(@object_id)
|
||||||
d = =>
|
d = =>
|
||||||
@highligher.loadHighlights(@ticket_article_id)
|
@highligher.loadHighlights(@object_id)
|
||||||
@delay(d, 200)
|
@delay(d, 200)
|
||||||
|
|
||||||
hasChanged: (article) =>
|
|
||||||
|
|
||||||
# if no last article exists, remember it and return true
|
|
||||||
if !@articleAttributesLastUpdate
|
|
||||||
@articleAttributesLastUpdate = {}
|
|
||||||
for item in @hasChangedAttributes
|
|
||||||
@articleAttributesLastUpdate[item] = article[item]
|
|
||||||
return true
|
|
||||||
|
|
||||||
# compare last and current article attributes
|
|
||||||
articleAttributesLastUpdateCheck = {}
|
|
||||||
for item in @hasChangedAttributes
|
|
||||||
articleAttributesLastUpdateCheck[item] = article[item]
|
|
||||||
diff = difference(@articleAttributesLastUpdate, articleAttributesLastUpdateCheck)
|
|
||||||
return false if !diff || _.isEmpty( diff )
|
|
||||||
@articleAttributesLastUpdate = articleAttributesLastUpdateCheck
|
|
||||||
true
|
|
||||||
|
|
||||||
render: (article) =>
|
render: (article) =>
|
||||||
|
|
||||||
# get articles
|
|
||||||
@article = App.TicketArticle.fullLocal(@ticket_article_id)
|
|
||||||
|
|
||||||
# set @el attributes
|
# set @el attributes
|
||||||
if !article
|
@el.addClass("ticket-article-item #{article.sender.name.toLowerCase()}")
|
||||||
@el.addClass("ticket-article-item #{@article.sender.name.toLowerCase()}")
|
@el.attr('data-id', article.id)
|
||||||
@el.attr('data-id', @article.id)
|
@el.attr('id', "article-#{article.id}")
|
||||||
@el.attr('id', "article-#{@article.id}")
|
|
||||||
|
|
||||||
# set internal change directly in dom, without rerender while article
|
|
||||||
if !article || ( @lastArticle && @lastArticle.internal isnt @article.internal )
|
|
||||||
if @article.internal is true
|
|
||||||
@el.addClass('is-internal')
|
|
||||||
else
|
|
||||||
@el.removeClass('is-internal')
|
|
||||||
|
|
||||||
# check if rerender is needed
|
|
||||||
if !@force && !@hasChanged(@article)
|
|
||||||
@lastArticle = @article.attributes()
|
|
||||||
return
|
|
||||||
@force = false
|
|
||||||
|
|
||||||
# prepare html body
|
# prepare html body
|
||||||
if @article.content_type is 'text/html'
|
if article.content_type is 'text/html'
|
||||||
if @article.sender.name is 'Agent'
|
if article.sender.name is 'Agent'
|
||||||
@article['html'] = App.Utils.signatureIdentify(@article.body, false, true)
|
article['html'] = App.Utils.signatureIdentify(article.body, false, true)
|
||||||
else
|
else
|
||||||
@article['html'] = App.Utils.signatureIdentify(@article.body)
|
article['html'] = App.Utils.signatureIdentify(article.body)
|
||||||
else
|
else
|
||||||
|
|
||||||
# client signature detection
|
# client signature detection
|
||||||
bodyHtml = App.Utils.text2html(@article.body)
|
bodyHtml = App.Utils.text2html(article.body)
|
||||||
@article['html'] = App.Utils.signatureIdentify(bodyHtml)
|
article['html'] = App.Utils.signatureIdentify(bodyHtml)
|
||||||
|
|
||||||
# if no signature detected or within frist 25 lines, check if signature got detected in backend
|
# if no signature detected or within frist 25 lines, check if signature got detected in backend
|
||||||
if @article['html'] is bodyHtml || (@article.preferences && @article.preferences.signature_detection < 25)
|
if article['html'] is bodyHtml || (article.preferences && article.preferences.signature_detection < 25)
|
||||||
signatureDetected = false
|
signatureDetected = false
|
||||||
body = @article.body
|
body = article.body
|
||||||
if @article.preferences && @article.preferences.signature_detection
|
if article.preferences && article.preferences.signature_detection
|
||||||
signatureDetected = '########SIGNATURE########'
|
signatureDetected = '########SIGNATURE########'
|
||||||
# coffeelint: disable=no_unnecessary_double_quotes
|
# coffeelint: disable=no_unnecessary_double_quotes
|
||||||
body = body.split("\n")
|
body = body.split("\n")
|
||||||
body.splice(@article.preferences.signature_detection, 0, signatureDetected)
|
body.splice(article.preferences.signature_detection, 0, signatureDetected)
|
||||||
body = body.join("\n")
|
body = body.join("\n")
|
||||||
# coffeelint: enable=no_unnecessary_double_quotes
|
# coffeelint: enable=no_unnecessary_double_quotes
|
||||||
if signatureDetected
|
if signatureDetected
|
||||||
body = App.Utils.textCleanup(body)
|
body = App.Utils.textCleanup(body)
|
||||||
@article['html'] = App.Utils.text2html(body)
|
article['html'] = App.Utils.text2html(body)
|
||||||
@article['html'] = @article['html'].replace(signatureDetected, '<span class="js-signatureMarker"></span>')
|
article['html'] = article['html'].replace(signatureDetected, '<span class="js-signatureMarker"></span>')
|
||||||
|
|
||||||
|
if article.sender.name is 'System'
|
||||||
|
@html App.view('ticket_zoom/article_view_system')(
|
||||||
|
ticket: @ticket
|
||||||
|
article: article
|
||||||
|
isCustomer: @isRole('Customer')
|
||||||
|
)
|
||||||
|
return
|
||||||
@html App.view('ticket_zoom/article_view')(
|
@html App.view('ticket_zoom/article_view')(
|
||||||
ticket: @ticket
|
ticket: @ticket
|
||||||
article: @article
|
article: article
|
||||||
isCustomer: @isRole('Customer')
|
isCustomer: @isRole('Customer')
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.WidgetAvatar(
|
new App.WidgetAvatar(
|
||||||
el: @$('.js-avatar')
|
el: @$('.js-avatar')
|
||||||
user_id: @article.created_by_id
|
object_id: article.created_by_id
|
||||||
size: 40
|
size: 40
|
||||||
)
|
)
|
||||||
|
|
||||||
new App.TicketZoomArticleActions(
|
new App.TicketZoomArticleActions(
|
||||||
el: @$('.js-article-actions')
|
el: @$('.js-article-actions')
|
||||||
ticket: @ticket
|
ticket: @ticket
|
||||||
article: @article
|
article: article
|
||||||
|
lastAttributres: @lastAttributres
|
||||||
)
|
)
|
||||||
|
|
||||||
# set see more
|
# set see more
|
||||||
|
@ -343,3 +320,6 @@ class ArticleViewItem extends App.Controller
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
false
|
false
|
||||||
|
|
||||||
|
remove: =>
|
||||||
|
@el.remove()
|
||||||
|
|
|
@ -1,24 +1,12 @@
|
||||||
class App.TicketZoomMeta extends App.Controller
|
class App.TicketZoomMeta extends App.ObserverController
|
||||||
constructor: ->
|
model: 'Ticket'
|
||||||
super
|
observe:
|
||||||
@render()
|
number: true
|
||||||
|
created_at: true
|
||||||
# rerender, e. g. on language change
|
escalation_time: true
|
||||||
@bind('ui:rerender', =>
|
|
||||||
@render()
|
|
||||||
)
|
|
||||||
|
|
||||||
render: (ticket) =>
|
render: (ticket) =>
|
||||||
if !ticket
|
|
||||||
ticket = App.Ticket.fullLocal(@ticket.id)
|
|
||||||
|
|
||||||
if !@subscribeId
|
|
||||||
@subscribeId = @ticket.subscribe(@render)
|
|
||||||
|
|
||||||
@html App.view('ticket_zoom/meta')(
|
@html App.view('ticket_zoom/meta')(
|
||||||
ticket: ticket
|
ticket: ticket
|
||||||
isCustomer: @isRole('Customer')
|
isCustomer: @isRole('Customer')
|
||||||
)
|
)
|
||||||
|
|
||||||
release: =>
|
|
||||||
App.Ticket.unsubscribe(@subscribeId)
|
|
||||||
|
|
|
@ -1,34 +1,13 @@
|
||||||
class App.TicketZoomTitle extends App.Controller
|
class App.TicketZoomTitle extends App.ObserverController
|
||||||
|
model: 'Ticket'
|
||||||
|
template: 'ticket_zoom/title'
|
||||||
|
observe:
|
||||||
|
title: true
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'blur .ticket-title-update': 'update'
|
'blur .ticket-title-update': 'update'
|
||||||
|
|
||||||
constructor: ->
|
renderPost: (object) =>
|
||||||
super
|
|
||||||
@render()
|
|
||||||
|
|
||||||
# rerender, e. g. on language change
|
|
||||||
@bind('ui:rerender', =>
|
|
||||||
@render()
|
|
||||||
)
|
|
||||||
|
|
||||||
render: (ticket) =>
|
|
||||||
if !ticket
|
|
||||||
ticket = App.Ticket.fullLocal(@ticket.id)
|
|
||||||
|
|
||||||
if !@subscribeId
|
|
||||||
@subscribeId = @ticket.subscribe(@render)
|
|
||||||
|
|
||||||
@title = ticket.title
|
|
||||||
|
|
||||||
# check if render is needed
|
|
||||||
if @lastTitle && @lastTitle is ticket.title
|
|
||||||
return
|
|
||||||
@lastTitle = ticket.title
|
|
||||||
|
|
||||||
@html App.view('ticket_zoom/title')(
|
|
||||||
ticket: ticket
|
|
||||||
)
|
|
||||||
|
|
||||||
@$('.ticket-title-update').ce({
|
@$('.ticket-title-update').ce({
|
||||||
mode: 'textonly'
|
mode: 'textonly'
|
||||||
multiline: false
|
multiline: false
|
||||||
|
@ -39,8 +18,8 @@ class App.TicketZoomTitle extends App.Controller
|
||||||
title = $(e.target).ceg() || ''
|
title = $(e.target).ceg() || ''
|
||||||
|
|
||||||
# update title
|
# update title
|
||||||
if title isnt @title
|
return if title is @lastAttributres.title
|
||||||
ticket = App.Ticket.find(@ticket.id)
|
ticket = App.Ticket.find(@object_id)
|
||||||
ticket.title = title
|
ticket.title = title
|
||||||
|
|
||||||
# reset article - should not be resubmited on next ticket update
|
# reset article - should not be resubmited on next ticket update
|
||||||
|
@ -54,6 +33,3 @@ class App.TicketZoomTitle extends App.Controller
|
||||||
App.TaskManager.touch(@task_key)
|
App.TaskManager.touch(@task_key)
|
||||||
|
|
||||||
App.Event.trigger('overview:fetch')
|
App.Event.trigger('overview:fetch')
|
||||||
|
|
||||||
release: =>
|
|
||||||
App.Ticket.unsubscribe(@subscribeId)
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class App.UserProfile extends App.Controller
|
||||||
|
|
||||||
new Object(
|
new Object(
|
||||||
el: elLocal.find('.js-object-container')
|
el: elLocal.find('.js-object-container')
|
||||||
user: user
|
object_id: user.id
|
||||||
task_key: @task_key
|
task_key: @task_key
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -65,19 +65,23 @@ class App.UserProfile extends App.Controller
|
||||||
genericObject: user
|
genericObject: user
|
||||||
)
|
)
|
||||||
|
|
||||||
class Object extends App.Controller
|
class Object extends App.ObserverController
|
||||||
|
model: 'User'
|
||||||
|
observeNot:
|
||||||
|
created_at: true
|
||||||
|
created_by_id: true
|
||||||
|
updated_at: true
|
||||||
|
updated_by_id: true
|
||||||
|
preferences: true
|
||||||
|
password: true
|
||||||
|
last_login: true
|
||||||
|
login_failed: true
|
||||||
|
source: true
|
||||||
|
image_source: true
|
||||||
|
|
||||||
events:
|
events:
|
||||||
'focusout [contenteditable]': 'update'
|
'focusout [contenteditable]': 'update'
|
||||||
|
|
||||||
constructor: (params) ->
|
|
||||||
super
|
|
||||||
|
|
||||||
# subscribe and reload data / fetch new data if triggered
|
|
||||||
@subscribeId = App.User.full(@user.id, @render, false, true)
|
|
||||||
|
|
||||||
release: =>
|
|
||||||
App.User.unsubscribe(@subscribeId)
|
|
||||||
|
|
||||||
render: (user) =>
|
render: (user) =>
|
||||||
|
|
||||||
# update taskbar with new meta data
|
# update taskbar with new meta data
|
||||||
|
@ -111,6 +115,12 @@ class Object extends App.Controller
|
||||||
maxlength: 250
|
maxlength: 250
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if user.organization_id
|
||||||
|
new Organization(
|
||||||
|
object_id: user.organization_id
|
||||||
|
el: @$('.js-organization')
|
||||||
|
)
|
||||||
|
|
||||||
# start action controller
|
# start action controller
|
||||||
showHistory = =>
|
showHistory = =>
|
||||||
new App.UserHistory(
|
new App.UserHistory(
|
||||||
|
@ -151,13 +161,24 @@ class Object extends App.Controller
|
||||||
update: (e) =>
|
update: (e) =>
|
||||||
name = $(e.target).attr('data-name')
|
name = $(e.target).attr('data-name')
|
||||||
value = $(e.target).html()
|
value = $(e.target).html()
|
||||||
user = App.User.find(@user.id)
|
user = App.User.find(@object_id)
|
||||||
if user[name] isnt value
|
if user[name] isnt value
|
||||||
|
@lastAttributres[name] = value
|
||||||
data = {}
|
data = {}
|
||||||
data[name] = value
|
data[name] = value
|
||||||
user.updateAttributes(data)
|
user.updateAttributes(data)
|
||||||
@log 'notice', 'update', name, value, user
|
@log 'notice', 'update', name, value, user
|
||||||
|
|
||||||
|
class Organization extends App.ObserverController
|
||||||
|
model: 'Organization'
|
||||||
|
observe:
|
||||||
|
name: true
|
||||||
|
|
||||||
|
render: (organization) =>
|
||||||
|
@html App.view('user_profile/organization')(
|
||||||
|
organization: organization
|
||||||
|
)
|
||||||
|
|
||||||
class Router extends App.ControllerPermanent
|
class Router extends App.ControllerPermanent
|
||||||
constructor: (params) ->
|
constructor: (params) ->
|
||||||
super
|
super
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
class App.WidgetAvatar extends App.Controller
|
class App.WidgetAvatar extends App.ObserverController
|
||||||
constructor: ->
|
model: 'User'
|
||||||
super
|
observe:
|
||||||
|
login: true
|
||||||
# subscribe and reload data / fetch new data if triggered
|
firstname: true
|
||||||
@subscribeId = App.User.full(@user_id, @render, false, true)
|
lastname: true
|
||||||
|
email: true
|
||||||
release: =>
|
|
||||||
App.User.unsubscribe(@subscribeId)
|
|
||||||
|
|
||||||
render: (user) =>
|
render: (user) =>
|
||||||
@html user.avatar @size, @position, undefined, false, false, @type
|
@html(user.avatar @size, @position, undefined, false, false, @type)
|
||||||
|
|
||||||
# start user popups
|
|
||||||
@userPopups(@position)
|
@userPopups(@position)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class App.Organization extends App.Model
|
class App.Organization extends App.Model
|
||||||
@configure 'Organization', 'name', 'shared', 'note', 'active', 'updated_at'
|
@configure 'Organization', 'name', 'shared', 'note', 'member_ids', 'active', 'updated_at'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/organizations'
|
@url: @apiPath + '/organizations'
|
||||||
@configure_attributes = [
|
@configure_attributes = [
|
||||||
|
@ -36,8 +36,8 @@ Mit **Organisationen** können Sie Kunden **gruppieren**. Dies hat u. a. zwei be
|
||||||
if data['member_ids']
|
if data['member_ids']
|
||||||
data['members'] = []
|
data['members'] = []
|
||||||
for user_id in data['member_ids']
|
for user_id in data['member_ids']
|
||||||
if App.User.exists( user_id )
|
if App.User.exists(user_id)
|
||||||
user = App.User.find( user_id )
|
user = App.User.find(user_id)
|
||||||
data['members'].push user
|
data['members'].push user
|
||||||
data
|
data
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="userList-entry">
|
||||||
|
<%- @user.avatar("40") %>
|
||||||
|
<a href="<%- @user.uiUrl() %>" class="userList-name user-popover" data-id="<%- @user.id %>"><%= @user.displayName() %></a>
|
||||||
|
</div>
|
|
@ -27,13 +27,6 @@
|
||||||
<% if @organization.members: %>
|
<% if @organization.members: %>
|
||||||
<div class="profile-section profile-memberSection">
|
<div class="profile-section profile-memberSection">
|
||||||
<label><%- @T('Members') %></label>
|
<label><%- @T('Members') %></label>
|
||||||
<div class="userList">
|
<div class="userList js-userList"></div>
|
||||||
<% for user in @organization.members: %>
|
|
||||||
<div class="userList-entry">
|
|
||||||
<%- user.avatar("40") %>
|
|
||||||
<a href="<%- user.uiUrl() %>" class="userList-name user-popover" data-id="<%- user.id %>"><%= user.displayName() %></a>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
|
@ -32,7 +32,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="article-content zIndex-5 bubble-gap">
|
<div class="article-content bubble-gap">
|
||||||
<div class="internal-border">
|
<div class="internal-border">
|
||||||
|
|
||||||
<div class="input form-group">
|
<div class="input form-group">
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="article-content zIndex-1">
|
<div class="article-content">
|
||||||
<% if @article.sender.name isnt 'Agent': %>
|
<% if @article.sender.name isnt 'Agent': %>
|
||||||
<% position = 'left' %>
|
<% position = 'left' %>
|
||||||
<% else: %>
|
<% else: %>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="small task-subline">
|
||||||
|
"<%= @article.subject %>" -> "<%= @article.to %>"
|
||||||
|
</div>
|
|
@ -1 +1 @@
|
||||||
<div contenteditable="true" class="ticket-title-update" data-placeholder="<%- @Ti('Enter Title...') %>"><%= @ticket.title %></div>
|
<div contenteditable="true" class="ticket-title-update" data-placeholder="<%- @Ti('Enter Title...') %>"><%= @object.title %></div>
|
|
@ -3,7 +3,7 @@
|
||||||
<%- @user.avatar("80") %>
|
<%- @user.avatar("80") %>
|
||||||
<h1><%= @user.displayName() %></h1>
|
<h1><%= @user.displayName() %></h1>
|
||||||
<% if @user.organization: %>
|
<% if @user.organization: %>
|
||||||
<div class="profile-organization"><a href="<%- @user.organization.uiUrl() %>"><%= @user.organization.displayName() %></a></div>
|
<div class="profile-organization js-organization"></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile-section">
|
<div class="profile-section">
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<a href="<%- @organization.uiUrl() %>"><%= @organization.displayName() %></a>
|
|
@ -23,7 +23,10 @@ class Observer::Ticket::ArticleChanges < ActiveRecord::Observer
|
||||||
end
|
end
|
||||||
|
|
||||||
# save ticket
|
# save ticket
|
||||||
return if !changed
|
if !changed
|
||||||
|
record.ticket.touch
|
||||||
|
return
|
||||||
|
end
|
||||||
record.ticket.save
|
record.ticket.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue