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
|
||||
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')
|
||||
if 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
|
||||
return if !@isRole('Agent')
|
||||
|
||||
@el.find('div.user-popover, span.user-popover').bind('click', (e) =>
|
||||
@$('div.user-popover, span.user-popover').bind('click', (e) =>
|
||||
id = $(e.target).data('id')
|
||||
if 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
|
||||
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')
|
||||
if id
|
||||
organization = App.Organization.find(id)
|
||||
|
|
|
@ -1068,3 +1068,83 @@ class App.CollectionController extends App.Controller
|
|||
|
||||
onRemoved: (id) ->
|
||||
# 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)
|
||||
|
|
|
@ -59,8 +59,8 @@ class App.DashboardActivityStream extends App.Controller
|
|||
item: item
|
||||
))
|
||||
new App.WidgetAvatar(
|
||||
el: html.find('.js-avatar')
|
||||
user_id: item.created_by_id
|
||||
size: 40
|
||||
el: html.find('.js-avatar')
|
||||
object_id: item.created_by_id
|
||||
size: 40
|
||||
)
|
||||
html
|
|
@ -125,9 +125,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
# only start avatar widget on existing session
|
||||
if App.Session.get('id')
|
||||
new App.WidgetAvatar(
|
||||
el: @$('.js-avatar')
|
||||
user_id: App.Session.get('id')
|
||||
type: 'personal'
|
||||
el: @$('.js-avatar')
|
||||
object_id: App.Session.get('id')
|
||||
type: 'personal'
|
||||
)
|
||||
|
||||
renderResult: (result = []) =>
|
||||
|
|
|
@ -49,9 +49,9 @@ class App.OrganizationProfile extends App.Controller
|
|||
))
|
||||
|
||||
new Object(
|
||||
el: elLocal.find('.js-object-container')
|
||||
organization: organization
|
||||
task_key: @task_key
|
||||
el: elLocal.find('.js-object-container')
|
||||
object_id: organization.id
|
||||
task_key: @task_key
|
||||
)
|
||||
|
||||
new App.TicketStats(
|
||||
|
@ -65,19 +65,20 @@ class App.OrganizationProfile extends App.Controller
|
|||
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:
|
||||
'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) =>
|
||||
|
||||
# update taskbar with new meta data
|
||||
|
@ -111,6 +112,17 @@ class Object extends App.Controller
|
|||
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
|
||||
showHistory = ->
|
||||
new App.OrganizationHistory(
|
||||
|
@ -151,13 +163,26 @@ class Object extends App.Controller
|
|||
update: (e) =>
|
||||
name = $(e.target).attr('data-name')
|
||||
value = $(e.target).html()
|
||||
org = App.Organization.find(@organization.id)
|
||||
org = App.Organization.find(@object_id)
|
||||
if org[name] isnt value
|
||||
@lastAttributres[name] = value
|
||||
data = {}
|
||||
data[name] = value
|
||||
org.updateAttributes(data)
|
||||
@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
|
||||
constructor: (params) ->
|
||||
|
|
|
@ -300,15 +300,15 @@ class App.TicketZoom extends App.Controller
|
|||
)
|
||||
|
||||
new App.TicketZoomTitle(
|
||||
ticket: @ticket
|
||||
object_id: @ticket.id
|
||||
overview_id: @overview_id
|
||||
el: elLocal.find('.ticket-title')
|
||||
task_key: @task_key
|
||||
)
|
||||
|
||||
new App.TicketZoomMeta(
|
||||
ticket: @ticket
|
||||
el: elLocal.find('.ticket-meta')
|
||||
object_id: @ticket.id
|
||||
el: elLocal.find('.ticket-meta')
|
||||
)
|
||||
|
||||
new App.TicketZoomAttributeBar(
|
||||
|
@ -352,9 +352,9 @@ class App.TicketZoom extends App.Controller
|
|||
else
|
||||
el = @el
|
||||
new App.WidgetAvatar(
|
||||
el: el.find('.ticketZoom-header .js-avatar')
|
||||
user_id: @ticket.customer_id
|
||||
size: 50
|
||||
el: el.find('.ticketZoom-header .js-avatar')
|
||||
object_id: @ticket.customer_id
|
||||
size: 50
|
||||
)
|
||||
@sidebar = new App.TicketZoomSidebar(
|
||||
el: el.find('.tabsSidebar')
|
||||
|
|
|
@ -23,7 +23,7 @@ class App.TicketZoomArticleActions extends App.Controller
|
|||
else
|
||||
@html ''
|
||||
|
||||
publicInternal: (e) ->
|
||||
publicInternal: (e) =>
|
||||
e.preventDefault()
|
||||
articleContainer = $(e.target).closest('.ticket-article-item')
|
||||
article_id = $(e.target).parents('[data-id]').data('id')
|
||||
|
@ -33,9 +33,8 @@ class App.TicketZoomArticleActions extends App.Controller
|
|||
internal = true
|
||||
if article.internal == true
|
||||
internal = false
|
||||
article.updateAttributes(
|
||||
internal: internal
|
||||
)
|
||||
@lastAttributres.internal = internal
|
||||
article.updateAttributes(internal: internal)
|
||||
|
||||
# runntime update
|
||||
if internal
|
||||
|
|
|
@ -175,11 +175,10 @@ class App.TicketZoomArticleNew extends App.Controller
|
|||
@setArticleType(@type)
|
||||
|
||||
new App.WidgetAvatar(
|
||||
el: @$('.js-avatar')
|
||||
user_id: App.Session.get('id')
|
||||
size: 40
|
||||
position: 'right'
|
||||
class: 'zIndex-5'
|
||||
el: @$('.js-avatar')
|
||||
object_id: App.Session.get('id')
|
||||
size: 40
|
||||
position: 'right'
|
||||
)
|
||||
|
||||
configure_attributes = [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class App.TicketZoomArticleView extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@article_controller = {}
|
||||
@articleController = {}
|
||||
@run()
|
||||
|
||||
execute: (params) =>
|
||||
|
@ -11,20 +11,39 @@ class App.TicketZoomArticleView extends App.Controller
|
|||
run: =>
|
||||
all = []
|
||||
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>')
|
||||
@article_controller[ticket_article_id] = new ArticleViewItem(
|
||||
ticket: @ticket
|
||||
ticket_article_id: ticket_article_id
|
||||
el: el
|
||||
ui: @ui
|
||||
highligher: @highligher
|
||||
@articleController[controllerKey] = new ArticleViewItem(
|
||||
ticket: @ticket
|
||||
object_id: ticket_article_id
|
||||
el: el
|
||||
ui: @ui
|
||||
highligher: @highligher
|
||||
)
|
||||
all.push el
|
||||
@el.append(all)
|
||||
|
||||
class ArticleViewItem extends App.Controller
|
||||
hasChangedAttributes: ['from', 'to', 'cc', 'subject', 'body', 'preferences']
|
||||
# check elements to remove
|
||||
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:
|
||||
'.textBubble-content': 'textBubbleContent'
|
||||
|
@ -36,12 +55,7 @@ class ArticleViewItem extends App.Controller
|
|||
'click .js-unfold': 'unfold'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@seeMore = false
|
||||
@force = true
|
||||
|
||||
@render()
|
||||
|
||||
# set expand of text area only once
|
||||
@bind('ui::ticket::shown', (data) =>
|
||||
|
@ -54,112 +68,75 @@ class ArticleViewItem extends App.Controller
|
|||
@setSeeMore()
|
||||
)
|
||||
|
||||
# rerender, e. g. on language change
|
||||
@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)
|
||||
super
|
||||
|
||||
setHighlighter: =>
|
||||
return if @el.is(':hidden')
|
||||
# use delay do no ui blocking
|
||||
#@highligher.loadHighlights(@ticket_article_id)
|
||||
#@highligher.loadHighlights(@object_id)
|
||||
d = =>
|
||||
@highligher.loadHighlights(@ticket_article_id)
|
||||
@highligher.loadHighlights(@object_id)
|
||||
@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) =>
|
||||
|
||||
# get articles
|
||||
@article = App.TicketArticle.fullLocal(@ticket_article_id)
|
||||
|
||||
# set @el attributes
|
||||
if !article
|
||||
@el.addClass("ticket-article-item #{@article.sender.name.toLowerCase()}")
|
||||
@el.attr('data-id', @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
|
||||
@el.addClass("ticket-article-item #{article.sender.name.toLowerCase()}")
|
||||
@el.attr('data-id', article.id)
|
||||
@el.attr('id', "article-#{article.id}")
|
||||
|
||||
# prepare html body
|
||||
if @article.content_type is 'text/html'
|
||||
if @article.sender.name is 'Agent'
|
||||
@article['html'] = App.Utils.signatureIdentify(@article.body, false, true)
|
||||
if article.content_type is 'text/html'
|
||||
if article.sender.name is 'Agent'
|
||||
article['html'] = App.Utils.signatureIdentify(article.body, false, true)
|
||||
else
|
||||
@article['html'] = App.Utils.signatureIdentify(@article.body)
|
||||
article['html'] = App.Utils.signatureIdentify(article.body)
|
||||
else
|
||||
|
||||
# client signature detection
|
||||
bodyHtml = App.Utils.text2html(@article.body)
|
||||
@article['html'] = App.Utils.signatureIdentify(bodyHtml)
|
||||
bodyHtml = App.Utils.text2html(article.body)
|
||||
article['html'] = App.Utils.signatureIdentify(bodyHtml)
|
||||
|
||||
# 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
|
||||
body = @article.body
|
||||
if @article.preferences && @article.preferences.signature_detection
|
||||
body = article.body
|
||||
if article.preferences && article.preferences.signature_detection
|
||||
signatureDetected = '########SIGNATURE########'
|
||||
# coffeelint: disable=no_unnecessary_double_quotes
|
||||
body = body.split("\n")
|
||||
body.splice(@article.preferences.signature_detection, 0, signatureDetected)
|
||||
body.splice(article.preferences.signature_detection, 0, signatureDetected)
|
||||
body = body.join("\n")
|
||||
# coffeelint: enable=no_unnecessary_double_quotes
|
||||
if signatureDetected
|
||||
body = App.Utils.textCleanup(body)
|
||||
@article['html'] = App.Utils.text2html(body)
|
||||
@article['html'] = @article['html'].replace(signatureDetected, '<span class="js-signatureMarker"></span>')
|
||||
article['html'] = App.Utils.text2html(body)
|
||||
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')(
|
||||
ticket: @ticket
|
||||
article: @article
|
||||
article: article
|
||||
isCustomer: @isRole('Customer')
|
||||
)
|
||||
|
||||
new App.WidgetAvatar(
|
||||
el: @$('.js-avatar')
|
||||
user_id: @article.created_by_id
|
||||
size: 40
|
||||
el: @$('.js-avatar')
|
||||
object_id: article.created_by_id
|
||||
size: 40
|
||||
)
|
||||
|
||||
new App.TicketZoomArticleActions(
|
||||
el: @$('.js-article-actions')
|
||||
ticket: @ticket
|
||||
article: @article
|
||||
el: @$('.js-article-actions')
|
||||
ticket: @ticket
|
||||
article: article
|
||||
lastAttributres: @lastAttributres
|
||||
)
|
||||
|
||||
# set see more
|
||||
|
@ -343,3 +320,6 @@ class ArticleViewItem extends App.Controller
|
|||
return false
|
||||
return true
|
||||
false
|
||||
|
||||
remove: =>
|
||||
@el.remove()
|
||||
|
|
|
@ -1,24 +1,12 @@
|
|||
class App.TicketZoomMeta extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@render()
|
||||
|
||||
# rerender, e. g. on language change
|
||||
@bind('ui:rerender', =>
|
||||
@render()
|
||||
)
|
||||
class App.TicketZoomMeta extends App.ObserverController
|
||||
model: 'Ticket'
|
||||
observe:
|
||||
number: true
|
||||
created_at: true
|
||||
escalation_time: true
|
||||
|
||||
render: (ticket) =>
|
||||
if !ticket
|
||||
ticket = App.Ticket.fullLocal(@ticket.id)
|
||||
|
||||
if !@subscribeId
|
||||
@subscribeId = @ticket.subscribe(@render)
|
||||
|
||||
@html App.view('ticket_zoom/meta')(
|
||||
ticket: ticket
|
||||
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:
|
||||
'blur .ticket-title-update': 'update'
|
||||
|
||||
constructor: ->
|
||||
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
|
||||
)
|
||||
|
||||
renderPost: (object) =>
|
||||
@$('.ticket-title-update').ce({
|
||||
mode: 'textonly'
|
||||
multiline: false
|
||||
|
@ -39,21 +18,18 @@ class App.TicketZoomTitle extends App.Controller
|
|||
title = $(e.target).ceg() || ''
|
||||
|
||||
# update title
|
||||
if title isnt @title
|
||||
ticket = App.Ticket.find(@ticket.id)
|
||||
ticket.title = title
|
||||
return if title is @lastAttributres.title
|
||||
ticket = App.Ticket.find(@object_id)
|
||||
ticket.title = title
|
||||
|
||||
# reset article - should not be resubmited on next ticket update
|
||||
ticket.article = undefined
|
||||
# reset article - should not be resubmited on next ticket update
|
||||
ticket.article = undefined
|
||||
|
||||
ticket.save()
|
||||
ticket.save()
|
||||
|
||||
App.TaskManager.mute(@task_key)
|
||||
App.TaskManager.mute(@task_key)
|
||||
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@task_key)
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@task_key)
|
||||
|
||||
App.Event.trigger('overview:fetch')
|
||||
|
||||
release: =>
|
||||
App.Ticket.unsubscribe(@subscribeId)
|
||||
App.Event.trigger('overview:fetch')
|
||||
|
|
|
@ -49,9 +49,9 @@ class App.UserProfile extends App.Controller
|
|||
))
|
||||
|
||||
new Object(
|
||||
el: elLocal.find('.js-object-container')
|
||||
user: user
|
||||
task_key: @task_key
|
||||
el: elLocal.find('.js-object-container')
|
||||
object_id: user.id
|
||||
task_key: @task_key
|
||||
)
|
||||
|
||||
new App.TicketStats(
|
||||
|
@ -65,19 +65,23 @@ class App.UserProfile extends App.Controller
|
|||
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:
|
||||
'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) =>
|
||||
|
||||
# update taskbar with new meta data
|
||||
|
@ -111,6 +115,12 @@ class Object extends App.Controller
|
|||
maxlength: 250
|
||||
})
|
||||
|
||||
if user.organization_id
|
||||
new Organization(
|
||||
object_id: user.organization_id
|
||||
el: @$('.js-organization')
|
||||
)
|
||||
|
||||
# start action controller
|
||||
showHistory = =>
|
||||
new App.UserHistory(
|
||||
|
@ -151,13 +161,24 @@ class Object extends App.Controller
|
|||
update: (e) =>
|
||||
name = $(e.target).attr('data-name')
|
||||
value = $(e.target).html()
|
||||
user = App.User.find(@user.id)
|
||||
user = App.User.find(@object_id)
|
||||
if user[name] isnt value
|
||||
@lastAttributres[name] = value
|
||||
data = {}
|
||||
data[name] = value
|
||||
user.updateAttributes(data)
|
||||
@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
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
class App.WidgetAvatar extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# subscribe and reload data / fetch new data if triggered
|
||||
@subscribeId = App.User.full(@user_id, @render, false, true)
|
||||
|
||||
release: =>
|
||||
App.User.unsubscribe(@subscribeId)
|
||||
class App.WidgetAvatar extends App.ObserverController
|
||||
model: 'User'
|
||||
observe:
|
||||
login: true
|
||||
firstname: true
|
||||
lastname: true
|
||||
email: true
|
||||
|
||||
render: (user) =>
|
||||
@html user.avatar @size, @position, undefined, false, false, @type
|
||||
|
||||
# start user popups
|
||||
@html(user.avatar @size, @position, undefined, false, false, @type)
|
||||
@userPopups(@position)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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
|
||||
@url: @apiPath + '/organizations'
|
||||
@configure_attributes = [
|
||||
|
@ -36,8 +36,8 @@ Mit **Organisationen** können Sie Kunden **gruppieren**. Dies hat u. a. zwei be
|
|||
if data['member_ids']
|
||||
data['members'] = []
|
||||
for user_id in data['member_ids']
|
||||
if App.User.exists( user_id )
|
||||
user = App.User.find( user_id )
|
||||
if App.User.exists(user_id)
|
||||
user = App.User.find(user_id)
|
||||
data['members'].push user
|
||||
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: %>
|
||||
<div class="profile-section profile-memberSection">
|
||||
<label><%- @T('Members') %></label>
|
||||
<div class="userList">
|
||||
<% 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 class="userList js-userList"></div>
|
||||
</div>
|
||||
<% end %>
|
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="article-content zIndex-5 bubble-gap">
|
||||
<div class="article-content bubble-gap">
|
||||
<div class="internal-border">
|
||||
|
||||
<div class="input form-group">
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="article-content zIndex-1">
|
||||
<div class="article-content">
|
||||
<% if @article.sender.name isnt 'Agent': %>
|
||||
<% position = 'left' %>
|
||||
<% 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") %>
|
||||
<h1><%= @user.displayName() %></h1>
|
||||
<% 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 %>
|
||||
</div>
|
||||
<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
|
||||
|
||||
# save ticket
|
||||
return if !changed
|
||||
if !changed
|
||||
record.ticket.touch
|
||||
return
|
||||
end
|
||||
record.ticket.save
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue