Merge branch 'develop' of github.com:martini/zammad into develop

This commit is contained in:
rkaldung 2015-01-21 11:38:02 +01:00
commit ee3719ab25
66 changed files with 4071 additions and 797 deletions

View file

@ -233,7 +233,8 @@ class App.Controller extends Spine.Controller
trigger: 'hover'
container: 'body'
html: true
delay: { show: 400, hide: 800 }
animation: false
delay: 100
placement: position
title: ->
ticket_id = $(@).data('id')
@ -270,7 +271,8 @@ class App.Controller extends Spine.Controller
trigger: 'hover'
container: 'body'
html: true
delay: { show: 400, hide: 800 }
animation: false
delay: 100
placement: "auto #{position}"
title: ->
user_id = $(@).data('id')
@ -326,7 +328,8 @@ class App.Controller extends Spine.Controller
trigger: 'hover'
container: 'body'
html: true
delay: { show: 400, hide: 800 }
animation: false
delay: 100
placement: "auto #{position}"
title: ->
organization_id = $(@).data('id')
@ -379,7 +382,8 @@ class App.Controller extends Spine.Controller
trigger: 'hover'
container: 'body'
html: true
delay: { show: 500, hide: 5200 }
animation: false
delay: 100
placement: "auto #{data.position}"
title: ->
$(@).find('[title="*"]').val()
@ -496,6 +500,7 @@ class App.ControllerModal extends App.Controller
head: '?'
buttonClass: 'btn--success'
centerButtons: []
container: null
options = _.extend( defaults, options )
@ -522,10 +527,14 @@ class App.ControllerModal extends App.Controller
if @content
@body.html @content
if @container
@el.addClass('modal--local')
@el.modal
keyboard: @keyboard
show: true
backdrop: @backdrop
container: @container
.on
'show.bs.modal': @onShow
'shown.bs.modal': @onShown

View file

@ -87,6 +87,9 @@ class App.TicketCreate extends App.Controller
# update form
@el.find('[name="formSenderType"]').val(type)
# force changing signature
@el.find('[name="group_id"]').trigger('change')
meta: =>
text = ''
if @articleAttributes
@ -168,9 +171,14 @@ class App.TicketCreate extends App.Controller
# reset owner
t.owner_id = 0
t.customer_id_autocompletion = a.from
t.customer_id_completion = a.from
t.subject = a.subject || t.title
# convert non text/html from text 2 html
if a.content_type.match(/\/html/)
t.body = a.body
else
t.body = App.Utils.text2html( a.body )
# render page
@render( options: t )
@ -220,6 +228,44 @@ class App.TicketCreate extends App.Controller
# replace new option list
form.find('[name="' + fieldNameToChange + '"]').closest('.form-group').replaceWith( newElement )
signatureChanges = (params, attribute, attributes, classname, form, ui) =>
if attribute && attribute.name is 'group_id'
signature = undefined
if params['group_id']
group = App.Group.find( params['group_id'] )
if group && group.signature_id
signature = App.Signature.find( group.signature_id )
# check if signature need to be added
type = @$('[name="formSenderType"]').val()
if signature isnt undefined && signature.body && type is 'email-out'
signatureFinished = App.Utils.text2html(
App.Utils.replaceTags( signature.body, { user: App.Session.get() } )
)
# get current body
body = @$('[data-name="body"]').html() || ''
if App.Utils.signatureCheck( body, signatureFinished )
# if signature has changed, replace it
signature_id = @$('[data-signature=true]').data('signature-id')
if signature_id && signature_id.toString() isnt signature.id.toString()
# remove old signature
@$('[data-signature="true"]').remove()
body = @$('[data-name="body"]').html() || ''
if !App.Utils.lastLineEmpty(body)
body = body + '<br>'
body = body + "<div data-signature=\"true\" data-signature-id=\"#{signature.id}\">#{signatureFinished}</div>"
@$('[data-name="body"]').html(body)
# remove old signature
else
@$('[data-name="body"]').find('[data-signature=true]').remove()
new App.ControllerForm(
el: @el.find('.ticket-form-top')
form_id: @form_id
@ -228,7 +274,8 @@ class App.TicketCreate extends App.Controller
events:
'change [name=customer_id]': @localUserInfo
handlers: [
formChanges
formChanges,
signatureChanges,
]
filter: @form_meta.filter
autofocus: true
@ -250,7 +297,8 @@ class App.TicketCreate extends App.Controller
events:
'change [name=customer_id]': @localUserInfo
handlers: [
formChanges
formChanges,
signatureChanges,
]
filter: @form_meta.filter
params: params
@ -264,7 +312,8 @@ class App.TicketCreate extends App.Controller
events:
'change [name=customer_id]': @localUserInfo
handlers: [
formChanges
formChanges,
signatureChanges,
]
filter: @form_meta.filter
params: params
@ -330,7 +379,7 @@ class App.TicketCreate extends App.Controller
if sender.name is 'Customer'
params['article'] = {
to: (group && group.name) || ''
from: params.customer_id_autocompletion
from: params.customer_id_completion
cc: params.cc
subject: params.subject
body: params.body
@ -342,7 +391,7 @@ class App.TicketCreate extends App.Controller
else
params['article'] = {
from: (group && group.name) || ''
to: params.customer_id_autocompletion
to: params.customer_id_completion
cc: params.cc
subject: params.subject
body: params.body
@ -467,6 +516,7 @@ class Sidebar extends App.Controller
icon: 'person'
actions: [
{
title: 'Edit Customer'
name: 'Edit Customer'
class: 'glyphicon glyphicon-edit'
callback: editCustomer

View file

@ -11,9 +11,9 @@ App.Config.set( 'layout_ref', Index, 'Routes' )
class Content extends App.ControllerContent
events:
'hide.bs.dropdown .js-recipientDropdown': 'hideOrganisationMembers'
'click .js-organisation': 'showOrganisationMembers'
'click .js-back': 'hideOrganisationMembers'
'hide.bs.dropdown .js-recipientDropdown': 'hideOrganizationMembers'
'click .js-organization': 'showOrganizationMembers'
'click .js-back': 'hideOrganizationMembers'
constructor: ->
super
@ -46,21 +46,21 @@ class Content extends App.ControllerContent
render: ->
@html App.view('layout_ref/content')()
showOrganisationMembers: (e) =>
showOrganizationMembers: (e) =>
e.stopPropagation()
listEntry = $(e.currentTarget)
organisationId = listEntry.data('organisation-id')
organizationId = listEntry.data('organization-id')
@recipientList = @$('.recipientList')
@organisationList = @$("##{ organisationId }")
@organizationList = @$("##{ organizationId }")
# move organisation-list to the right and slide it in
# move organization-list to the right and slide it in
$.Velocity.hook(@organisationList, 'translateX', '100%')
@organisationList.removeClass('hide')
$.Velocity.hook(@organizationList, 'translateX', '100%')
@organizationList.removeClass('hide')
@organisationList.velocity
@organizationList.velocity
properties:
translateX: 0
options:
@ -73,12 +73,12 @@ class Content extends App.ControllerContent
translateX: '-100%'
options:
speed: 300
complete: => @recipientList.height(@organisationList.height())
complete: => @recipientList.height(@organizationList.height())
hideOrganisationMembers: (e) =>
hideOrganizationMembers: (e) =>
e && e.stopPropagation()
return if !@organisationList
return if !@organizationList
# fade list back in
@ -92,18 +92,20 @@ class Content extends App.ControllerContent
@recipientList.height('')
# slide out organisation-list and hide it
@organisationList.velocity
# slide out organization-list and hide it
@organizationList.velocity
properties:
translateX: '100%'
options:
speed: 300
complete: => @organisationList.addClass('hide')
complete: => @organizationList.addClass('hide')
App.Config.set( 'layout_ref/content', Content, 'Routes' )
class CommunicationOverview extends App.ControllerContent
events:
'click .js-unfold': 'unfold'
constructor: ->
super
@ -116,9 +118,38 @@ class CommunicationOverview extends App.ControllerContent
scrollHolder = pageHeader.scrollParent()
scrollBody = scrollHolder.get(0).scrollHeight - scrollHolder.height()
unfold: (e) ->
container = $(e.currentTarget).parents('.textBubble-content')
overflowContainer = container.find('.textBubble-overflowContainer')
overflowContainer.velocity
properties:
opacity: 0
options:
duration: 300
container.velocity
properties:
height: container.attr('data-height')
options:
duration: 300
complete: -> overflowContainer.addClass('hide');
render: ->
@html App.view('layout_ref/communication_overview')()
# set see more options
previewHeight = 240
@$('.textBubble-content').each( (index) ->
bubble = $( @ )
heigth = bubble.height()
if heigth > (previewHeight + 30)
bubble.attr('data-height', heigth)
bubble.css('height', "#{previewHeight}px")
else
bubble.parent().find('.textBubble-overflowContainer').addClass('hide')
)
App.Config.set( 'layout_ref/communication_overview', CommunicationOverview, 'Routes' )
@ -133,7 +164,7 @@ class LayoutRefCommunicationReply extends App.ControllerContent
'.attachmentUpload': 'attachmentUpload'
'.attachmentUpload-progressBar':'progressBar'
'.js-percentage': 'progressText'
'.text-bubble': 'textBubble'
'.textBubble': 'textBubble'
events:
'focus .js-textarea': 'open_textarea'
@ -713,4 +744,37 @@ class RichText extends App.ControllerContent
App.Config.set( 'layout_ref/richtext', RichText, 'Routes' )
class LocalModalRef extends App.ControllerContent
constructor: ->
super
@render()
render: ->
@html App.view('layout_ref/local_modal')()
App.Config.set( 'layout_ref/local_modal', LocalModalRef, 'Routes' )
class loadingPlaceholderRef extends App.ControllerContent
constructor: ->
super
@render()
render: ->
@html App.view('layout_ref/loading_placeholder')()
App.Config.set( 'layout_ref/loading_placeholder', loadingPlaceholderRef, 'Routes' )
class insufficientRightsRef extends App.ControllerContent
constructor: ->
super
@render()
render: ->
@html App.view('layout_ref/insufficient_rights')()
App.Config.set( 'layout_ref/insufficient_rights', insufficientRightsRef, 'Routes' )
App.Config.set( 'LayoutRef', { prio: 1700, parent: '#current_user', name: 'Layout Reference', target: '#layout_ref', role: [ 'Admin' ] }, 'NavBarRight' )

View file

@ -173,9 +173,9 @@ class App.Navigation extends App.Controller
data =
display: "#{organization.displayName()}"
id: organization.id
class: "organisation organization-popover"
class: "organization organization-popover"
url: organization.uiUrl()
iconClass: "organisation"
iconClass: "organization"
area.result.push data
@renderResult(result)

View file

@ -29,6 +29,7 @@ class App.TaskbarWidget extends App.Controller
data =
url: '#'
id: false
iconClass: 'loading dot'
title: App.i18n.translateInline('Loading...')
head: App.i18n.translateInline('Loading...')
worker = App.TaskManager.worker( task.key )

View file

@ -8,7 +8,7 @@ class App.TicketCustomer extends App.ControllerModal
@button = true
configure_attributes = [
{ name: 'customer_id', display: 'Customer', tag: 'user_autocompletion', null: false, placeholder: 'Enter Person or Organisation/Company', minLengt: 2, disableCreateUser: true },
{ name: 'customer_id', display: 'Customer', tag: 'user_autocompletion', null: false, placeholder: 'Enter Person or Organization/Company', minLengt: 2, disableCreateUser: true },
]
controller = new App.ControllerForm(

View file

@ -482,6 +482,7 @@ class Table extends App.ControllerContent
new App.OverviewSettings(
overview_id: @overview.id
view_mode: @view_mode
container: @el
)
class App.OverviewSettings extends App.ControllerModal

View file

@ -21,7 +21,6 @@ class App.TicketZoom extends App.Controller
@form_meta = undefined
@ticket_id = params.ticket_id
@article_id = params.article_id
@signature = undefined
@key = 'ticket::' + @ticket_id
cache = App.Store.get( @key )
@ -44,15 +43,25 @@ class App.TicketZoom extends App.Controller
)
meta: =>
# default attributes
meta =
url: @url()
id: @ticket_id
iconClass: "priority"
# set icon and tilte if defined
if @taskIconClass
meta.iconClass = @taskIconClass
if @taskHead
meta.head = @taskHead
# set icon and title based on ticket
if @ticket
@ticket = App.Ticket.fullLocal( @ticket.id )
meta.head = @ticket.title
meta.title = '#' + @ticket.number + ' - ' + @ticket.title
meta.class = "level-#{@ticket.level()}"
meta.iconClass = 'priority'
meta
url: =>
@ -67,6 +76,7 @@ class App.TicketZoom extends App.Controller
@positionPageHeaderStop()
changed: =>
return false if !@ticket
formCurrent = @formParam( @el.find('.edit') )
ticket = App.Ticket.find(@ticket_id).attributes()
modelDiff = @getDiff( ticket, formCurrent )
@ -115,11 +125,31 @@ class App.TicketZoom extends App.Controller
# do not close window if request is aborted
return if status is 'abort'
# do not close window on network error but if object is not found
return if status is 'error' && error isnt 'Not Found'
# show error message
if xhr.status is 401 || error is 'Unauthorized'
@taskHead = '» ' + App.i18n.translateInline('Unauthorized') + ' «'
@taskIconClass = 'error'
@html App.view('generic/error/unauthorized')( objectName: 'Ticket' )
else if xhr.status is 404 || error is 'Not Found'
@taskHead = '» ' + App.i18n.translateInline('Not Found') + ' «'
@taskIconClass = 'error'
@html App.view('generic/error/not_found')( objectName: 'Ticket' )
else
@taskHead = '» ' + App.i18n.translateInline('Error') + ' «'
@taskIconClass = 'error'
# remove task
App.TaskManager.remove( @task_key )
status = xhr.status
detail = xhr.responseText
if !status && !detail
detail = 'General communication error, maybe internet is not available!'
@html App.view('generic/error/generic')(
status: status
detail: detail
objectName: 'Ticket'
)
# update current task title
App.Event.trigger 'task:render'
)
@ -137,9 +167,6 @@ class App.TicketZoom extends App.Controller
# get edit form attributes
@form_meta = data.form_meta
# get signature
@signature = data.signature
# load assets
App.Collection.loadAssets( data.assets )
@ -316,7 +343,10 @@ class App.TicketZoom extends App.Controller
showTicketHistory = =>
new App.TicketHistory( ticket_id: @ticket.id )
showTicketMerge = =>
new App.TicketMerge( ticket: @ticket, task_key: @task_key )
new App.TicketMerge
ticket: @ticket
task_key: @task_key
container: @el
changeCustomer = (e, el) =>
new App.TicketCustomer(
ticket: @ticket
@ -423,6 +453,18 @@ class App.TicketZoom extends App.Controller
ui: @
)
# set see more options
previewHeight = 270
@$('.textBubble-content').each( (index) ->
bubble = $( @ )
heigth = bubble.height()
if heigth > (previewHeight + 30)
bubble.attr('data-height', heigth)
bubble.css('height', "#{previewHeight}px")
else
bubble.parent().find('.textBubble-overflowContainer').addClass('hide')
)
# scroll to article if given
if @article_id && document.getElementById( 'article-' + @article_id )
offset = document.getElementById( 'article-' + @article_id ).offsetTop
@ -775,7 +817,7 @@ class Edit extends App.Controller
'.attachmentUpload-progressBar': 'progressBar'
'.js-percentage': 'progressText'
'.js-cancel': 'cancelContainer'
'.text-bubble': 'textBubble'
'.textBubble': 'textBubble'
'.editControls-item': 'editControlItem'
#'.editControls': 'editControls'
#'.recipient-picker': 'recipientPicker'
@ -860,14 +902,15 @@ class Edit extends App.Controller
if data.ticket.id is @ticket.id
#@setArticleType(data.type.name)
# preselect article type
@setArticleType( 'email' )
@open_textarea(null, true)
for key, value of data.article
if key is 'body'
@$('[data-name="' + key + '"]').html(value)
else
@$('[name="' + key + '"]').val(value)
# preselect article type
@setArticleType( 'email' )
)
isIE10: ->
@ -893,7 +936,7 @@ class Edit extends App.Controller
@setArticleType(@type)
configure_attributes = [
{ name: 'customer_id', display: 'Recipients', tag: 'user_autocompletion', null: false, placeholder: 'Enter Person or Organisation/Company', minLengt: 2, disableCreateUser: false },
{ name: 'customer_id', display: 'Recipients', tag: 'user_autocompletion', null: false, placeholder: 'Enter Person or Organization/Company', minLengt: 2, disableCreateUser: false },
]
controller = new App.ControllerForm(
@ -905,7 +948,7 @@ class Edit extends App.Controller
@$('[data-name="body"]').ce({
mode: 'richtext'
multiline: true
maxlength: 2500
maxlength: 5000
})
html5Upload.initialize(
@ -1075,10 +1118,29 @@ class Edit extends App.Controller
# show/hide attributes
for articleType in @articleTypes
if articleType.name is type
@$(".form-group").addClass('hide')
@$('.form-group').addClass('hide')
for name in articleType.attributes
@$("[name=#{name}]").closest('.form-group').removeClass('hide')
# check if signature need to be added
body = @$('[data-name="body"]').html() || ''
signature = undefined
if @ticket.group.signature_id
signature = App.Signature.find( @ticket.group.signature_id )
if signature && signature.body && @type is 'email'
signatureFinished = App.Utils.text2html(
App.Utils.replaceTags( signature.body, { user: App.Session.get(), ticket: @ticket } )
)
if App.Utils.signatureCheck( body, signatureFinished )
if !App.Utils.lastLineEmpty(body)
body = body + '<br>'
body = body + "<div data-signature=\"true\" data-signature-id=\"#{signature.id}\">#{signatureFinished}</div>"
@$('[data-name="body"]').html(body)
# remove old signature
else
@$('[data-name="body"]').find("[data-signature=true]").remove()
detect_empty_textarea: =>
if !@textarea.text().trim()
@add_textarea_catcher()
@ -1246,8 +1308,9 @@ class ArticleView extends App.Controller
'click .show_toogle': 'show_toogle'
'click [data-type=reply]': 'reply'
'click [data-type=replyAll]': 'replyAll'
'click .text-bubble': 'toggle_meta'
'click .text-bubble a': 'stopPropagation'
'click .textBubble': 'toggle_meta_with_delay'
'click .textBubble a': 'stopPropagation'
'click .js-unfold': 'unfold'
constructor: ->
super
@ -1311,7 +1374,17 @@ class ArticleView extends App.Controller
stopPropagation: (e) ->
e.stopPropagation()
toggle_meta: (e) ->
toggle_meta_with_delay: (e) =>
# allow double click select
# by adding a delay to the toggle
if @lastClick and +new Date - @lastClick < 150
clearTimeout(@toggleMetaTimeout)
else
@toggleMetaTimeout = setTimeout(@toggle_meta, 150, e)
@lastClick = +new Date
toggle_meta: (e) =>
e.preventDefault()
animSpeed = 300
@ -1387,6 +1460,25 @@ class ArticleView extends App.Controller
metaTopClip.velocity({ height: metaTop.outerHeight() }, animSpeed, 'easeOutQuad')
metaBottomClip.velocity({ height: metaBottom.outerHeight() }, animSpeed, 'easeOutQuad')
unfold: (e) ->
e.preventDefault()
e.stopPropagation()
container = $(e.currentTarget).parents('.textBubble-content')
overflowContainer = container.find('.textBubble-overflowContainer')
overflowContainer.velocity
properties:
opacity: 0
options:
duration: 300
container.velocity
properties:
height: container.attr('data-height')
options:
duration: 300
complete: -> overflowContainer.addClass('hide');
isOrContains: (node, container) ->
while node
if node is container
@ -1488,12 +1580,6 @@ class ArticleView extends App.Controller
# get current body
body = @ui.el.find('[data-name="body"]').html() || ''
# check if signature need to be added
if @ui.signature && @ui.signature.body && type.name is 'email'
signature = App.Utils.text2html( @ui.signature.body )
if App.Utils.signatureCheck( body, signature )
body = body + signature
# check if quote need to be added
selectedText = App.ClipBoard.getSelected()
if selectedText

View file

@ -1,11 +1,14 @@
class App.OnlineNotificationWidget extends App.Controller
elements:
'.js-toggleNavigation': 'toggle'
constructor: ->
super
@bind 'OnlineNotification::changed', =>
@delay(
=> @fetch()
1000
1200
'online-notification-changed'
)
@ -17,14 +20,14 @@ class App.OnlineNotificationWidget extends App.Controller
if !@access()
@el.find('activity-counter').html('')
return
@start()
@createContainer()
if @access()
@start()
@subscribeId = App.OnlineNotification.subscribe( @start )
@createContainer()
@subscribeId = App.OnlineNotification.subscribe( @updateContent )
release: =>
@stop()
@removeContainer()
App.OnlineNotification.unsubscribe( @subscribeId )
access: ->
@ -38,24 +41,64 @@ class App.OnlineNotificationWidget extends App.Controller
@el.find('.activity-counter').remove()
return
if @el.find('.logo .activity-counter')[0]
@el.find('.logo .activity-counter').html(count)
if @el.find('.js-toggleNavigation .activity-counter')[0]
@el.find('.js-toggleNavigation .activity-counter').html(count)
else
@el.find('.logo').append('<div class="activity-counter">' + count.toString() + '</div>')
@toggle.append('<div class="activity-counter">' + count.toString() + '</div>')
markAllAsSeen: (items) =>
for item in items
if !item.seen
App.OnlineNotification.seen( 'Ticket', item.id )
markAllAsRead: =>
@ajax(
id: 'markAllAsRead'
type: 'POST'
url: @apiPath + '/online_notifications/mark_all_as_read'
data: JSON.stringify( '' )
processData: true
)
stop: =>
@counterUpdate(0)
@el.find('.logo').popover('destroy')
removeClickCatcher: () =>
return if !@clickCatcher
@clickCatcher.remove()
@clickCatcher = null
start: =>
@stop()
onShow: =>
@updateContent()
# show popover
# set heigth of notification popover
height = $('#app').height()
$('.js-notificationsContainer').css('height', "#{height-12}px")
$('.js-notificationsContainer .arrow').css('top', '20px')
# close notification list on click
$('.js-notificationsContainer').on('click', (e) =>
#console.log('CL')
@hidePopover()
)
# mark all notifications as read
$('.js-markAllAsRead').on('click', (e) =>
e.preventDefault()
@markAllAsRead()
)
# add clickCatcher
@clickCatcher = new App.clickCatcher
holder: @el.offsetParent()
callback: @hidePopover
zIndexScale: 4
onHide: =>
@removeClickCatcher()
hidePopover: =>
@toggle.popover('hide')
fetch: =>
load = (items) =>
App.OnlineNotification.refresh( items, { clear: true } )
@updateContent()
App.OnlineNotification.fetchFull(load)
updateContent: =>
items = App.OnlineNotification.search( sortBy: 'created_at', order: 'DESC' )
counter = 0
for item in items
@ -63,33 +106,46 @@ class App.OnlineNotificationWidget extends App.Controller
counter = counter + 1
@counterUpdate(counter)
items = @prepareForObjectList(items)
# update title
$('.js-notificationsContainer .popover-title').html(
App.i18n.translateInline( 'Notifications' ) + " <span class='popover-notificationsCounter'>#{counter}</span>"
)
@el.find('.logo').popover(
# update content
items = @prepareForObjectList(items)
$('.js-notificationsContainer .popover-content').html(
$( App.view('widget/online_notification_content')(items: items) )
)
# show frontend times
@frontendTimeUpdate()
createContainer: =>
@removeContainer()
# show popover
waitUntilOldPopoverIsRemoved = =>
@toggle.popover
trigger: 'click'
container: 'body'
html: true
delay: { show: 100, hide: 0 }
placement: 'right'
title: ->
App.i18n.translateInline( 'Notifications' ) + " <span>#{counter}</span>"
content: =>
# insert data
$( App.view('widget/online_notification')(items: items))
).on('shown.bs.popover', =>
viewport: { "selector": "#app", "padding": 10 }
template: App.view('widget/online_notification')()
title: ' '
content: ' '
.on
'shown.bs.popover': @onShow
'hide.bs.popover': @onHide
# show frontend times
$('#markAllAsSeen').bind('click', (e) =>
e.preventDefault()
@markAllAsSeen(items)
);
@frontendTimeUpdate()
).on('hide.bs.popover', =>
$('#markAllAsSeen').unbind('click')
@updateContent()
@delay(
=> waitUntilOldPopoverIsRemoved()
600
'popover'
)
fetch: =>
load = (items) =>
App.OnlineNotification.refresh( items, { clear: true } )
@start()
App.OnlineNotification.fetchFull(load)
removeContainer: =>
@counterUpdate(0)
@toggle.popover('destroy')

File diff suppressed because one or more lines are too long

View file

@ -2,11 +2,11 @@
Velocity UI Pack
**********************/
/* VelocityJS.org UI Pack (4.1.4). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License. Portions copyright Daniel Eden, Christian Pucci. */
/* VelocityJS.org UI Pack (5.0.2). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License. Portions copyright Daniel Eden, Christian Pucci. */
;(function (factory) {
/* CommonJS module. */
if (typeof module === "object" && typeof module.exports === "object") {
if (typeof require === "function" && typeof exports === "object" ) {
module.exports = factory();
/* AMD module. */
} else if (typeof define === "function" && define.amd) {
@ -18,32 +18,61 @@
}(function() {
return function (global, window, document, undefined) {
/**************
/*************
Checks
**************/
*************/
if (!global.Velocity || !global.Velocity.Utilities) {
window.console && console.log("Velocity UI Pack: Velocity must be loaded first. Aborting.");
return;
} else if (!global.Velocity.version || (global.Velocity.version.major <= 0 && global.Velocity.version.minor <= 11 && global.Velocity.version.patch < 8)) {
var abortError = "Velocity UI Pack: You need to update Velocity (jquery.velocity.js) to a newer version. Visit http://github.com/julianshapiro/velocity.";
} else {
var Velocity = global.Velocity,
$ = Velocity.Utilities;
}
var velocityVersion = Velocity.version,
requiredVersion = { major: 1, minor: 1, patch: 0 };
function greaterSemver (primary, secondary) {
var versionInts = [];
if (!primary || !secondary) { return false; }
$.each([ primary, secondary ], function(i, versionObject) {
var versionIntsComponents = [];
$.each(versionObject, function(component, value) {
while (value.toString().length < 5) {
value = "0" + value;
}
versionIntsComponents.push(value);
});
versionInts.push(versionIntsComponents.join(""))
});
return (parseFloat(versionInts[0]) > parseFloat(versionInts[1]));
}
if (greaterSemver(requiredVersion, velocityVersion)){
var abortError = "Velocity UI Pack: You need to update Velocity (jquery.velocity.js) to a newer version. Visit http://github.com/julianshapiro/velocity.";
alert(abortError);
throw new Error(abortError);
}
/******************
Register UI
******************/
/************************
Effect Registration
************************/
global.Velocity.RegisterUI = function (effectName, properties) {
/* Note: RegisterUI is a legacy name. */
Velocity.RegisterEffect = Velocity.RegisterUI = function (effectName, properties) {
/* Animate the expansion/contraction of the elements' parent's height for In/Out effects. */
function animateParentHeight (elements, direction, totalDuration, stagger) {
var totalHeightDelta = 0,
parentNode;
/* Sum the total height (including padding and margin) of all targeted elements. */
global.Velocity.Utilities.each(elements.nodeType ? [ elements ] : elements, function(i, element) {
$.each(elements.nodeType ? [ elements ] : elements, function(i, element) {
if (stagger) {
/* Increase the totalDuration by the successive delay amounts produced by the stagger option. */
totalDuration += i * stagger;
@ -51,84 +80,99 @@ return function (global, window, document, undefined) {
parentNode = element.parentNode;
global.Velocity.Utilities.each([ "height", "paddingTop", "paddingBottom", "marginTop", "marginBottom"], function(i, property) {
totalHeightDelta += parseFloat(global.Velocity.CSS.getPropertyValue(element, property));
$.each([ "height", "paddingTop", "paddingBottom", "marginTop", "marginBottom"], function(i, property) {
totalHeightDelta += parseFloat(Velocity.CSS.getPropertyValue(element, property));
});
});
/* Animate the parent element's height adjustment (with a varying duration multiplier for aesthetic benefits). */
global.Velocity.animate(
Velocity.animate(
parentNode,
{ height: (direction === "In" ? "+" : "-") + "=" + totalHeightDelta },
{ queue: false, easing: "ease-in-out", duration: totalDuration * (direction === "In" ? 0.6 : 1) }
);
}
/* Register a custom sequence for each effect. */
global.Velocity.Sequences[effectName] = function (element, sequenceOptions, elementsIndex, elementsSize, elements, promiseData) {
/* Register a custom redirect for each effect. */
Velocity.Redirects[effectName] = function (element, redirectOptions, elementsIndex, elementsSize, elements, promiseData) {
var finalElement = (elementsIndex === elementsSize - 1);
if (typeof properties.defaultDuration === "function") {
properties.defaultDuration = properties.defaultDuration.call(elements, elements);
} else {
properties.defaultDuration = parseFloat(properties.defaultDuration);
}
/* Iterate through each effect's call array. */
for (var callIndex = 0; callIndex < properties.calls.length; callIndex++) {
var call = properties.calls[callIndex],
propertyMap = call[0],
sequenceDuration = (sequenceOptions.duration || properties.defaultDuration || 1000),
redirectDuration = (redirectOptions.duration || properties.defaultDuration || 1000),
durationPercentage = call[1],
callOptions = call[2] || {},
opts = {};
/* Assign the whitelisted per-call options. */
opts.duration = sequenceDuration * (durationPercentage || 1);
opts.queue = sequenceOptions.queue || "";
opts.duration = redirectDuration * (durationPercentage || 1);
opts.queue = redirectOptions.queue || "";
opts.easing = callOptions.easing || "ease";
opts.delay = callOptions.delay || 0;
opts.delay = parseFloat(callOptions.delay) || 0;
opts._cacheValues = callOptions._cacheValues || true;
/* Special processing for the first effect call. */
if (callIndex === 0) {
/* If a delay was passed into the sequence, combine it with the first call's delay. */
opts.delay += (sequenceOptions.delay || 0);
/* If a delay was passed into the redirect, combine it with the first call's delay. */
opts.delay += (parseFloat(redirectOptions.delay) || 0);
if (elementsIndex === 0) {
opts.begin = function() {
/* Only trigger a begin callback on the first effect call with the first element in the set. */
sequenceOptions.begin && sequenceOptions.begin.call(elements, elements);
redirectOptions.begin && redirectOptions.begin.call(elements, elements);
var direction = effectName.match(/(In|Out)$/);
/* Make "in" transitioning elements invisible immediately so that there's no FOUC between now
and the first RAF tick. */
if ((direction && direction[0] === "In") && propertyMap.opacity !== undefined) {
$.each(elements.nodeType ? [ elements ] : elements, function(i, element) {
Velocity.CSS.setPropertyValue(element, "opacity", 0);
});
}
/* Only trigger animateParentHeight() if we're using an In/Out transition. */
var direction = effectName.match(/(In|Out)$/);
if (sequenceOptions.animateParentHeight && direction) {
animateParentHeight(elements, direction[0], sequenceDuration + opts.delay, sequenceOptions.stagger);
if (redirectOptions.animateParentHeight && direction) {
animateParentHeight(elements, direction[0], redirectDuration + opts.delay, redirectOptions.stagger);
}
}
}
/* If the user isn't overriding the display option, default to "auto" for "In"-suffixed transitions. */
if (sequenceOptions.display !== null) {
if (sequenceOptions.display !== undefined && sequenceOptions.display !== "none") {
opts.display = sequenceOptions.display;
if (redirectOptions.display !== null) {
if (redirectOptions.display !== undefined && redirectOptions.display !== "none") {
opts.display = redirectOptions.display;
} else if (/In$/.test(effectName)) {
/* Inline elements cannot be subjected to transforms, so we switch them to inline-block. */
var defaultDisplay = global.Velocity.CSS.Values.getDisplayType(element);
var defaultDisplay = Velocity.CSS.Values.getDisplayType(element);
opts.display = (defaultDisplay === "inline") ? "inline-block" : defaultDisplay;
}
}
if (sequenceOptions.visibility && sequenceOptions.visibility !== "hidden") {
opts.visibility = sequenceOptions.visibility;
if (redirectOptions.visibility && redirectOptions.visibility !== "hidden") {
opts.visibility = redirectOptions.visibility;
}
}
/* Special processing for the last effect call. */
if (callIndex === properties.calls.length - 1) {
/* Append promise resolving onto the user's sequence callback. */
/* Append promise resolving onto the user's redirect callback. */
function injectFinalCallbacks () {
if ((sequenceOptions.display === undefined || sequenceOptions.display === "none") && /Out$/.test(effectName)) {
global.Velocity.Utilities.each(elements.nodeType ? [ elements ] : elements, function(i, element) {
global.Velocity.CSS.setPropertyValue(element, "display", "none");
if ((redirectOptions.display === undefined || redirectOptions.display === "none") && /Out$/.test(effectName)) {
$.each(elements.nodeType ? [ elements ] : elements, function(i, element) {
Velocity.CSS.setPropertyValue(element, "display", "none");
});
}
sequenceOptions.complete && sequenceOptions.complete.call(elements, elements);
redirectOptions.complete && redirectOptions.complete.call(elements, elements);
if (promiseData) {
promiseData.resolver(elements || element);
@ -142,7 +186,8 @@ return function (global, window, document, undefined) {
/* Format each non-array value in the reset property map to [ value, value ] so that changes apply
immediately and DOM querying is avoided (via forcefeeding). */
if (typeof resetValue === "string" || typeof resetValue === "number") {
/* Note: Don't forcefeed hooks, otherwise their hook roots will be defaulted to their null values. */
if (Velocity.CSS.Hooks.registered[resetProperty] === undefined && (typeof resetValue === "string" || typeof resetValue === "number")) {
properties.reset[resetProperty] = [ properties.reset[resetProperty], properties.reset[resetProperty] ];
}
}
@ -155,24 +200,24 @@ return function (global, window, document, undefined) {
resetOptions.complete = injectFinalCallbacks;
}
global.Velocity.animate(element, properties.reset, resetOptions);
Velocity.animate(element, properties.reset, resetOptions);
/* Only trigger the user's complete callback on the last effect call with the last element in the set. */
} else if (finalElement) {
injectFinalCallbacks();
}
};
if (sequenceOptions.visibility === "hidden") {
opts.visibility = sequenceOptions.visibility;
if (redirectOptions.visibility === "hidden") {
opts.visibility = redirectOptions.visibility;
}
}
global.Velocity.animate(element, propertyMap, opts);
Velocity.animate(element, propertyMap, opts);
}
};
/* Return the Velocity object so that RegisterUI calls can be chained. */
return global.Velocity;
return Velocity;
};
/*********************
@ -181,7 +226,7 @@ return function (global, window, document, undefined) {
/* Externalize the packagedEffects data so that they can optionally be modified and re-registered. */
/* Support: <=IE8: Callouts will have no effect, and transitions will simply fade in/out. IE9/Android 2.3: Most effects are fully supported, the rest fade in/out. All other browsers: full support. */
global.Velocity.RegisterUI.packagedEffects =
Velocity.RegisterEffect.packagedEffects =
{
/* Animate.css */
"callout.bounce": {
@ -221,7 +266,7 @@ return function (global, window, document, undefined) {
"callout.pulse": {
defaultDuration: 825,
calls: [
[ { scaleX: 1.1, scaleY: 1.1 }, 0.50 ],
[ { scaleX: 1.1, scaleY: 1.1 }, 0.50, { easing: "easeInExpo" } ],
[ { scaleX: 1, scaleY: 1 }, 0.50 ]
]
},
@ -356,28 +401,28 @@ return function (global, window, document, undefined) {
/* Magic.css */
/* Support: Loses rotation in IE9/Android 2.3. (Fades and scales only.) */
"transition.whirlIn": {
defaultDuration: 900,
defaultDuration: 850,
calls: [
[ { opacity: [ 1, 0 ], transformOriginX: [ "50%", "50%" ], transformOriginY: [ "50%", "50%" ], scaleX: [ 1, 0 ], scaleY: [ 1, 0 ], rotateY: [ 0, 160 ] } ]
[ { opacity: [ 1, 0 ], transformOriginX: [ "50%", "50%" ], transformOriginY: [ "50%", "50%" ], scaleX: [ 1, 0 ], scaleY: [ 1, 0 ], rotateY: [ 0, 160 ] }, 1, { easing: "easeInOutSine" } ]
]
},
/* Magic.css */
/* Support: Loses rotation in IE9/Android 2.3. (Fades and scales only.) */
"transition.whirlOut": {
defaultDuration: 900,
defaultDuration: 750,
calls: [
[ { opacity: [ 0, 1 ], transformOriginX: [ "50%", "50%" ], transformOriginY: [ "50%", "50%" ], scaleX: 0, scaleY: 0, rotateY: 160 } ]
[ { opacity: [ 0, "easeInOutQuint", 1 ], transformOriginX: [ "50%", "50%" ], transformOriginY: [ "50%", "50%" ], scaleX: 0, scaleY: 0, rotateY: 160 }, 1, { easing: "swing" } ]
],
reset: { scaleX: 1, scaleY: 1, rotateY: 0 }
},
"transition.shrinkIn": {
defaultDuration: 700,
defaultDuration: 750,
calls: [
[ { opacity: [ 1, 0 ], transformOriginX: [ "50%", "50%" ], transformOriginY: [ "50%", "50%" ], scaleX: [ 1, 1.5 ], scaleY: [ 1, 1.5 ], translateZ: 0 } ]
]
},
"transition.shrinkOut": {
defaultDuration: 650,
defaultDuration: 600,
calls: [
[ { opacity: [ 0, 1 ], transformOriginX: [ "50%", "50%" ], transformOriginY: [ "50%", "50%" ], scaleX: 1.3, scaleY: 1.3, translateZ: 0 } ]
],
@ -409,9 +454,9 @@ return function (global, window, document, undefined) {
"transition.bounceOut": {
defaultDuration: 800,
calls: [
[ { scaleX: 0.95, scaleY: 0.95 }, 0.40 ],
[ { scaleX: 1.1, scaleY: 1.1, translateZ: 0 }, 0.40 ],
[ { opacity: [ 0, 1 ], scaleX: 0.3, scaleY: 0.3 }, 0.20 ]
[ { scaleX: 0.95, scaleY: 0.95 }, 0.35 ],
[ { scaleX: 1.1, scaleY: 1.1, translateZ: 0 }, 0.35 ],
[ { opacity: [ 0, 1 ], scaleX: 0.3, scaleY: 0.3 }, 0.30 ]
],
reset: { scaleX: 1, scaleY: 1 }
},
@ -596,8 +641,7 @@ return function (global, window, document, undefined) {
defaultDuration: 800,
calls: [
[ { opacity: [ 1, 0 ], transformPerspective: [ 800, 800 ], transformOriginX: [ 0, 0 ], transformOriginY: [ "100%", "100%" ], rotateX: [ 0, -180 ] } ]
],
reset: { transformPerspective: 0, transformOriginX: "50%", transformOriginY: "50%" }
]
},
/* Magic.css */
/* Support: Loses rotation in IE9/Android 2.3 (fades only). */
@ -665,8 +709,46 @@ return function (global, window, document, undefined) {
};
/* Register the packaged effects. */
for (var effectName in global.Velocity.RegisterUI.packagedEffects) {
global.Velocity.RegisterUI(effectName, global.Velocity.RegisterUI.packagedEffects[effectName]);
for (var effectName in Velocity.RegisterEffect.packagedEffects) {
Velocity.RegisterEffect(effectName, Velocity.RegisterEffect.packagedEffects[effectName]);
}
/*********************
Sequence Running
**********************/
/* Note: Sequence calls must use Velocity's single-object arguments syntax. */
Velocity.RunSequence = function (originalSequence) {
var sequence = $.extend(true, [], originalSequence);
if (sequence.length > 1) {
$.each(sequence.reverse(), function(i, currentCall) {
var nextCall = sequence[i + 1];
if (nextCall) {
/* Parallel sequence calls (indicated via sequenceQueue:false) are triggered
in the previous call's begin callback. Otherwise, chained calls are normally triggered
in the previous call's complete callback. */
var timing = (currentCall.options && currentCall.options.sequenceQueue === false) ? "begin" : "complete",
callbackOriginal = nextCall.options && nextCall.options[timing],
options = {};
options[timing] = function() {
var nextCallElements = nextCall.elements || nextCall.e;
var elements = nextCallElements.nodeType ? [ nextCallElements ] : nextCallElements;
callbackOriginal && callbackOriginal.call(elements, elements);
Velocity(currentCall);
}
nextCall.options = $.extend({}, nextCall.options, options);
}
});
sequence.reverse();
}
Velocity(sequence[0]);
};
}((window.jQuery || window.Zepto || window), window, document);
}));

View file

@ -62,16 +62,15 @@ class _ajaxSingleton
# do not show aborded requests
return if status is 0
# do not show any error message on wrong login
return if status is 401 && !settings.url.match('login')
# do not show any error message with code 200
# 200, all is fine
return if status is 200
# show human readable message
if status is 401
status = 'Access denied.'
detail = ''
# do not show any error message with code 401/404 (handled by controllers)
return if status is 401
return if status is 404
# do not show any error message with code 502
return if status is 502
# show error message
new App.ErrorModal(

View file

@ -1,9 +1,9 @@
class App.UserOrganizationAutocompletion extends App.Controller
className: 'dropdown js-recipientDropdown zIndex-2'
events:
'hide.bs.dropdown .js-recipientDropdown': 'hideOrganisationMembers'
'click .js-organisation': 'showOrganisationMembers'
'click .js-back': 'hideOrganisationMembers'
'hide.bs.dropdown .js-recipientDropdown': 'hideOrganizationMembers'
'click .js-organization': 'showOrganizationMembers'
'click .js-back': 'hideOrganizationMembers'
'click .js-user': 'selectUser'
'click .js-user-new': 'newUser'
'focus input': 'open'
@ -148,9 +148,9 @@ class App.UserOrganizationAutocompletion extends App.Controller
e.preventDefault()
userId = @$('.recipientList').find('li.is-active').data('user-id')
if !userId
organisationId = @$('.recipientList').find('li.is-active').data('organisation-id')
if organisationId
@showOrganisationMembers(undefined, @$('.recipientList').find('li.is-active'))
organizationId = @$('.recipientList').find('li.is-active').data('organization-id')
if organizationId
@showOrganizationMembers(undefined, @$('.recipientList').find('li.is-active'))
return
if userId is 'new'
@newUser()
@ -217,24 +217,24 @@ class App.UserOrganizationAutocompletion extends App.Controller
emptyResultList: =>
@$('.recipientList').empty()
@$('.recipientList-organisationMembers').remove()
@$('.recipientList-organizationMembers').remove()
showOrganisationMembers: (e,listEntry) =>
showOrganizationMembers: (e,listEntry) =>
if e
e.stopPropagation()
listEntry = $(e.currentTarget)
organisationId = listEntry.data('organisation-id')
organizationId = listEntry.data('organization-id')
@recipientList = @$('.recipientList')
@organisationList = @$("##{ organisationId }")
@organizationList = @$("##{ organizationId }")
# move organisation-list to the right and slide it in
# move organization-list to the right and slide it in
$.Velocity.hook(@organisationList, 'translateX', '100%')
@organisationList.removeClass('hide')
$.Velocity.hook(@organizationList, 'translateX', '100%')
@organizationList.removeClass('hide')
@organisationList.velocity
@organizationList.velocity
properties:
translateX: 0
options:
@ -246,12 +246,12 @@ class App.UserOrganizationAutocompletion extends App.Controller
translateX: '-100%'
options:
speed: 300
complete: => @recipientList.height(@organisationList.height())
complete: => @recipientList.height(@organizationList.height())
hideOrganisationMembers: (e) =>
hideOrganizationMembers: (e) =>
e && e.stopPropagation()
return if !@organisationList
return if !@organizationList
# fade list back in
@recipientList.velocity
@ -264,13 +264,13 @@ class App.UserOrganizationAutocompletion extends App.Controller
@recipientList.height('')
# slide out organisation-list and hide it
@organisationList.velocity
# slide out organization-list and hide it
@organizationList.velocity
properties:
translateX: '100%'
options:
speed: 300
complete: => @organisationList.addClass('hide')
complete: => @organizationList.addClass('hide')
newUser: (e) =>
if e

View file

@ -114,7 +114,7 @@ class App.Utils
@_removeAttributes( html )
# remove tags, keep content
html.find('a, font').replaceWith( ->
html.find('a, font, small, time').replaceWith( ->
$(@).contents()
)
@ -166,3 +166,27 @@ class App.Utils
else
true
# textReplaced = App.Utils.replaceTags( template, { user: { firstname: 'Bob', lastname: 'Smith' } } )
@replaceTags: (template, objects) ->
template = template.replace( /#\{\s{0,2}(.+?)\s{0,2}\}/g, ( index, key ) ->
levels = key.split(/\./)
dataRef = objects
for level in levels
if dataRef[level]
dataRef = dataRef[level]
if typeof dataRef is 'function'
value = dataRef()
else if typeof dataRef is 'string'
value = dataRef
else
value = ''
#console.log( "tag replacement #{key}, #{value} env: ", objects)
value
)
# true|false = App.Utils.lastLineEmpty( message )
@lastLineEmpty: (message) ->
messageCleanup = message.replace(/>\s+</g, '><').replace(/(\n|\r|\t)/g, '').trim()
return true if messageCleanup.match(/<(br|\s+?|\/)>$/im)
return true if messageCleanup.match(/<div(|\s.+?)><\/div>$/im)
false

View file

@ -25,6 +25,7 @@
40: true, // left
91: true, // cmd left
92: true, // cmd right
224: true, // cmd left
},
extraAllowKey: {
65: true, // a + ctrl - select all
@ -38,6 +39,7 @@
73: true, // i
85: true, // u
},
//maxlength: 20,
};
function Plugin( element, options ) {
@ -58,13 +60,9 @@
this.preventInput = false
this.init();
// bind
// bind paste
}
Plugin.prototype.init = function () {
var _this = this
@ -84,59 +82,22 @@
e.preventDefault()
return
}
}
// limit check
if ( !_this.maxLengthOk( true ) ) {
if ( !_this.allowKey(e) ) {
if ( !_this.maxLengthOk( 1 ) ) {
e.preventDefault()
return
}
}
})
this.$element.on('keyup', function (e) {
console.log('KU', e.ctrlKey)
// do not remove tags on space, enter or backspace key, it's needed for FF
if ( _this.options.mode === 'textonly' ) {
if ( !_this.options.multiline ) {
// do tricky this for FF
if ( e.keyCode !== 32 && e.keyCode !== 13 && e.keyCode !== 8 ) {
// start request to remove tags
_this.htmlRemoveTags()
}
else {
// clear request to delete tags, in FF we need <br> anytime at the end
_this.htmlRemoveTagsClearClearTimeout()
}
}
else {
App.Utils.htmlRemoveRichtext(_this.$element)
}
}
else {
App.Utils.htmlClanup(_this.$element)
}
})
// just paste text
this.$element.on('paste', function (e) {
console.log('paste')
if ( _this.options.mode === 'textonly' ) {
if ( !_this.options.multiline ) {
_this.htmlRemoveTags()
}
else {
App.Utils.htmlRemoveRichtext(_this.$element)
}
}
else {
App.Utils.htmlClanup(_this.$element)
}
return true
if ( this.options.mode === 'textonly' ) {
e.preventDefault()
// check existing + paste text for limit
var text
if (window.clipboardData) { // IE
text = window.clipboardData.getData('Text')
@ -144,38 +105,32 @@
else {
text = (e.originalEvent || e).clipboardData.getData('text/plain')
}
var overlimit = false
if (text) {
// replace new lines
if ( !_this.maxLengthOk( text.length) ) {
e.preventDefault()
return
}
// use setTimeout() with 0 to execute it right after paste event
if ( _this.options.mode === 'textonly' ) {
if ( !_this.options.multiline ) {
text = text.replace(/\n/g, '')
text = text.replace(/\r/g, '')
text = text.replace(/\t/g, '')
}
// limit length, limit paste string
if ( _this.options.maxlength ) {
var pasteLength = text.length
var currentLength = _this.$element.text().length
var overSize = ( currentLength + pasteLength ) - _this.options.maxlength
if ( overSize > 0 ) {
text = text.substr( 0, pasteLength - overSize )
overlimit = true
}
}
// insert new text
if (document.selection) { // IE
var range = document.selection.createRange()
range.pasteHTML(text)
setTimeout($.proxy(function(){
App.Utils.htmlRemoveTags(this.$element)
}, _this), 0)
}
else {
document.execCommand('inserttext', false, text)
}
_this.maxLengthOk( overlimit )
setTimeout($.proxy(function(){
App.Utils.htmlRemoveRichtext(this.$element)
}, _this), 0)
}
}
else {
setTimeout($.proxy(function(){
App.Utils.htmlClanup(this.$element)
}, _this), 0)
}
return true
})
// disable rich text b/u/i
@ -188,23 +143,15 @@
}
}
// check if rich text key is pressed
Plugin.prototype.htmlRemoveTags = function() {
// clear old clear request
this.htmlRemoveTagsClearClearTimeout()
// set new clear request
this._setTimeOutReformat = setTimeout($.proxy(function(){
App.Utils.htmlRemoveTags(this.$element)
}, this), 100)
console.log('htmlRemoveTagsClearSetTimeout', this._setTimeOutReformat)
// check if key is allowed, even if length limit is reached
Plugin.prototype.allowKey = function(e) {
if ( this.options.allowKey[ e.keyCode ] ) {
return true
}
Plugin.prototype.htmlRemoveTagsClearClearTimeout = function() {
if (this._setTimeOutReformat) {
console.log('htmlRemoveTagsClearClearTimeout', this._setTimeOutReformat)
clearTimeout(this._setTimeOutReformat)
if ( ( e.ctrlKey || e.metaKey ) && this.options.extraAllowKey[ e.keyCode ] ) {
return true
}
return false
}
// check if rich text key is pressed
@ -225,10 +172,14 @@
// max length check
Plugin.prototype.maxLengthOk = function(typeAhead) {
if ( !this.options.maxlength ) {
return true
}
var length = this.$element.text().length
if (typeAhead) {
length = length + 1
length = length + typeAhead
}
console.log('maxLengthOk', length, this.options.maxlength)
if ( length > this.options.maxlength ) {
// try to set error on framework form

View file

@ -52,18 +52,22 @@
e.preventDefault()
var id = _this.$widget.find('.dropdown-menu li.active a').data('id')
_this.take(id)
return
}
// arrow keys
if ( e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40 ) {
// arrow keys left/right
if ( e.keyCode === 37 || e.keyCode === 39 ) {
e.preventDefault()
return
}
// up
if ( e.keyCode === 38 ) {
e.preventDefault()
if ( !_this.$widget.find('.dropdown-menu li.active')[0] ) {
var top = _this.$widget.find('.dropdown-menu li').last().addClass('active').position().top
_this.$widget.find('.dropdown-menu').scrollTop( top );
return
}
else {
var prev = _this.$widget.find('.dropdown-menu li.active').removeClass('active').prev()
@ -72,15 +76,17 @@
top = prev.addClass('active').position().top
}
_this.$widget.find('.dropdown-menu').scrollTop( top );
return
}
}
// down
if ( e.keyCode === 40 ) {
e.preventDefault()
if ( !_this.$widget.find('.dropdown-menu li.active')[0] ) {
var top = _this.$widget.find('.dropdown-menu li').first().addClass('active').position().top
_this.$widget.find('.dropdown-menu').scrollTop( top );
return
}
else {
var next = _this.$widget.find('.dropdown-menu li.active').removeClass('active').next()
@ -89,6 +95,7 @@
top = next.addClass('active').position().top
}
_this.$widget.find('.dropdown-menu').scrollTop( top );
return
}
}
@ -100,9 +107,15 @@
// backspace
if ( e.keyCode === 8 && _this.buffer ) {
// backspace + buffer === :: -> close textmodule
if ( _this.buffer === '::' ) {
_this.close()
e.preventDefault()
return
}
// reduce buffer and show new result
var length = _this.buffer.length
_this.buffer = _this.buffer.substr( 0, length-1 )
console.log('BS backspace', _this.buffer)
@ -115,22 +128,26 @@
console.log('BUFF', _this.buffer, e.keyCode, String.fromCharCode(e.which) )
// shift
if ( e.keyCode === 16 ) {
return
}
if ( e.keyCode === 16 ) return
// enter
if ( e.keyCode === 13 ) {
return
}
if ( e.keyCode === 13 ) return
// arrow keys
if ( e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40 ) {
return
if ( e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40 ) return
// observer other second key
if ( _this.buffer === ':' && String.fromCharCode(e.which) !== ':' ) {
_this.buffer = ''
}
// enter :
if ( String.fromCharCode(e.which) === ':' ) {
// oberserve second :
if ( _this.buffer === ':' && String.fromCharCode(e.which) === ':' ) {
_this.buffer = _this.buffer + ':'
}
// oberserve first :
if ( !_this.buffer && String.fromCharCode(e.which) === ':' ) {
_this.buffer = _this.buffer + ':'
}
@ -172,57 +189,38 @@
this.$widget = this.$element.next()
}
// update widget position
// set height of widget
Plugin.prototype.movePosition = function() {
if (!this._position) return
var height = this.$element.height() + 20
var widgetHeight = this.$widget.find('ul').height() //+ 60 // + height
var top = -( widgetHeight + height ) + this._position.top
this.$widget.css('top', top)
this.$widget.css('left', this._position.left)
}
// set position of widget
Plugin.prototype.updatePosition = function() {
this.$widget.find('.dropdown-menu').scrollTop( 300 );
if ( !this.$element.is(':visible') ) return
// get cursor position
var marker = '<span id="js-cursor-position"></span>'
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// only relatively recently standardized and is not supported in
// some browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = marker;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
position = $('#js-cursor-position').position()
var range = this.getFirstRange();
var clone = range.cloneRange()
clone.pasteHtml(marker)
this._position = $('#js-cursor-position').position()
$('#js-cursor-position').remove()
if (!position) return
if (!this._position) return
// set position of widget
var height = this.$element.height()
var widgetHeight = this.$widget.find('ul').height() //+ 60 // + height
var top = -( widgetHeight + height ) + position.top
this.$widget.css('top', top)
this.$widget.css('left', position.left)
this.movePosition()
}
// open widget
Plugin.prototype.open = function() {
this.active = true
this.updatePosition()
b = $.proxy(function() {
this.$widget.addClass('open')
}, this)
@ -231,9 +229,11 @@
// close widget
Plugin.prototype.close = function() {
this.active = false
this.cutInput()
this.$widget.removeClass('open')
if ( this.active ) {
this.cutInput(true)
}
this.active = false
}
// check if widget is active/open
@ -255,11 +255,15 @@
// cut some content
Plugin.prototype.cut = function(string) {
var range = this.getFirstRange();
if (!range) return
/*
var sel = window.getSelection()
if ( !sel || sel.rangeCount < 1) {
return
}
var range = sel.getRangeAt(0)
*/
var clone = range.cloneRange()
// improve error handling
@ -267,9 +271,34 @@
if (start < 0) {
start = 0
}
// for chrome, remove also leading space, add it later - otherwice space will be tropped
if (start) {
clone.setStart(range.startContainer, start-1)
clone.setEnd(range.startContainer, start)
var spacerChar = clone.toString()
if ( spacerChar === ' ' ) {
start = start - 1
}
}
//console.log('CUT FOR', string, "-"+clone.toString()+"-", start, range.startOffset)
clone.setStart(range.startContainer, start)
clone.setEnd(range.startContainer, range.startOffset)
clone.deleteContents()
// for chrome, insert space again
if (start) {
if ( spacerChar === ' ' ) {
string = "&nbsp;"
if (document.selection) { // IE
var range = document.selection.createRange()
range.pasteHTML(string)
}
else {
document.execCommand('insertHTML', false, string)
}
}
}
}
// select text module and insert into text
@ -291,15 +320,15 @@
return
}
Plugin.prototype.getFirstRange = function() {
var sel = rangy.getSelection();
return sel.rangeCount ? sel.getRangeAt(0) : null;
}
// cut out search string from text
Plugin.prototype.cutInput = function() {
if (!this.buffer) return
if (!this.$element.text()) return
var sel = window.getSelection()
if ( !sel || sel.rangeCount < 1) {
this.buffer = ''
return
}
this.cut(this.buffer)
this.buffer = ''
}
@ -322,9 +351,9 @@
console.log('result', term, result)
for (var i = 0; i < result.length; i++) {
var item = result[i]
var template = "<li><a href=\"#\" class=\"u-textTruncate\" data-id=" + item.id + ">" + item.name
var template = "<li><a href=\"#\" class=\"u-textTruncate\" data-id=" + item.id + ">" + App.Utils.htmlEscape(item.name)
if (item.keywords) {
template = template + " (" + item.keywords + ")"
template = template + " (" + App.Utils.htmlEscape(item.keywords) + ")"
}
template = template + "</a></li>"
this.$widget.find('ul').append(template)
@ -340,10 +369,9 @@
_this.take(id)
}
)
this.updatePosition()
this.movePosition()
}
$.fn[pluginName] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,11 @@
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
/*
modified by Felix Jan-2014
- add this.$body = $(options.container || document.body)
*/
+function ($) {
'use strict';
@ -15,7 +20,7 @@
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$body = $(options.container || document.body)
this.$element = $(element)
this.$backdrop =
this.isShown = null
@ -57,6 +62,7 @@
this.checkScrollbar()
this.setScrollbar()
this.$body.addClass('modal-open')
this.escape()

View file

@ -0,0 +1,30 @@
/*
Makes the popover stay when hovered over it
from here http://jsfiddle.net/WojtekKruszewski/Zf3m7/22/
*/
var originalLeave = $.fn.popover.Constructor.prototype.leave;
$.fn.popover.Constructor.prototype.leave = function(obj){
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
var container, timeout;
originalLeave.call(this, obj);
if(obj.currentTarget) {
container = $('body .popover');
timeout = self.timeout;
container.one('mouseenter', function(){
//We entered the actual popover call off the dogs
clearTimeout(timeout);
//Let's monitor popover content instead
container.one('mouseleave', function(){
$.fn.popover.Constructor.prototype.leave.call(self, self);
});
})
}
};

View file

@ -25,7 +25,7 @@
placement: 'right',
trigger: 'click',
content: '',
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h2 class="popover-title"></h2><div class="popover-content"></div></div>'
})

View file

@ -18,7 +18,7 @@ class App.Organization extends App.Model
'#organization/profile/' + @id
icon: (user) ->
"organisation icon"
"organization icon"
@_fillUp: (data) ->

View file

@ -44,6 +44,9 @@ class App.Ticket extends App.Model
iconTitle: (user) ->
App.TicketState.find( @state_id ).displayName()
iconTextClass: (user) ->
"level-#{ @level() }"
iconActivity: (user) ->
if @owner_id == user.id
return 'important'

View file

@ -2,9 +2,12 @@
<div class="tableOverview flex scrollable">
<div class="horizontal">
<div class="page-header-title">
<h1><%- @T( @overview.name ) %> <% if @edit: %><small><a href="#" data-type="settings" class="glyphicon glyphicon-edit"></a></small><% end %></h1>
<h1><%- @T( @overview.name ) %></h1>
</div>
<div class="page-header-meta">
<% if @edit: %>
<div class="btn btn--action" data-type="settings"><%- @T('Options') %></div>
<% end %>
<ul class="pagination">
<% for item in @view_modes: %>
<li class="<%= item.class %>">

View file

@ -1,9 +1,10 @@
<div>
<div class="horizontal">
<div class="page-header-title">
<h1 class="can-move"><%- @T( @overview.name ) %> <small><a href="#" data-type="settings" class="glyphicon glyphicon-edit"></a></small></h1>
<h1 class="can-move"><%- @T( @overview.name ) %></h1>
</div>
<div class="page-header-meta horizontal">
<div class="page-header-meta">
<div class="btn btn--action" data-type="settings"><%- @T('Options') %></div>
<div class="pagination-counter">
<span class="pagination-items-range"><%- @items_from %>-<%- @items_till %></span> <%- @T("of") %> <span class="pagination-total-items"><%- @items_total %></span>
</div>

View file

@ -0,0 +1,5 @@
<div class="flex fullscreenMessage">
<div class="error icon"></div><h2><%- @T('Opps.. I\'m sorry, something went wrong!' ) %></h2>
<p><%- @T('Status Code') %>: <%= @status %></p>
<p><%= @detail %></p>
</div>

View file

@ -0,0 +1,3 @@
<div class="flex fullscreenMessage">
<div class="error icon"></div><h2><%- @T('Opps.. I\'m sorry, but I can\'t find this %s.', @objectName ) %></h2>
</div>

View file

@ -0,0 +1,3 @@
<div class="flex fullscreenMessage">
<div class="error icon"></div><h2><%- @T('Opps.. I\'m sorry, but you have insufficient rights to open this %s.', @objectName ) %></h2>
</div>

View file

@ -1,6 +1,6 @@
<li class="recipientList-entry u-clickable horizontal center js-organisation" data-organisation-id="<%- @organization.id %>">
<li class="recipientList-entry u-clickable horizontal center js-organization" data-organization-id="<%- @organization.id %>">
<div class="recipientList-iconSpacer centered">
<div class="white organisation icon"></div>
<div class="white organization icon"></div>
</div>
<div class="recipientList-name flex u-textTruncat">
<%= @organization.displayName() %>

View file

@ -1,4 +1,4 @@
<ul class="recipientList-organisationMembers hide" id="<%- @organization.id %>">
<ul class="recipientList-organizationMembers hide" id="<%- @organization.id %>">
<li class="recipientList-controls u-clickable js-back">
<div class="recipientList-backClickArea centered">
<div class="recipientList-backButton">

View file

@ -44,7 +44,7 @@
</div>
<div class="ticket-article">
<div class="ticket-article-item bubble-grid customer phone" data-id="1" id="article-1">
<div class="ticket-article-item customer phone" data-id="1" id="article-1">
<div class="article-meta-clip top">
<div class="article-content-meta top hide">
<div class="article-meta top">
@ -55,20 +55,27 @@
</div>
</div>
</div>
<div class="article-content zIndex-1 horizontal reverse">
<div class="article-content zIndex-1">
<span class="avatar unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
<div class="flex bubble-gap internal-border">
<div class="text-bubble"><div class="bubble-arrow"></div>Welcome!
Thank you for installing Zammad.
You will find updates and patches at <a href="http://zammad.org/" title="http://zammad.org/" target="_blank">http://zammad.org/</a>. Online
documentation is available at <a href="http://guides.zammad.org/" title="http://guides.zammad.org/" target="_blank">http://guides.zammad.org/</a>. You can also
use our forums at <a href="http://forums.zammad.org/" title="http://forums.zammad.org/" target="_blank">http://forums.zammad.org/</a>
Regards,
<a href="#" class="show_toogle">See more</a><div class="hide preview">
The <a href="http://Zammad.org" title="http://Zammad.org" target="_blank">Zammad.org</a> Project</div></div>
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="textBubble-content">
Welcome!
<br/>
Thank you for installing Zammad.<br/>
<br/>
You will find updates and patches at <a href="http://zammad.org/" title="http://zammad.org/" target="_blank">http://zammad.org/</a>. Online<br/>
documentation is available at <a href="http://guides.zammad.org/" title="http://guides.zammad.org/" target="_blank">http://guides.zammad.org/</a>. You can also<br/>
use our forums at <a href="http://forums.zammad.org/" title="http://forums.zammad.org/" target="_blank">http://forums.zammad.org/</a><br/>
<br/>
Regards,<br/>
The <a href="http://Zammad.org" title="http://Zammad.org" target="_blank">Zammad.org</a> Project
<div class="textBubble-overflowContainer">
<div class="btn btn--text js-unfold"><%- @T('See more') %></div>
</div>
</div>
</div>
</div>
</div>
<div class="article-meta-clip bottom">
@ -98,7 +105,7 @@ The <a href="http://Zammad.org" title="http://Zammad.org" target="_blank">Zammad
<small class="task-subline zIndex-1"><time class="humanTimeFromNow" data-time="2014-07-11T10:10:32.000Z" data-tooltip="2014-07-11 12:10">2014-07-11</time></small>
</div>
<div class="ticket-article-item bubble-grid agent note" data-id="23" id="article-23">
<div class="ticket-article-item agent note" data-id="23" id="article-23">
<div class="article-meta-clip top">
<div class="article-content-meta top hide">
<div class="article-meta top">
@ -109,10 +116,10 @@ The <a href="http://Zammad.org" title="http://Zammad.org" target="_blank">Zammad
</div>
</div>
</div>
<div class="article-content zIndex-1 horizontal">
<div class="article-content zIndex-1">
<span class="avatar user-popover" data-id="3" style="background-image: url(api/v1/users/image/bb100af55234cf61fb6f207636f095f8)" data-placement="right" data-original-title="" title=""></span>
<div class="flex bubble-gap internal-border">
<div class="text-bubble"><div class="bubble-arrow"></div>Hallp HP, du kannst dich nur einmal einloggen. Was machst du genau?</div>
<div class="textBubble"><div class="bubble-arrow"></div>Hallp HP, du kannst dich nur einmal einloggen. Was machst du genau?</div>
</div>
</div>
<div class="article-meta-clip bottom">
@ -136,7 +143,7 @@ The <a href="http://Zammad.org" title="http://Zammad.org" target="_blank">Zammad
<small class="task-subline zIndex-1"><time class="humanTimeFromNow" data-time="2014-08-05T13:34:01.000Z" data-tooltip="2014-08-05 15:34">2014-08-05</time></small>
</div>
<div class="ticket-article-item bubble-grid customer phone" data-id="1" id="article-1">
<div class="ticket-article-item customer phone" data-id="1" id="article-1">
<div class="article-meta-clip top">
<div class="article-content-meta top hide">
<div class="article-meta top">
@ -147,10 +154,10 @@ The <a href="http://Zammad.org" title="http://Zammad.org" target="_blank">Zammad
</div>
</div>
</div>
<div class="article-content zIndex-1 horizontal reverse">
<div class="article-content zIndex-1">
<span class="avatar unique user-popover " data-id="2" style="background-position: -96.5079185759074px -112.28590086669901px;" data-placement="left" data-original-title="" title="">NB</span>
<div class="flex bubble-gap internal-border">
<div class="text-bubble"><div class="bubble-arrow"></div>Ich wollte mir die Lyrics von Maria herunterladen, aber ich schaff es einfach nicht, da raufzukommen. Schick mir bitte mein Passwort.
<div class="textBubble"><div class="bubble-arrow"></div>Ich wollte mir die Lyrics von Maria herunterladen, aber ich schaff es einfach nicht, da raufzukommen. Schick mir bitte mein Passwort.
Grüße, Peter</div>
</div>
@ -182,7 +189,7 @@ Grüße, Peter</div>
<small class="task-subline zIndex-1"><time class="humanTimeFromNow" data-time="2014-07-11T10:10:32.000Z" data-tooltip="2014-07-11 12:10">2014-07-11</time></small>
</div>
<div class="ticket-article-item bubble-grid agent note" data-id="23" id="article-23">
<div class="ticket-article-item agent note" data-id="23" id="article-23">
<div class="article-meta-clip top">
<div class="article-content-meta top hide">
<div class="article-meta top">
@ -193,15 +200,34 @@ Grüße, Peter</div>
</div>
</div>
</div>
<div class="article-content zIndex-1 horizontal">
<div class="article-content zIndex-1">
<span class="avatar user-popover " data-id="3" style="background-image: url(api/v1/users/image/bb100af55234cf61fb6f207636f095f8)" data-placement="right" data-original-title="" title=""></span>
<div class="flex bubble-gap internal-border">
<div class="text-bubble"><div class="bubble-arrow"></div>Lieber HP,<br>
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="textBubble-content">Lieber HP,<br>
anbei findest du die Midi Noten für Maria Maria "I Like it Loud".<br>
Wünsche dir einen guten Auftritt in Hamburg.<br>
<br>
Deine Frau bekommt ein Kind haben wir gehört.<br>
Gratulation dazu! Wir schicken dir was liebes.<br>
<br>
Und wenn du noch mal Probleme mit der Stimme hast sag bescheid ich kenn da ein Wundermittel.<br>
<br>
Das ist eine Pille von einem Druiden aus dem Bayerischen Wald. Die ölt einem so richtig die Stimmbänder.<br>
<br>
Verwende ich immer wenn ich meine Frau anschreien will. Die macht meinen Tenor richtig zum Löwen.<br>
<br>
Ach ja und dein Freund Tim. Richt dem mal aus dass er das doch bitte sein lassen soll mit den Anrufen.<br>
<br>Ich weiß schon dass ich ein hübscher bin. Aber ich hab ihm schon tausend mal gesagt, dass ich seine Gefühle leider nicht erwiedern kann.<br>
<br>
Bin verheiratet, hab Kind. Is doch offensichtlich, Junge!<br>
Alles gute,<br>
Oliver<br>
<div class="textBubble-overflowContainer">
<div class="btn btn--text js-unfold"><%- @T('See more') %></div>
</div>
</div>
<div class="attachments">
<div class="paperclip icon"></div>
<h3>2 <%- @T('Attached Files') %></h3>
@ -213,7 +239,8 @@ Oliver<br>
<div class="attachment-name u-highlight">lyrics_I_Like_it_Loud.txt</div>
<div class="attachment-size">17.1kb</div>
</div>
</div></div>
</div>
</div>
</div>
</div>
<div class="article-meta-clip bottom">

View file

@ -9,10 +9,10 @@
<div class="ticket-edit">
<div class="article-content zIndex-5">
<div class="internal-border">
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-textarea ticketEdit-body" contenteditable="true"><%- @content %></div>
<!-- .text-bubble grows with textarea (and expanding clone) -->
<!-- .textBubble grows with textarea (and expanding clone) -->
<div class="attachments"></div>
<!--
</div>

View file

@ -80,24 +80,24 @@
<div class="dropdown js-recipientDropdown">
<div class="dropdown-toggle u-positionOrigin" data-toggle="dropdown">
<input id="customer_id_autocompletion2" name="customer_id_autocompletion" class="ui-autocomplete-input form-control" autocapitalize="off" placeholder="Enter Person or Organisation/Company" autocomplete="off" role="textbox" aria-autocomplete="list" aria-haspopup="true">
<input id="customer_id_autocompletion2" name="customer_id_autocompletion" class="ui-autocomplete-input form-control" autocapitalize="off" placeholder="Enter Person or Organization/Company" autocomplete="off" role="textbox" aria-autocomplete="list" aria-haspopup="true">
<span class="select-arrow icon"></span>
</div>
<div class="dropdown-menu" aria-labelledby="customer_id">
<ul class="recipientList" role="menu">
<li class="recipientList-entry u-clickable horizontal center js-organisation" data-organisation-id="AlbrechtBertschlerGmbG">
<li class="recipientList-entry u-clickable horizontal center js-organization" data-organization-id="AlbrechtBertschlerGmbG">
<div class="recipientList-iconSpacer centered">
<div class="white organisation icon"></div>
<div class="white organization icon"></div>
</div>
<div class="recipientList-name flex u-textTruncat">
Albrecht &amp; Bertschler GmbH
<span class="recipientList-detail">- 4 Personen</span>
</div>
<div class="white right arrow icon"></div> <li class="recipientList-entry u-clickable horizontal center js-organisation" data-organisation-id="BENCHMARKhumanresources">
<div class="white right arrow icon"></div> <li class="recipientList-entry u-clickable horizontal center js-organization" data-organization-id="BENCHMARKhumanresources">
<div class="recipientList-iconSpacer centered">
<div class="white organisation icon"></div>
<div class="white organization icon"></div>
</div>
<div class="recipientList-name flex u-textTruncat">
BENCHMARK human resources
@ -134,14 +134,14 @@
<li class="recipientList-entry u-clickable horizontal center">
<div class="recipientList-iconSpacer centered">
<div class="white organisation icon"></div>
<div class="white organization icon"></div>
</div>
<div class="recipientList-name flex u-textTruncat">
Benteler SGL Composite Technology GmbH
<span class="recipientList-detail"></span>
</div>
<li class="recipientList-entry u-clickable horizontal center js-organisation">
<li class="recipientList-entry u-clickable horizontal center js-organization">
<div class="recipientList-iconSpacer centered">
<div class="white team icon"></div>
</div>
@ -151,9 +151,9 @@
</div>
<div class="white right arrow icon"></div>
<li class="recipientList-entry u-clickable horizontal center js-organisation">
<li class="recipientList-entry u-clickable horizontal center js-organization">
<div class="recipientList-iconSpacer centered">
<div class="white organisation icon"></div>
<div class="white organization icon"></div>
</div>
<div class="recipientList-name flex u-textTruncat">
Bernecker + Rainer Industrie-Elektronik Ges.m.b.H.
@ -161,9 +161,9 @@
</div>
<div class="white right arrow icon"></div>
<li class="recipientList-entry u-clickable horizontal center js-organisation">
<li class="recipientList-entry u-clickable horizontal center js-organization">
<div class="recipientList-iconSpacer centered">
<div class="white organisation icon"></div>
<div class="white organization icon"></div>
</div>
<div class="recipientList-name flex u-textTruncat">
Bertsch Ecopower GmbH
@ -178,7 +178,7 @@
<div class="recipientList-name flex u-textTruncat">
<%- @T('Create new Customer') %>
</div>
</ul> <ul class="recipientList-organisationMembers hide" id="AlbrechtBertschlerGmbG">
</ul> <ul class="recipientList-organizationMembers hide" id="AlbrechtBertschlerGmbG">
<li class="recipientList-controls u-clickable js-back">
<div class="recipientList-backClickArea centered">
<div class="recipientList-backButton">
@ -222,7 +222,7 @@
Katharina Nussman
<span class="recipientList-detail">- Albrecht &amp; Bertschler GmbG</span>
</div>
</ul> <ul class="recipientList-organisationMembers hide" id="BENCHMARKhumanresources">
</ul> <ul class="recipientList-organizationMembers hide" id="BENCHMARKhumanresources">
<li class="recipientList-controls u-clickable js-back">
<div class="recipientList-backClickArea centered">
<div class="recipientList-backButton">

View file

@ -19,6 +19,9 @@
<li><a href="#layout_ref/organization_profile">Organization Profile</a></li>
<li><a href="#layout_ref/setup">Setup Wizard</a></li>
<li><a href="#layout_ref/richtext">Richtext</a></li>
<li><a href="#layout_ref/local_modal">Local Modal</a></li>
<li><a href="#layout_ref/loading_placeholder">Loading Placeholder</a></li>
<li><a href="#layout_ref/insufficient_rights">Insufficient Rights Warning</a></li>
</ul>
</div>

View file

@ -0,0 +1,3 @@
<div class="flex fullscreenMessage">
<div class="error icon"></div><h2>Opps.. I'm sorry, but you have insufficient rights to open this ticket.</h2>
</div>

View file

@ -0,0 +1,3 @@
<div class="flex fullscreenMessage">
<div class="loading icon"></div><h2>Loading Ticket</h2>
</div>

View file

@ -0,0 +1,537 @@
<div class="flex profile">
<div class="modal modal--local">
<div class="modal-backdrop"></div>
<div class="modal-dialog">
<form>
<div class="modal-content">
<div class="modal-header">
<div class="modal-close js-close">
<div class="close icon"></div>
</div>
<h1 class="modal-title">Edit Customer</h1>
</div>
<div class="modal-body">
<fieldset>
<div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_firstname">Firstname <span>*</span></label>
</div>
<div class="controls"><input id="User_968887_firstname" type="text" name="firstname" value="Nicole" class="form-control " required="" autofocus="">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_lastname">Lastname <span>*</span></label>
</div>
<div class="controls"><input id="User_968887_lastname" type="text" name="lastname" value="Braun" class="form-control " required="">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_email">Email <span>*</span></label>
</div>
<div class="controls"><input id="User_968887_email" type="email" name="email" value="nicole.braun@zammad.org" class="form-control " required="">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_web">Web <span></span></label>
</div>
<div class="controls"><input id="User_968887_web" type="url" name="web" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_phone">Phone <span></span></label>
</div>
<div class="controls"><input id="User_968887_phone" type="phone" name="phone" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_mobile">Mobile <span></span></label>
</div>
<div class="controls"><input id="User_968887_mobile" type="phone" name="mobile" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_fax">Fax <span></span></label>
</div>
<div class="controls"><input id="User_968887_fax" type="phone" name="fax" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="select form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_organization_id">Organization <span></span></label>
</div>
<div class="controls"><div class="u-positionOrigin">
<select id="User_968887_organization_id" class="form-control" name="organization_id">
<option value="">-</option>
<option value="1" selected="">Zammad Foundation</option>
</select>
<div class="select-arrow icon"></div>
</div>
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_department">Department <span></span></label>
</div>
<div class="controls"><input id="User_968887_department" type="text" name="department" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group">
<div class="formGroup-label">
<label for="User_968887_street">Street <span></span></label>
</div>
<div class="controls"><input id="User_968887_street" type="text" name="street" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_zip">Zip <span></span></label>
</div>
<div class="controls"><input id="User_968887_zip" type="text" name="zip" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group formGroup--halfSize">
<div class="formGroup-label">
<label for="User_968887_city">City <span></span></label>
</div>
<div class="controls"><input id="User_968887_city" type="text" name="city" value="" class="form-control ">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group">
<div class="formGroup-label">
<label for="User_968887_password">Password <span></span></label>
</div>
<div class="controls"><input id="User_968887_password" type="password" name="password" value="" class="form-control " autocomplete="off">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="input form-group">
<div class="formGroup-label">
<label for="User_968887_password_confirm">Password (confirm) <span></span></label>
</div>
<div class="controls"><input id="User_968887_password_confirm" type="password" name="password_confirm" value="" class="form-control " autocomplete="off">
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="richtext form-group">
<div class="formGroup-label">
<label for="User_968887_note">Note <span></span></label>
<div class="align-right help-message" title="Notes are visible to agents only, never to customers. ">
<div class="help icon"></div>
</div>
</div>
<div class="controls"><div class="richtext form-control">
<div contenteditable="true" id="User_968887_note" data-name="note" class=""></div>
</div>
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="checkbox form-group">
<div class="formGroup-label">
<label for="User_968887_role_ids">Roles <span>*</span></label>
</div>
<div class="controls"><div class=" checkbox">
<label><input type="checkbox" value="1" name="role_ids"> Admin - To configure your system.</label>
<label><input type="checkbox" value="2" name="role_ids"> Agent - To work on Tickets.</label>
<label><input type="checkbox" value="3" name="role_ids" checked=""> Customer - People who create Tickets ask for help.</label>
</div>
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="checkbox form-group">
<div class="formGroup-label">
<label for="User_968887_group_ids">Groups <span></span></label>
</div>
<div class="controls"><div class=" checkbox">
<label><input type="checkbox" value="1" name="group_ids"> Users - Standard Group/Pool for Tickets.</label>
</div>
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div><div class="boolean form-group">
<div class="formGroup-label">
<label for="User_968887_active">Active <span>*</span></label>
</div>
<div class="controls"><div class="u-positionOrigin">
<select id="User_968887_active" class="form-control" name="active" required="">
<option value="{boolean}::true" selected="">active</option>
<option value="{boolean}::false">inactive</option>
</select>
<div class="select-arrow icon"></div>
</div>
<span class="help-inline"></span>
<span class="help-block"></span>
</div>
</div>
</fieldset>
</div>
<div class="modal-footer horizontal">
<a class="subtle-link standalone js-cancel" href="#/">Cancel & Go Back</a>
<button type="submit" class="btn btn--success js-submit align-right">Update & Back</button>
</div>
</div>
</form>
</div>
</div>
<div class="profile-window">
<div class="profile-section vertical centered">
<div class="align-right profile-action dropdown dropdown--actions">
<div class="dropdown-toggle horizontal center" id="profileAction" data-toggle="dropdown">
<div class="light cog icon"></div>
<label>Aktion</label>
<span class="select-arrow icon"></span>
</div>
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="profileAction">
<li role="presentation"><a role="menuitem" tabindex="-1">Kontaktdaten bearbeiten</a>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Änderungsprotokoll</a>
<li role="presentation"><a role="menuitem" tabindex="-1">Benutzer zusammenführen</a>
<li role="presentation"><a role="menuitem" tabindex="-1">Benutzer löschen</a>
</ul>
</div>
<div class="avatar size-80" style="background-image: url(https://pbs.twimg.com/profile_images/1216362658/DSC_0084-p_bigger.jpg)"></div>
<h1>Doreen Kubiak</h1>
<div class="profile-subtitle">Steuerbüro C. Kaik</div>
</div>
<div class="profile-section">
<div class="profile-details horizontal wrap">
<div class="profile-detailsEntry">
<label>Email</label>
<a href="mailto:doreen.kubiak@gmail.com">doreen.kubiak@gmail.com</a>
</div>
<div class="profile-detailsEntry">
<label>Organization</label>
Steuerbüro C. Kaik
</div>
<div class="profile-detailsEntry">
<label>Web</label>
<a href="http://ckaik.com" target="_blank">chaik.com</a>
</div>
<div class="profile-detailsEntry">
<label>Strasse</label>
Johannitergasse 2/2
</div>
<div class="profile-detailsEntry">
<label>Telefon</label>
+43 5522 36346
</div>
<div class="profile-detailsEntry">
<label>PLZ, ORT</label>
6800 Feldkirch
</div>
<div class="profile-detailsEntry">
<label>Mobile-Nr.</label>
+43 699 4565789
</div>
<div class="profile-detailsEntry">
<label>Land</label>
Österreich
</div>
</div>
</div>
<div class="profile-section">
<!-- if user has organization -->
<div class="tabs wide-tabs horizontal">
<div class="tab js-userTickets active">Tickets von Doreen Kubiak</div>
<div class="tab js-organizationTickets">Tickets von Steuerbüro C. Kaik</div>
</div>
<!-- endif -->
<div class="profile-ticketLists horizontal">
<div class="profile-ticketList">
<label>Offene Tickets (0)</label>
<div class="profile-ticketsPlaceholder vertical centered">
<div class="mood icon supergood-state"></div>
Keine offenen Tickets
</div>
<a href="#">Alle Tickets von Doreen Kubiak …</a>
</div>
<div class="profile-ticketList">
<label>Bearbeitete Tickets (12)</label>
<ol class="tasks tasks--standalone">
<li class="task level-1">
<div class="icon-holder">
<div class="priority icon"></div>
</div>
<div class="flex">
<div class="name">Micro-SIM doesn't work</div>
<div class="time">23 minutes ago</div>
</div>
<li class="task level-1">
<div class="icon-holder">
<div class="priority icon"></div>
</div>
<div class="flex">
<div class="name">Superb Service!</div>
<div class="time">43 minutes ago</div>
</div>
<li class="task level-1">
<div class="icon-holder">
<div class="priority icon"></div>
</div>
<div class="flex">
<div class="name">Print sheets strip off</div>
<div class="time">1 hour ago</div>
</div>
<li class="task level-1">
<div class="icon-holder">
<div class="priority icon"></div>
</div>
<div class="flex">
<div class="name">Block not properly wrought</div>
<div class="time">2 hour ago</div>
</div>
</ol>
<a href="#">Alle Tickets von Steuerbüro C. Kaik …</a>
</div>
</div>
</div>
<div class="profile-section horizontal two-columns">
<div class="column status stat-widget vertical">
<h3>Status</h3>
<div class="stat-graphic">
<div class="stat-tickets vertical reverse end">
<div class="stat-ticket icon supergood-state"></div>
<div class="stat-ticket icon supergood-state"></div>
<div class="stat-ticket icon supergood-state"></div>
<div class="stat-ticket icon supergood-state"></div>
<div class="stat-ticket icon supergood-state"></div>
<div class="stat-ticket icon supergood-state"></div>
</div>
<div class="stat-all-tickets icon"></div>
</div>
<!--
Achtung: hier müssen wir schauen, dass wir das Widget genauso verwenden wie im Dashboard. Sonst gibt's Verwirrung.
-->
<div class="stat-label">Tickets of my Group: 78 of 234</div>
<div class="stat-detail">Average: 22%</div>
</div>
<div class="column mood stat-widget vertical">
<h3>Stimmung</h3>
<div class="stat-graphic">
<div class="mood icon supergood-state"></div>
</div>
<div class="stat-label">3% of my tickets escalated.</div>
<div class="stat-detail">Average: 17%</div>
</div>
</div>
<div class="profile-section">
<div class="frequency stat-widget vertical">
<h3>Frequency</h3>
<div class="stat-graphic">
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 80%"></div>
<div class="stat-bar secondary" style="height: 34%"></div>
</div>
<div class="stat-label">Jan</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 53%"></div>
<div class="stat-bar secondary" style="height: 47%"></div>
</div>
<div class="stat-label">Feb</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 46%"></div>
<div class="stat-bar secondary" style="height: 21%"></div>
</div>
<div class="stat-label">Mär</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 24%"></div>
<div class="stat-bar secondary" style="height: 18%"></div>
</div>
<div class="stat-label">Apr</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 13%"></div>
<div class="stat-bar secondary" style="height: 5%"></div>
</div>
<div class="stat-label">Mai</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 18%"></div>
<div class="stat-bar secondary" style="height: 10%"></div>
</div>
<div class="stat-label">Jun</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 50%"></div>
<div class="stat-bar secondary" style="height: 8%"></div>
</div>
<div class="stat-label">Jul</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 67%"></div>
<div class="stat-bar secondary" style="height: 13%"></div>
</div>
<div class="stat-label">Aug</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 34%"></div>
<div class="stat-bar secondary" style="height: 2%"></div>
</div>
<div class="stat-label">Sep</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 5%"></div>
<div class="stat-bar secondary" style="height: 0%"></div>
</div>
<div class="stat-label">Okt</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 25%"></div>
<div class="stat-bar secondary" style="height: 0%"></div>
</div>
<div class="stat-label">Nov</div>
</div>
<div class="stats-row">
<div class="stat-bars">
<div class="stat-bar primary" style="height: 80%"></div>
<div class="stat-bar secondary" style="height: 5%"></div>
</div>
<div class="stat-label">Dez</div>
</div>
</div>
<div class="stat-legend">
<div class="stat-legendEntry primary"><span class="primary stat-circle"></span>Bearbeitet</div>
<div class="stat-legendEntry secondary"><span class="secondary stat-circle"></span>Offen</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -16,7 +16,7 @@
</ul>
</div>
<div class="profile-organizationIcon">
<div class="organisation icon"></div>
<div class="organization icon"></div>
</div>
<h1>Steuerbüro C. Kaik</h1>
</div>

View file

@ -4,36 +4,36 @@
<h2>Singleline / Textonly</h2>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-text-oneline text-1" contenteditable="true" data-name="body" style="min-height: 40px;"></div>
</div>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-text-oneline text-2" contenteditable="true" data-name="body" style="min-height: 40px;">some test</div>
</div>
<h2>Multiline / Textonly</h2>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-text-multiline text-3" contenteditable="true" data-name="body" style="min-height: 40px;"></div>
</div>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-text-multiline text-4" contenteditable="true" data-name="body" style="min-height: 40px;">some text <br>Multiline</div>
</div>
<h2>Multiline / Richtext</h2>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-text-richtext text-5" contenteditable="true" data-name="body" style="min-height: 40px;"></div>
</div>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-text-richtext text-6" contenteditable="true" data-name="body" style="min-height: 40px;">some text <br>Multiline <b>bolt</b></div>
</div>

View file

@ -26,7 +26,7 @@
<a href="mailto:doreen.kubiak@gmail.com">doreen.kubiak@gmail.com</a>
</div>
<div class="profile-detailsEntry">
<label>Organisation</label>
<label>Organization</label>
Steuerbüro C. Kaik
</div>
<div class="profile-detailsEntry">
@ -56,10 +56,10 @@
</div>
</div>
<div class="profile-section">
<!-- if user has organisation -->
<!-- if user has organization -->
<div class="tabs wide-tabs horizontal">
<div class="tab js-userTickets active">Tickets von Doreen Kubiak</div>
<div class="tab js-organisationTickets">Tickets von Steuerbüro C. Kaik</div>
<div class="tab js-organizationTickets">Tickets von Steuerbüro C. Kaik</div>
</div>
<!-- endif -->
<div class="profile-ticketLists horizontal">

View file

@ -5,7 +5,7 @@
<div class="white close icon"></div>
</div>
</div>
<div class="logo" title="<%- @C( 'product_name' ) %>"></div>
<div class="logo js-toggleNavigation"></div>
<ul id="global-search-result" class="custom-dropdown-menu" role="menu"></ul>
</form>

View file

@ -4,7 +4,7 @@
<div class="profile-section vertical centered">
<div class="align-right profile-action js-action"></div>
<div class="profile-organizationIcon">
<div class="organisation icon"></div>
<div class="organization icon"></div>
</div>
<h1><%= @organization.displayName() %></h1>
</div>

View file

@ -10,7 +10,7 @@
<form class="form-password">
<div class="form-password-item"></div>
<div class="form-controls">
<a class="subtle-link standalone pull-left cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
<a class="subtle-link standalone pull-left cancel" href="#login"><%- @T( 'Cancel & Go Back' ) %></a>
<button class="btn btn--primary submit pull-right"><%- @T( 'Submit' ) %></button>
</div>
</form>

View file

@ -1,18 +1,20 @@
<hr>
<div class="horizontal two-columns">
<% for row in @organizationData: %>
<% if @organization[row.name]: %>
<% if row.tag is 'richtext': %>
<div class="customer-info" title="<%- @Ti( row.display ) %>"><%- @organization[row.name] %></div>
<% else: %>
<div class="customer-info" title="<%- @Ti( row.display ) %>"><%- @L( @P( @organization[row.name] ) ) %></div>
<% end %>
<div class="column">
<h3><%- @T( row.display ) %></h3>
<div><%- @L( @P( @organization[row.name] ) ) %></div>
</div>
<% end %>
<% end %>
</div>
<% if @organization.members: %>
<hr>
<%- @T('Members') %>
<ul>
<h3><%- @T('Members') %></h3>
<% for user in @organization.members: %>
<li><%= user.displayName() %></li>
<div class="person">
<%= user.displayName() %>
</div>
<% end %>
</ul>
<% end %>

View file

@ -1,13 +1,20 @@
<div>
<div class="<%- @ticket.icon() %>" title="<%- @ticket.iconTitle() %>"></div>
<span class="<%- @ticket.icon() %>" title="<%- @ticket.iconTitle() %>"></span> <span class="<%- @ticket.iconTextClass() %>"><%- @ticket.iconTitle() %></span>
</div>
<hr>
<h3>Personen</h3>
<h3><%- @P('Agent') %></h3>
<div class="person">
<%- @P( @ticket.owner ) %>
<%= @ticket.owner.displayName() %>
<% if @ticket.owner.organization_id: %>
<span class="organization"><%= @ticket.owner.organization.displayName() %></span>
<% end %>
</div>
<h3><%- @P('Customer') %></h3>
<div class="person">
<%- @P( @ticket.customer ) %>
<%= @ticket.customer.displayName() %>
<% if @ticket.customer.organization_id: %>
<span class="organization"><%= @ticket.customer.organization.displayName() %></span>
<% end %>
</div>
<hr>
<div class="horizontal two-columns">
@ -15,10 +22,6 @@
<h3>#</h3>
<div class="u-textTruncate"><%- @P( @ticket.number ) %></div>
</div>
<div class="column">
<h3><%- @T( 'State' ) %></h3>
<div class="u-textTruncate"><%- @P( @ticket.state.name ) %></div>
</div>
<div class="column">
<h3><%- @T( 'Priority' ) %></h3>
<div class="u-textTruncate"><%- @T( @ticket.priority.name ) %></div>

View file

@ -1,15 +1,14 @@
<% if @user['organization']: %>
<div class="customer-info">
<%- @P( @user['organization'] ) %>
</div>
<div class="user-organization"><a href="<%- @user.organization.uiUrl() %>"><%= @user.organization.displayName() %></a></div>
<% end %>
<hr>
<div class="horizontal two-columns">
<% for row in @userData: %>
<% if @user[row.name]: %>
<% if row.tag is 'richtext': %>
<div class="customer-info" title="<%- @Ti( row.display ) %>"><%- @user[row.name] %></div>
<% else: %>
<div class="customer-info" title="<%- @Ti( row.display ) %>"><%- @L( @P( @user[row.name] ) ) %></div>
<% end %>
<div class="column">
<h3><%- @T( row.display ) %></h3>
<div><%- @L( @P( @user[row.name] ) ) %></div>
</div>
<% end %>
<% end %>
<% if !_.isEmpty(@user['accounts']): %>

View file

@ -4,7 +4,7 @@
<h1><%- @T( 'Join' ) %> <%= @C( 'product_name' ) %></h1>
<form>
<div class="form-controls">
<a class="subtle-link standalone pull-left" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
<a class="subtle-link standalone pull-left" href="#login"><%- @T( 'Cancel & Go Back' ) %></a>
<button class="btn btn--primary submit pull-right"><%- @T( 'Create my account' ) %></button>
</div>
</form>

View file

@ -1,9 +1,9 @@
<div class="tabsSidebar-holder">
<div class="main no-padding flex tabsSidebar-sidebarSpacer tabsSidebar-tabsSpacer">
<div class="ticketZoom">
<div class="scrollPageHeader tabsSidebar-sidebarSpacer zIndex-6 horizontal center">
<div class="scrollPageHeader">
<small><%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span></small>
<div class="ticket-title flex"></div>
<div class="ticket-title"></div>
<div class="pagination-counter">
<span class="pagination-item-current">1</span>/<span class="pagination-total-items">36</span>
</div>

View file

@ -1,5 +1,5 @@
<% for article in @articles: %>
<div class="ticket-article-item bubble-grid <%= article.sender.name.toLowerCase() %> <%= article.type.name %><%= ' is-internal' if article.internal is true %>" data-id="<%= article.id %>" id="article-<%= article.id %>">
<div class="ticket-article-item <%= article.sender.name.toLowerCase() %> <%= article.type.name %><%= ' is-internal' if article.internal is true %>" data-id="<%= article.id %>" id="article-<%= article.id %>">
<div class="article-meta-clip top">
@ -33,18 +33,23 @@
</div>
</div>
<div class="article-content zIndex-1 horizontal<%= ' reverse' if article.sender.name isnt 'Agent' %>">
<div class="article-content zIndex-1">
<% if article.sender.name isnt 'Agent': %>
<% position = 'left' %>
<% else: %>
<% position = 'right' %>
<% end %>
<%- article.created_by.avatar("40", position) %>
<div class="flex bubble-gap">
<div class="bubble-gap">
<div class="internal-border">
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="textBubble-content">
<%- article.html %>
<div class="textBubble-overflowContainer">
<div class="btn btn--text js-unfold"><%- @T('See more') %></div>
</div>
</div>
<% if !_.isEmpty( article.attachments ): %>
<div class="attachments">
<div class="paperclip icon"></div>
@ -59,17 +64,6 @@
<% end %>
</div>
</div>
<% if article.actions: %>
<div>
<div class="article-actions horizontal stretch">
<% for action in article.actions: %>
<a href="<%= action.href %>" data-type="<%= action.type %>" class="article-action u-clickable<% if action.class: %> <%= action.class %><% end %>">
<span class="<%= action.type %> action icon"></span><%- @T( action.name ) %>
</a>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
@ -90,6 +84,18 @@
</div>
</div>
<% if article.actions: %>
<div>
<div class="article-actions horizontal stretch">
<% for action in article.actions: %>
<a href="<%= action.href %>" data-type="<%= action.type %>" class="article-action u-clickable<% if action.class: %> <%= action.class %><% end %>">
<span class="<%= action.type %> action icon"></span><%- @T( action.name ) %>
</a>
<% end %>
</div>
</div>
<% end %>
<small class="task-subline zIndex-1"><time class="humanTimeFromNow" data-time="<%- article.created_at %>">?</time></small>
</div>
<% end %>

View file

@ -2,7 +2,6 @@
<input type="hidden" name="type" value="<%= @article.type %>">
<input type="hidden" name="internal" value="<%= @article.internal %>">
<input type="hidden" name="form_id" value="<%= @article.form_id %>">
<div class="bubble-grid horizontal">
<div class="editControls">
<%- App.User.fullLocal( @S('id') ).avatar("40", 'right', 'zIndex-5') %>
<div class="dark pop-select zIndex-7 editControls-item">
@ -28,7 +27,7 @@
</div>
</div>
</div>
<div class="flex article-content zIndex-5 bubble-gap">
<div class="article-content zIndex-5 bubble-gap">
<!--
<label class="recipients"><%- @T('Recipients') %>
<div class="avatar" style="background-image: url(https://pbs.twimg.com/profile_images/1216362658/DSC_0084-p_normal.jpg)"></div>
@ -50,10 +49,10 @@
<div class="controls"><input id="" type="text" name="cc" value="<%= @article.cc %>" class="form-control"></div>
</div>
<div class="text-bubble">
<div class="textBubble">
<div class="bubble-arrow"></div>
<div class="js-textarea ticketEdit-body" contenteditable="true" data-name="body"><%- @article.body %></div>
<!-- .text-bubble grows with textarea (and expanding clone) -->
<!-- .textBubble grows with textarea (and expanding clone) -->
<div class="attachments"></div>
<div class="article-attachment u-unclickable u-textTruncate">
<div class="attachmentPlaceholder">
@ -82,7 +81,5 @@
</div>
</div>
</div>
</div>
</div>
</form>

View file

@ -6,7 +6,7 @@
<%- @user.avatar("80") %>
<h1><%= @user.displayName() %></h1>
<% if @user.organization: %>
<div class="profile-organisation"><a href="<%- @user.organization.uiUrl() %>"><%= @user.organization.displayName() %></a></div>
<div class="profile-organization"><a href="<%- @user.organization.uiUrl() %>"><%= @user.organization.displayName() %></a></div>
<% end %>
</div>

View file

@ -1,22 +1,8 @@
<% if @items.length: %>
<a href="#" id="markAllAsSeen"><%- @T( 'Mark all as seen.' ) %></a>
<% for item in @items: %>
<div class="activity-entry horizontal">
<a class="activity-avatar user-popover" data-id="<%= item.created_by_id %>" href="<%- item.created_by.uiUrl() %>">
<%- item.created_by.avatar() %>
</a>
<a href="<%- item.link %>" class="activity-body flex horizontal">
<span class="activity-message flex">
<span class="activity-text <% if item.seen: %>inactive<% end %>">
<%= item.created_by.displayName() %> <%- @T( item.type ) %> <%- @T( item.object_name ) %><% if item.title: %> (<%= item.title %>)<% end %>
</span>
<span class="activity-time <% if item.seen: %>inactive<% end %> humanTimeFromNow" data-time="<%- item.created_at %>">?</span>
</span>
</a>
<div class="popover popover--notifications js-notificationsContainer" role="tooltip">
<div class="arrow"></div>
<div class="popover-notificationsHeader">
<span class="popover-title"></span>
<a class="popover-notificationsMarkRead js-markAllAsRead"><%- @T( 'Mark all as read' ) %></a>
</div>
<div class="popover-content"></div>
</div>
<% end %>
<% else: %>
<h3 class="u-textTruncate" title="<%- @Ti( 'Name') %>">
<%- @T("No unread Notifications for you. :) ") %>
</h3>
<% end %>

View file

@ -0,0 +1,21 @@
<% if @items.length: %>
<% for item in @items: %>
<div class="activity-entry horizontal">
<a class="activity-avatar user-popover" data-id="<%= item.created_by_id %>" href="<%- item.created_by.uiUrl() %>">
<%- item.created_by.avatar() %>
</a>
<a href="<%- item.link %>" class="activity-body flex horizontal">
<span class="activity-message flex">
<span class="activity-text <% if item.seen: %>inactive<% end %>">
<%= item.created_by.displayName() %> <%- @T( item.type ) %> <%- @T( item.object_name ) %><% if item.title: %> (<%= item.title %>)<% end %>
</span>
<span class="activity-time <% if item.seen: %>inactive<% end %> humanTimeFromNow" data-time="<%- item.created_at %>">?</span>
</span>
</a>
</div>
<% end %>
<% else: %>
<div class="label u-textTruncate" title="<%- @Ti( 'Name') %>">
<%- @T("No unread Notifications for you. :) ") %>
</div>
<% end %>

View file

@ -25,7 +25,11 @@
//= require ./app/lib/bootstrap/dropdown.js
//= require ./app/lib/bootstrap/tooltip.js
//= require ./app/lib/bootstrap/popover.js
//= require ./app/lib/bootstrap/popover-enhance.js
// modified by Felix Jan-2014
//= require ./app/lib/bootstrap/modal.js
//= require ./app/lib/bootstrap/tab.js
//= require ./app/lib/bootstrap/transition.js
//= require ./app/lib/bootstrap/button.js

View file

@ -18,7 +18,7 @@ p {
}
.u-highlight {
color: hsl(194,90%,45%);
color: #0F94D6;
}
a {
@ -140,6 +140,10 @@ blockquote {
display: block;
outline-style: none;
border-radius: 3px;
/* needed to make empty tags editable, otherwise no focus can be set */
min-height: 10px;
min-width: 20px;
}
[contenteditable]:hover,
[contenteditable]:focus {
@ -265,7 +269,7 @@ span[data-tooltip]:hover:before {
color: hsl(202,68%,54%);
background: white;
border-color: rgba(0,0,0,.1);
outline: none;
outline: none !important;
&.is-disabled {
pointer-events: none;
@ -275,22 +279,47 @@ span[data-tooltip]:hover:before {
&:active {
box-shadow: none;
background: hsl(0,0%,98%);
}
&.btn--action {
@extend label;
padding: 7px 11px 5px !important;
}
&.btn--primary {
color: white;
background: #419ed7;
border-color: #419ed7;
background: hsl(203,65%,55%);
&:active {
background: hsl(203,65%,45%);
}
}
&.btn--success {
color: white;
background: hsl(145,51%,45%);
&:active {
background: hsl(145,51%,35%);
}
}
&.btn--danger {
color: white;
background: hsl(0,65%,55%);
&:active {
background: hsl(0,65%,45%);
}
}
&.btn--text {
padding-left: 0;
padding-right: 0;
color: hsl(203,65%,55%);
border: none;
background: none;
&:active {
color: hsl(203,65%,45%);
}
}
&.btn--subtle {
@ -302,6 +331,10 @@ span[data-tooltip]:hover:before {
background: none;
@extend .u-clickable;
&:active {
color: rgba(0,0,0,.42);
}
&:hover {
color: rgba(0,0,0,.5);
}
@ -538,7 +571,8 @@ h5 {
}
label,
.checkbox.form-group label {
.checkbox.form-group label,
.label {
text-transform: uppercase;
color: hsl(0,0%,60%);
display: block;
@ -546,6 +580,8 @@ label,
font-weight: normal;
letter-spacing: 0.1em;
margin-bottom: 4px;
text-align: left;
padding: 0;
}
fieldset {
@ -610,6 +646,12 @@ fieldset > *:not(.form-group) .form-control {
.form-group .help-message {
cursor: help;
opacity: 0.2;
top: -2px;
position: relative;
.icon {
display: block;
}
}
.form-group:not(.formGroup--halfSize) {
@ -731,6 +773,19 @@ textarea,
z-index: 1;
}
.fullscreenMessage {
padding: 22px;
@extend .centered;
.icon {
margin: -5px 14px 0 0;
}
h2 {
margin: 0;
}
}
.form-stacked .checkbox label {
color: inherit;
font-size: 13px;
@ -739,22 +794,32 @@ textarea,
letter-spacing: inherit;
}
.pagination {
margin: 0;
@extend .horizontal;
}
.pagination > li > a,
.pagination > li > span {
padding: 0;
width: 31px;
height: 28px;
border-color: #ececec;
height: 31px;
border-color: #e5e5e5;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
background: #0F94D6;
border-color: #0F94D6;
}
.pagination-counter {
margin-right: 19px;
line-height: 28px;
margin: 0 19px 0 10px;
line-height: 33px;
color: #9c9c9b;
}
@ -771,16 +836,19 @@ textarea,
}
.page-header-title h1 {
margin-top: 13px;
margin-top: 9px;
}
.page-header-meta {
margin-top: 5px;
margin-top: 6px;
margin-left: auto;
}
@extend .horizontal;
@extend .justify;
@extend .self-start;
.page-header-meta.horizontal .pagination {
margin-left: auto;
.btn {
margin: 0 9px 2px;
}
}
.dropdown-menu .count {
@ -935,6 +1003,7 @@ textarea,
@extend .fit;
display: table;
width: 100%;
height: 100%;
min-height: 100vh;
}
@ -1279,15 +1348,15 @@ ol.tabs li {
@-moz-keyframes fade { from { opacity: 0 } to { opacity: 1 } }
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }
.organisation.icon {
.organization.icon {
height: 13px;
width: 14px;
background-position: 0 -118px;
}
.icon-switch:hover .organisation.icon,
.task.active .organisation.icon,
.white.organisation.icon {
.icon-switch:hover .organization.icon,
.task.active .organization.icon,
.white.organization.icon {
background-position: 0 -132px;
}
@ -1731,7 +1800,7 @@ ol.tabs li {
.loading.icon {
width: 30px;
height: 30px;
background: hsl(339,80%,62%);
background: hsl(145,51%,45%);
-webkit-animation: rotateplane 1.2s infinite ease-in-out;
animation: rotateplane 1.2s infinite ease-in-out;
}
@ -1742,27 +1811,28 @@ ol.tabs li {
}
@-webkit-keyframes rotateplane {
0% { -webkit-transform: perspective(120px); background: hsl(202,68%,54%); }
50% { -webkit-transform: perspective(120px) rotateY(180deg); background: hsl(145,51%,45%); }
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg); background: hsl(202,68%,54%); }
0% { -webkit-transform: perspective(120px); }
50% { -webkit-transform: perspective(120px) rotateY(180deg); }
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg); }
}
@keyframes rotateplane {
0% {
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);
background: hsl(202,68%,54%);
} 50% {
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
background: hsl(145,51%,45%);
} 100% {
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
background: hsl(202,68%,54%);
}
}
.loading.dot.icon {
border-radius: 100%;
}
/*
* removed margin of forms to not break the layout with submit buttons within <form></form> area e. g. for modal dialogs
@ -1826,6 +1896,11 @@ footer {
padding: 10px 20px;
}
.tableOverview-edit {
@extend .u-clickable;
@extend .u-highlight;
}
.bulkAction {
background: white;
z-index: 1;
@ -1912,7 +1987,7 @@ footer {
.navigation {
width: 260px;
background: #26272e;
background: hsl(232,10%,16%);
position: relative;
}
@ -1934,16 +2009,17 @@ footer {
text-decoration: none;
}
.main-navigation > li.active > a,
.main-navigation > li > a:hover,
.main-navigation > li > a:focus {
background: none;
color: #F0FAFF;
.main-navigation > li > a:hover {
background: hsl(230,10%,13%);
border-bottom-color: rgba(240, 250, 255, .08);
}
.main-navigation > li.active > a .icon,
.main-navigation > li > a:hover .icon,
.main-navigation > li > a:focus .icon {
.main-navigation > li.active > a {
background: none;
color: white;
}
.main-navigation > li.active > a .icon {
opacity: 1;
}
@ -2015,21 +2091,27 @@ footer {
.tasks-navigation .icon-holder {
width: 30px;
position: relative;
}
.tasks-navigation .icon-holder .icon {
margin-right: 3px;
margin-top: -3px;
&.loading {
width: 10px;
height: 10px;
}
&.error {
transform: scale(0.85);
}
}
.task:hover {
text-decoration: none;
}
.task .modified.priority.icon {
margin-right: 8px;
}
.task.active {
background: #389ed9;
}
@ -2128,12 +2210,12 @@ footer {
}
.search {
padding: 14px 15px 10px 10px;
padding: 14px 2px 10px 10px;
border-bottom: 1px solid rgba(240, 250, 255, .05);
}
.search-holder {
margin-right: 15px;
margin-right: 2px;
position: relative;
transition: 240ms;
}
@ -2175,12 +2257,13 @@ footer {
}
.search .logo {
width: 41px;
width: 67px;
height: 36px;
background: image_url("/assets/images/logo.svg");
background: image_url("/assets/images/logo.svg") no-repeat center;
transition: 240ms;
position: relative;
@extend .u-clickable;
@extend .zIndex-5;
}
.logo .activity-counter {
@ -2436,6 +2519,7 @@ footer {
.sidebar-block {
margin: 20px 0;
word-wrap: break-word;
&:first-child {
margin-top: 0;
@ -2552,18 +2636,18 @@ footer {
border: none;
z-index: 1110;
box-shadow: 0 1px 14px rgba(0,8,14,.25);
// max-height: calc(100vh - 20px);
}
.popover-title {
border: none;
background: none;
padding: 20px 17px 4px;
padding: 21px 17px 4px;
}
.popover-content {
padding: 0 17px 10px;
max-height: 600px;
overflow-y: scroll;
overflow-y: auto;
}
.popover.right { margin-left: 4px; }
@ -2598,16 +2682,21 @@ footer {
background: white;
}
.popover .person .company {
.popover .person .organization {
color: #a1a4a7;
}
.popover .user-organization {
margin-bottom: 8px;
margin-top: -4px;
}
.popover hr {
margin: 8px 0;
}
.popover .person .company:before { content: '('; }
.popover .person .company:after { content: ')'; }
.popover .person .organization:before { content: '('; }
.popover .person .organization:after { content: ')'; }
.popover .column h3 {
margin: 8px 0 1px;
@ -2617,6 +2706,53 @@ footer {
margin-bottom: 8px;
}
.popover--notifications {
@extend .zIndex-5;
&.is-visible {
@extend .vertical;
}
.popover-content {
@extend .flex;
}
&.is-overflowing .popover-notificationsHeader {
box-shadow:
0 1px hsla(240,4%,95%,.5),
0 2px hsla(240,4%,95%,.2);
}
}
.popover-notificationsHeader {
@extend .horizontal;
@extend .end;
padding-bottom: 22px;
margin: 21px 17px 0;
.popover-title {
@extend h1;
padding: 0;
line-height: 1;
}
}
.popover-notificationsCounter {
color: #e25253;
padding-left: 3px;
}
.popover-notificationsMarkRead {
@extend .btn;
@extend .btn--subtle;
@extend .align-right;
padding: 5px 0 0;
&:hover {
padding: 5px 0 0;
}
}
.stat-widgets {
margin: 0 -7px 20px;
}
@ -2955,6 +3091,13 @@ footer {
margin-top: 55px;
}
.ticket-article,
.ticket-edit {
max-width: 800px;
margin: 0 auto;
padding: 0 21px;
}
.ticket-title {
max-width: 800px;
padding: 0 81px;
@ -2975,49 +3118,41 @@ footer {
display: block;
}
.bubble-grid {
max-width: 800px;
margin: 0 auto;
padding: 0 21px;
}
.bubble-gap {
margin-left: 15px !important;
}
.customer.ticket-article-item .bubble-gap {
margin-left: 0 !important;
margin-right: 15px !important;
}
.ticket-article-item {
padding-bottom: 33px;
position: relative;
.avatar {
position: absolute;
right: 0;
top: 5px;
}
&.agent .avatar {
right: auto;
left: 0;
}
}
/*
clip the article-meta to not stand out on the other side
of the text-bubble if the text bubble is small
of the textBubble if the text bubble is small
*/
.article-meta-clip {
overflow: hidden;
position: relative;
height: 100%;
margin: 0 55px;
}
.article-content {
position: relative;
margin-right: 55px;
padding: 0 55px;
}
.customer.ticket-article-item .article-content {
margin-right: 0;
margin-left: 55px;
}
.article-content-meta {
padding: 0 55px;
position: absolute;
width: 100%;
}
@ -3039,7 +3174,7 @@ footer {
}
.article-meta-key {
width: 13%;
width: 20%;
text-transform: uppercase;
}
@ -3071,7 +3206,7 @@ footer {
display: none;
}
.text-bubble {
.textBubble {
padding: 10px 20px;
background: white;
border-radius: 2px;
@ -3079,32 +3214,66 @@ footer {
box-shadow: 0 0 1px rgba(0,0,0,.06) inset;
position: relative;
overflow-wrap: break-word;
}
word-wrap: break-word;
/* email css reset */
.text-bubble p {
p {
margin: 0;
}
.text-bubble blockquote,
.text-bubble pre
{
blockquote,
pre {
margin: 0px;
padding: 8px 12px 8px 12px;
}
}
.ticket-article-item.state--folde-out .text-bubble {
.ticket-article-item.state--folde-out .textBubble {
border-color: hsl(0,0%,90%);
}
.customer.ticket-article-item .text-bubble {
.textBubble-content {
overflow: hidden;
position: relative;
}
.textBubble-overflowContainer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: white;
.btn {
padding: 7px 0;
font-size: 10px;
}
&:before {
content: "";
position: absolute;
left: 0;
right: 0;
top: -30px;
height: 30px;
background: linear-gradient(rgba(255,255,255,0), white);
}
}
.customer .textBubble-overflowContainer {
background: #e5f0f5;
&:before {
background: linear-gradient(hsla(199,44%,93%,0), hsl(199,44%,93%));
}
}
.customer.ticket-article-item .textBubble {
background: #e5f0f5;
border-color: hsl(199,38%,92%);
box-shadow: none;
}
.customer.ticket-article-item.state--folde-out .text-bubble {
.customer.ticket-article-item.state--folde-out .textBubble {
border-color: hsl(199,44%,85%);
}
@ -3150,7 +3319,7 @@ footer {
}
.ticket-article-item .attachments:not(:empty) {
border-top: 1px solid hsl(0,0%,93%);
border-top: 1px solid rgba(0,0,0,.04);
white-space: normal;
margin: 0 -20px;
padding: 26px 20px 7px 72px;
@ -3196,6 +3365,10 @@ footer {
vertical-align: top;
}
.article-add {
position: relative;
}
.ticket-edit {
margin-top: auto;
margin-bottom: 36px;
@ -3215,7 +3388,9 @@ footer {
}
.editControls {
position: relative;
position: absolute;
left: 0;
top: 5px;
}
.editControls-item {
@ -3392,14 +3567,14 @@ footer {
.recipient-list input::-moz-placeholder { opacity: 1; color: #666; }
.recipient-list input:-ms-input-placeholder { color: #666; }
.ticket-edit .text-bubble {
.ticket-edit .textBubble {
border-color: #b3b3b3;
border-radius: 5px;
padding-left: 12px;
padding-right: 12px;
}
.ticket-edit .text-bubble [contenteditable],
.ticket-edit .textBubble [contenteditable],
.ticket-edit textarea,
.ticketEdit-body {
width: 100%;
@ -3981,6 +4156,22 @@ footer {
border: none;
}
.modal.modal--local {
display: block;
padding-left: 40px;
position: absolute;
overflow: auto;
background: hsla(210,17%,98%,.55);
.modal-backdrop {
display: none;
}
.modal-dialog {
box-shadow: 0 0 40px hsla(210,17%,40%,.34);
}
}
.caret {
position: absolute;
top: 50%;
@ -4051,7 +4242,7 @@ footer {
}
.recipientList,
.recipientList-organisationMembers {
.recipientList-organizationMembers {
list-style: none;
padding: 0;
}
@ -4121,7 +4312,7 @@ footer {
margin-bottom: -2px;
}
.recipientList-organisationMembers {
.recipientList-organizationMembers {
position: absolute;
top: 0;
left: 0;
@ -4273,6 +4464,10 @@ footer {
}
.scrollPageHeader {
@extend .tabsSidebar-sidebarSpacer;
@extend .zIndex-6;
@extend .horizontal;
@extend .center;
background: white;
border-bottom: 1px solid hsl(0,0%,78%);
height: 64px;
@ -4292,6 +4487,8 @@ footer {
.scrollPageHeader .ticket-title {
max-width: initial;
padding: 0;
min-width: 0;
@extend .flex;
}
.scrollPageHeader h1 {
@ -4708,6 +4905,7 @@ label + .wizard-buttonList {
.profile-details {
margin-left: -50px;
word-wrap: break-word;
}
.profile-ticketsPlaceholder {
@ -5024,6 +5222,13 @@ body.fit {
align-items: flex-end;
}
.self-start {
-webkit-align-self: start;
-moz-align-self: start;
-ms-align-self: start;
align-self: start;
}
.two-columns,
.three-columns,
.wrap {

View file

@ -59,7 +59,7 @@ class LongPollingController < ApplicationController
user_id = session[:user_id]
user = {}
if user_id
user = User.find( user_id )
user = User.find( user_id ).attributes
end
log 'notice', "send auth login (user_id #{user_id})", client_id
Sessions.create( client_id, user, { :type => 'ajax' } )

View file

@ -88,4 +88,30 @@ curl http://localhost/api/v1/online_notifications -v -u #{login}:#{password} -H
model_update_render(OnlineNotification, params)
end
=begin
Resource:
PUT /api/v1/online_notifications/mark_all_as_read
Payload:
{}
Response:
{}
Test:
curl http://localhost/api/v1/online_notifications/mark_all_as_read -v -u #{login}:#{password} -X POST -d '{}'
=end
def mark_all_as_read
notifications = OnlineNotification.list(current_user,100)
notifications.each do |notification|
if !notification['seen']
OnlineNotification.seen( :id => notification['id'] )
end
end
render :json => {}, :status => :ok
end
end

View file

@ -228,22 +228,6 @@ class TicketsController < ApplicationController
ticket = Ticket.find( params[:id] )
return if !ticket_permission( ticket )
# get signature
signature = {}
if ticket.group.signature
signature = ticket.group.signature.attributes
# replace tags
signature['body'] = NotificationFactory.build(
:locale => current_user.preferences[:locale],
:string => signature['body'],
:objects => {
:ticket => ticket,
:user => current_user,
}
)
end
# get attributes to update
attributes_to_change = Ticket::ScreenOptions.attributes_to_change( :user => current_user, :ticket => ticket )
@ -292,7 +276,6 @@ class TicketsController < ApplicationController
render :json => {
:ticket_id => ticket.id,
:ticket_article_ids => article_ids,
:signature => signature,
:assets => assets,
:links => link_list,
:tags => tags,

View file

@ -47,15 +47,12 @@ add a new online notification for this user
=begin
add a new online notification for this user
mark online notification as seen
OnlineNotification.add(
:type => 'Assigned to you',
:object => 'Ticket',
:o_id => ticket.id,
:seen => 1,
:created_by_id => 1,
:user_id => 2,
OnlineNotification.seen(
:id => 2,
:user => UserObject, #optional, if passed all
#notfications for the given user are marked as seen
)
=end
@ -86,7 +83,7 @@ remove whole online notifications of an object
return all online notifications of an user
notifications = OnlineNotification.list( user )
notifications = OnlineNotification.list( user, limit )
=end

View file

@ -4,5 +4,6 @@ Zammad::Application.routes.draw do
# groups
match api_path + '/online_notifications', :to => 'online_notifications#index', :via => :get
match api_path + '/online_notifications/:id', :to => 'online_notifications#update', :via => :put
match api_path + '/online_notifications/mark_all_as_read', :to => 'online_notifications#mark_all_as_read', :via => :post
end

View file

@ -34,7 +34,7 @@ class CreateObjectManager < ActiveRecord::Migration
:multiple => false,
:null => false,
:limit => 200,
:placeholder => 'Enter Person or Organisation/Company',
:placeholder => 'Enter Person or Organization/Company',
:minLengt => 2,
:translate => false,
},
@ -168,7 +168,7 @@ class CreateObjectManager < ActiveRecord::Migration
:null => false,
:default => 2,
:translate => true,
:filter => [1,2,3,4],
:filter => [1,2,3,4,7],
},
:editable => false,
:active => true,
@ -190,7 +190,7 @@ class CreateObjectManager < ActiveRecord::Migration
:Agent => {
:nulloption => false,
:null => false,
:filter => [2,3,4],
:filter => [2,3,4,7],
},
:Customer => {
:nulloption => false,
@ -217,10 +217,10 @@ class CreateObjectManager < ActiveRecord::Migration
:null => true,
:translate => true,
:required_if => {
:state_id => [3]
:state_id => [3,7]
},
:shown_if => {
:state_id => [3]
:state_id => [3,7]
},
},
:editable => false,

View file

@ -37,7 +37,7 @@ returns
:user => session,
:meta => meta,
}
file.write Marshal.dump(data)
file.write data.to_json
}
# send update to browser
@ -195,7 +195,7 @@ returns
path = @path + '/' + client_id.to_s
data[:meta][:last_ping] = Time.new.to_i.to_s
File.open( path + '/session', 'wb' ) { |file|
file.write Marshal.dump(data)
file.write data.to_json
}
true
end
@ -234,7 +234,11 @@ returns
file.flock( File::LOCK_EX )
all = file.read
file.flock( File::LOCK_UN )
data = Marshal.load( all )
dataJSON = JSON.parse( all )
if dataJSON
data = self.symbolize_keys(dataJSON)
data[:user] = dataJSON['user'] # for compat. reasons
end
}
rescue Exception => e
puts e.inspect
@ -567,4 +571,19 @@ returns
puts "/LOOP #{client_id} - #{try_count}"
end
def self.symbolize_keys(hash)
hash.inject({}){|result, (key, value)|
new_key = case key
when String then key.to_sym
else key
end
new_value = case value
when Hash then symbolize_keys(value)
else value
end
result[new_key] = new_value
result
}
end
end

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="333px" height="362px" viewBox="0 0 333 362" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.1.1 (8761) - http://www.bohemiancoding.com/sketch -->
<svg width="341px" height="362px" viewBox="0 0 341 362" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>Slice 2</title>
<desc>Created with Sketch.</desc>
<defs>
@ -16,12 +16,12 @@
<path d="M128.5,24.5 C128.5,-6.98023232 102.980232,-32.5 71.5,-32.5 C40.0197677,-32.5 14.5,-6.98023228 14.5,24.5 C14.5,55.9802323 40.0197677,81.5 71.5,81.5 C102.980232,81.5 128.5,55.9802323 128.5,24.5 Z M15.5,24.5 C15.5,-6.42794753 40.5720525,-31.5 71.5,-31.5 C102.427948,-31.5 127.5,-6.42794757 127.5,24.5 C127.5,55.4279476 102.427948,80.5 71.5,80.5 C40.5720525,80.5 15.5,55.4279475 15.5,24.5 Z" id="Oval-1-copy" opacity="0.34" fill="#EEEEEE" sketch:type="MSShapeGroup" mask="url(#mask-2)"></path>
<path d="M146.5,23 C146.5,-17.5929312 113.592931,-50.5 73,-50.5 C32.4070689,-50.5 -0.5,-17.5929311 -0.5,23 C-0.5,63.5929311 32.4070689,96.5 73,96.5 C113.592931,96.5 146.5,63.5929312 146.5,23 Z M0.5,23 C0.5,-17.0406463 32.9593537,-49.5 73,-49.5 C113.040647,-49.5 145.5,-17.0406464 145.5,23 C145.5,63.0406464 113.040647,95.5 73,95.5 C32.9593537,95.5 0.5,63.0406463 0.5,23 Z" id="Oval-1-copy-2" opacity="0.21" fill="#EEEEEE" sketch:type="MSShapeGroup" mask="url(#mask-2)"></path>
</g>
<path d="M12,2 C6.47711111,2 2,6.47711111 2,12 C2,17.5228889 6.47711111,22 12,22 C17.5231111,22 22,17.5228889 22,12 C22,6.47711111 17.5231111,2 12,2 L12,2 L12,2 Z M12,20.1248889 C10.6193333,20.1248889 9.5,19.0055556 9.5,17.6248889 C9.5,17.52 12,9.18755556 12,9.18755556 C12,9.18755556 14.5,17.52 14.5,17.6248889 C14.5,19.0055556 13.3806667,20.1248889 12,20.1248889 L12,20.1248889 L12,20.1248889 Z M18.372,15.9544444 C19.0862222,14.8064444 19.5,13.452 19.5,12 C19.5,7.85777778 16.1424444,4.5 12,4.5 C7.85777778,4.5 4.5,7.85777778 4.5,12 C4.5,13.452 4.91377778,14.8064444 5.62777778,15.9544444 L4.61155556,16.6853333 C3.75088889,15.3302222 3.25,13.7242222 3.25,12 C3.25,7.16755556 7.16755556,3.25 12,3.25 C16.8326667,3.25 20.75,7.16755556 20.75,12 C20.75,13.7242222 20.2488889,15.3302222 19.3882222,16.6853333 L18.372,15.9544444 L18.372,15.9544444 Z" id="dashboard" fill="#F0FAFF" sketch:type="MSShapeGroup"></path>
<path d="M34,7 L44,7 C45.308403,7 46,6.10537191 46,5 C46,3.8946281 45.308403,3 44,3 L34,3 C32.692595,3 32,3.8946281 32,5 C32,6.10537191 32.692595,7 34,7 L34,7 Z M44,10 L34,10 C32.692595,10 32,10.8970323 32,12 C32,13.1052903 32.692595,14 34,14 L44,14 C45.308403,14 46,13.1052903 46,12 C46,10.8972903 45.308403,10 44,10 L44,10 Z M44,18 L34,18 C32.692595,18 32,18.897464 32,20 C32,21.1043428 32.692595,22 34,22 L44,22 C45.308403,22 46,21.1043428 46,20 C46,18.897464 45.308403,18 44,18 L44,18 Z M28,3 C26.6750463,3 26,3.8946281 26,5 C26,6.10511364 26.6750463,7 28,7 C29.3251486,7 30,6.10537191 30,5 C30,3.8946281 29.3249537,3 28,3 L28,3 Z M28,10 C26.6750463,10 26,10.8970323 26,12 C26,13.1052903 26.6750463,14 28,14 C29.3251486,14 30,13.1052903 30,12 C30,10.8972903 29.3249537,10 28,10 L28,10 Z M28,18 C26.6750463,18 26,18.897464 26,20 C26,21.1043428 26.6750463,22 28,22 C29.3251486,22 30,21.1043428 30,20 C30,18.897464 29.3249537,18 28,18 L28,18 Z" id="overviews" fill="#F0FAFF" sketch:type="MSShapeGroup"></path>
<path d="M52.6384286,5.44643478 C54.0955925,5.44643478 55.2768571,4.2272089 55.2768571,2.72321739 C55.2768571,1.21922588 54.0955925,0 52.6384286,0 C51.1812646,0 50,1.21922588 50,2.72321739 C50,4.2272089 51.1812646,5.44643478 52.6384286,5.44643478 L52.6384286,5.44643478 L52.6384286,5.44643478 Z M59.6386813,5.44695652 C61.0959848,5.44695652 62.2773626,4.22761384 62.2773626,2.72347826 C62.2773626,1.21934268 61.0959848,0 59.6386813,0 C58.1813778,0 57,1.21934268 57,2.72347826 C57,4.22761384 58.1813778,5.44695652 59.6386813,5.44695652 L59.6386813,5.44695652 L59.6386813,5.44695652 Z M65.6386813,5.44695652 C67.0959848,5.44695652 68.2773626,4.22761384 68.2773626,2.72347826 C68.2773626,1.21934268 67.0959848,0 65.6386813,0 C64.1813778,0 63,1.21934268 63,2.72347826 C63,4.22761384 64.1813778,5.44695652 65.6386813,5.44695652 L65.6386813,5.44695652 L65.6386813,5.44695652 Z M63.2232198,6.31121739 L55.6989341,6.31121739 C55.055945,6.31121739 54.5347802,6.84913043 54.5347802,7.51226087 L54.5347802,14.3783478 C54.5347802,15.0422609 55.055945,15.5793913 55.6989341,15.5793913 L56.0570769,15.5793913 L56.0570769,24.0706957 L62.7278352,24.0706957 L62.7278352,15.5793913 L63.2232198,15.5793913 C63.8662088,15.5793913 64.3868681,15.042 64.3868681,14.3783478 L64.3868681,7.51226087 C64.3866154,6.8493913 63.8662088,6.31121739 63.2232198,6.31121739 L63.2232198,6.31121739 L63.2232198,6.31121739 Z M52.8934396,14.3786091 L52.8934396,7.51252217 C52.8934396,7.08313087 52.9902418,6.67878304 53.1532637,6.3114787 L49.2675275,6.3114787 C48.625044,6.3114787 48.1038791,6.84939174 48.1038791,7.51252217 L48.1038791,14.3786091 C48.1038791,15.0425222 48.625044,15.5796526 49.2675275,15.5796526 L49.6259231,15.5796526 L49.6259231,24.070957 L54.4152308,24.070957 L54.4152308,16.9533917 C53.5121648,16.4723483 52.8934396,15.4985222 52.8934396,14.3786091 L52.8934396,14.3786091 L52.8934396,14.3786091 Z M69.7572418,6.31121783 L65.7691429,6.31121783 C65.9321648,6.67852217 66.0292198,7.08313087 66.0292198,7.5122613 L66.0292198,14.3783483 C66.0292198,15.5543483 65.3468022,16.5675657 64.3696813,17.020957 L64.3696813,24.0706961 L69.2623626,24.0706961 L69.2623626,15.5793917 L69.756989,15.5793917 C70.3997253,15.5793917 70.9211429,15.0420004 70.9211429,14.3783483 L70.9211429,7.5122613 C70.9213956,6.84939174 70.3997253,6.31121783 69.7572418,6.31121783 L69.7572418,6.31121783 L69.7572418,6.31121783 Z" id="group" fill="#F0FAFF" sketch:type="MSShapeGroup"></path>
<path d="M92.9411437,4.85790489 C92.8674423,4.34072579 92.6070309,4.09021716 92.0980002,4.03466081 C91.9142382,4.01546861 91.7285108,4.001327 91.5437661,4.001327 C86.1851864,3.99930677 80.8266068,3.99930677 75.4670445,4.00334723 C75.219408,4.00334723 74.969806,4.03466081 74.7241349,4.07708566 C74.3408878,4.13971281 74.1237145,4.39527202 74.0618054,4.78113612 C74.0244634,5.01346267 74.0028443,5.25286003 74.0028443,5.48922704 C73.9989136,9.13271344 73.9998963,12.7772099 74.0008789,16.4206963 C74.0008789,16.5247382 74.0028443,16.6297902 74.0087404,16.7338321 C74.0559093,17.5469751 74.3389225,17.8429389 75.1329317,17.8580906 C76.1873524,17.8772828 77.1995176,17.8742525 78.2539383,17.8803131 C78.476025,17.8823334 78.9133197,17.8803131 78.9133197,17.8803131 L78.9133197,18.2338536 C78.9133197,19.5752869 78.9545925,20.91571 78.9585232,22.2591636 C78.9595059,22.5157329 78.9044755,22.8308889 79.2061598,22.9642242 C79.5009652,23.0945291 79.694554,22.83998 79.8812641,22.6642199 C81.5174341,21.133895 83.1565522,19.6055903 84.7858434,18.0681946 C84.9352115,17.9277886 85.0855623,17.8772828 85.2830819,17.8782929 C87.2828452,17.8823334 89.2826086,17.8823334 91.2804066,17.8803131 C91.5309911,17.8803131 91.7825584,17.870212 92.0311777,17.8469793 C92.6237365,17.7944533 92.8733384,17.5530357 92.958832,16.9510069 C92.9843818,16.7641356 92.9981394,16.5722137 92.9981394,16.3833221 C93.0001048,12.7974122 93.0010874,9.21049233 92.9981394,5.62256228 C92.996174,5.3690233 92.9765203,5.11043375 92.9411437,4.85790489 L92.9411437,4.85790489 L92.9411437,4.85790489 Z M77.9975446,8 C77.446616,8 77,8.44386482 77,9 C77,9.55228475 77.4463114,10 77.9975446,10 L85.0024554,10 C85.553384,10 86,9.55613518 86,9 C86,8.44771525 85.5536886,8 85.0024554,8 L77.9975446,8 L77.9975446,8 Z M78.0006529,12 C77.4480076,12 77,12.4438648 77,13 C77,13.5522847 77.4484532,14 78.0006529,14 L89.027347,14 C89.5799924,14 90.028,13.5561352 90.028,13 C90.028,12.4477153 89.5795467,12 89.027347,12 L78.0006529,12 L78.0006529,12 Z" id="message" fill="#F0FAFF" sketch:type="MSShapeGroup"></path>
<path d="M107.950737,21.9834667 C109.580384,21.9834667 110.901474,20.8678797 110.901474,19.4917333 C110.901474,18.1155869 109.580384,17 107.950737,17 C106.32109,17 105,18.1155869 105,19.4917333 C105,20.8678797 106.32109,21.9834667 107.950737,21.9834667 L107.950737,21.9834667 Z M107.950737,13.9834667 C109.580384,13.9834667 110.901474,12.8678797 110.901474,11.4917333 C110.901474,10.1155869 109.580384,9 107.950737,9 C106.32109,9 105,10.1155869 105,11.4917333 C105,12.8678797 106.32109,13.9834667 107.950737,13.9834667 L107.950737,13.9834667 Z M107.950737,6.98346666 C109.580384,6.98346666 110.901474,5.86787972 110.901474,4.49173333 C110.901474,3.11558694 109.580384,2 107.950737,2 C106.32109,2 105,3.11558694 105,4.49173333 C105,5.86787972 106.32109,6.98346666 107.950737,6.98346666 L107.950737,6.98346666 Z" id="tools" fill="#F0FAFF" sketch:type="MSShapeGroup"></path>
<path d="M132.638681,5.44695652 C134.095985,5.44695652 135.277363,4.22761384 135.277363,2.72347826 C135.277363,1.21934268 134.095985,0 132.638681,0 C131.181378,0 130,1.21934268 130,2.72347826 C130,4.22761384 131.181378,5.44695652 132.638681,5.44695652 L132.638681,5.44695652 L132.638681,5.44695652 Z M136.22322,6.31121739 L128.698934,6.31121739 C128.055945,6.31121739 127.53478,6.84913043 127.53478,7.51226087 L127.53478,14.3783478 C127.53478,15.0422609 128.055945,15.5793913 128.698934,15.5793913 L129.057077,15.5793913 L129.057077,24.0706957 L135.727835,24.0706957 L135.727835,15.5793913 L136.22322,15.5793913 C136.866209,15.5793913 137.386868,15.042 137.386868,14.3783478 L137.386868,7.51226087 C137.386615,6.8493913 136.866209,6.31121739 136.22322,6.31121739 L136.22322,6.31121739 L136.22322,6.31121739 Z" id="person" fill="#F0FAFF" sketch:type="MSShapeGroup"></path>
<path d="M12,2 C6.47711111,2 2,6.47711111 2,12 C2,17.5228889 6.47711111,22 12,22 C17.5231111,22 22,17.5228889 22,12 C22,6.47711111 17.5231111,2 12,2 L12,2 L12,2 Z M12,20.1248889 C10.6193333,20.1248889 9.5,19.0055556 9.5,17.6248889 C9.5,17.52 12,9.18755556 12,9.18755556 C12,9.18755556 14.5,17.52 14.5,17.6248889 C14.5,19.0055556 13.3806667,20.1248889 12,20.1248889 L12,20.1248889 L12,20.1248889 Z M18.372,15.9544444 C19.0862222,14.8064444 19.5,13.452 19.5,12 C19.5,7.85777778 16.1424444,4.5 12,4.5 C7.85777778,4.5 4.5,7.85777778 4.5,12 C4.5,13.452 4.91377778,14.8064444 5.62777778,15.9544444 L4.61155556,16.6853333 C3.75088889,15.3302222 3.25,13.7242222 3.25,12 C3.25,7.16755556 7.16755556,3.25 12,3.25 C16.8326667,3.25 20.75,7.16755556 20.75,12 C20.75,13.7242222 20.2488889,15.3302222 19.3882222,16.6853333 L18.372,15.9544444 L18.372,15.9544444 Z" id="dashboard" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M34,7 L44,7 C45.308403,7 46,6.10537191 46,5 C46,3.8946281 45.308403,3 44,3 L34,3 C32.692595,3 32,3.8946281 32,5 C32,6.10537191 32.692595,7 34,7 L34,7 Z M44,10 L34,10 C32.692595,10 32,10.8970323 32,12 C32,13.1052903 32.692595,14 34,14 L44,14 C45.308403,14 46,13.1052903 46,12 C46,10.8972903 45.308403,10 44,10 L44,10 Z M44,18 L34,18 C32.692595,18 32,18.897464 32,20 C32,21.1043428 32.692595,22 34,22 L44,22 C45.308403,22 46,21.1043428 46,20 C46,18.897464 45.308403,18 44,18 L44,18 Z M28,3 C26.6750463,3 26,3.8946281 26,5 C26,6.10511364 26.6750463,7 28,7 C29.3251486,7 30,6.10537191 30,5 C30,3.8946281 29.3249537,3 28,3 L28,3 Z M28,10 C26.6750463,10 26,10.8970323 26,12 C26,13.1052903 26.6750463,14 28,14 C29.3251486,14 30,13.1052903 30,12 C30,10.8972903 29.3249537,10 28,10 L28,10 Z M28,18 C26.6750463,18 26,18.897464 26,20 C26,21.1043428 26.6750463,22 28,22 C29.3251486,22 30,21.1043428 30,20 C30,18.897464 29.3249537,18 28,18 L28,18 Z" id="overviews" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M52.6384286,5.44643478 C54.0955925,5.44643478 55.2768571,4.2272089 55.2768571,2.72321739 C55.2768571,1.21922588 54.0955925,0 52.6384286,0 C51.1812646,0 50,1.21922588 50,2.72321739 C50,4.2272089 51.1812646,5.44643478 52.6384286,5.44643478 L52.6384286,5.44643478 L52.6384286,5.44643478 Z M59.6386813,5.44695652 C61.0959848,5.44695652 62.2773626,4.22761384 62.2773626,2.72347826 C62.2773626,1.21934268 61.0959848,0 59.6386813,0 C58.1813778,0 57,1.21934268 57,2.72347826 C57,4.22761384 58.1813778,5.44695652 59.6386813,5.44695652 L59.6386813,5.44695652 L59.6386813,5.44695652 Z M65.6386813,5.44695652 C67.0959848,5.44695652 68.2773626,4.22761384 68.2773626,2.72347826 C68.2773626,1.21934268 67.0959848,0 65.6386813,0 C64.1813778,0 63,1.21934268 63,2.72347826 C63,4.22761384 64.1813778,5.44695652 65.6386813,5.44695652 L65.6386813,5.44695652 L65.6386813,5.44695652 Z M63.2232198,6.31121739 L55.6989341,6.31121739 C55.055945,6.31121739 54.5347802,6.84913043 54.5347802,7.51226087 L54.5347802,14.3783478 C54.5347802,15.0422609 55.055945,15.5793913 55.6989341,15.5793913 L56.0570769,15.5793913 L56.0570769,24.0706957 L62.7278352,24.0706957 L62.7278352,15.5793913 L63.2232198,15.5793913 C63.8662088,15.5793913 64.3868681,15.042 64.3868681,14.3783478 L64.3868681,7.51226087 C64.3866154,6.8493913 63.8662088,6.31121739 63.2232198,6.31121739 L63.2232198,6.31121739 L63.2232198,6.31121739 Z M52.8934396,14.3786091 L52.8934396,7.51252217 C52.8934396,7.08313087 52.9902418,6.67878304 53.1532637,6.3114787 L49.2675275,6.3114787 C48.625044,6.3114787 48.1038791,6.84939174 48.1038791,7.51252217 L48.1038791,14.3786091 C48.1038791,15.0425222 48.625044,15.5796526 49.2675275,15.5796526 L49.6259231,15.5796526 L49.6259231,24.070957 L54.4152308,24.070957 L54.4152308,16.9533917 C53.5121648,16.4723483 52.8934396,15.4985222 52.8934396,14.3786091 L52.8934396,14.3786091 L52.8934396,14.3786091 Z M69.7572418,6.31121783 L65.7691429,6.31121783 C65.9321648,6.67852217 66.0292198,7.08313087 66.0292198,7.5122613 L66.0292198,14.3783483 C66.0292198,15.5543483 65.3468022,16.5675657 64.3696813,17.020957 L64.3696813,24.0706961 L69.2623626,24.0706961 L69.2623626,15.5793917 L69.756989,15.5793917 C70.3997253,15.5793917 70.9211429,15.0420004 70.9211429,14.3783483 L70.9211429,7.5122613 C70.9213956,6.84939174 70.3997253,6.31121783 69.7572418,6.31121783 L69.7572418,6.31121783 L69.7572418,6.31121783 Z" id="group" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M92.9411437,4.85790489 C92.8674423,4.34072579 92.6070309,4.09021716 92.0980002,4.03466081 C91.9142382,4.01546861 91.7285108,4.001327 91.5437661,4.001327 C86.1851864,3.99930677 80.8266068,3.99930677 75.4670445,4.00334723 C75.219408,4.00334723 74.969806,4.03466081 74.7241349,4.07708566 C74.3408878,4.13971281 74.1237145,4.39527202 74.0618054,4.78113612 C74.0244634,5.01346267 74.0028443,5.25286003 74.0028443,5.48922704 C73.9989136,9.13271344 73.9998963,12.7772099 74.0008789,16.4206963 C74.0008789,16.5247382 74.0028443,16.6297902 74.0087404,16.7338321 C74.0559093,17.5469751 74.3389225,17.8429389 75.1329317,17.8580906 C76.1873524,17.8772828 77.1995176,17.8742525 78.2539383,17.8803131 C78.476025,17.8823334 78.9133197,17.8803131 78.9133197,17.8803131 L78.9133197,18.2338536 C78.9133197,19.5752869 78.9545925,20.91571 78.9585232,22.2591636 C78.9595059,22.5157329 78.9044755,22.8308889 79.2061598,22.9642242 C79.5009652,23.0945291 79.694554,22.83998 79.8812641,22.6642199 C81.5174341,21.133895 83.1565522,19.6055903 84.7858434,18.0681946 C84.9352115,17.9277886 85.0855623,17.8772828 85.2830819,17.8782929 C87.2828452,17.8823334 89.2826086,17.8823334 91.2804066,17.8803131 C91.5309911,17.8803131 91.7825584,17.870212 92.0311777,17.8469793 C92.6237365,17.7944533 92.8733384,17.5530357 92.958832,16.9510069 C92.9843818,16.7641356 92.9981394,16.5722137 92.9981394,16.3833221 C93.0001048,12.7974122 93.0010874,9.21049233 92.9981394,5.62256228 C92.996174,5.3690233 92.9765203,5.11043375 92.9411437,4.85790489 L92.9411437,4.85790489 L92.9411437,4.85790489 Z M77.9975446,8 C77.446616,8 77,8.44386482 77,9 C77,9.55228475 77.4463114,10 77.9975446,10 L85.0024554,10 C85.553384,10 86,9.55613518 86,9 C86,8.44771525 85.5536886,8 85.0024554,8 L77.9975446,8 L77.9975446,8 Z M78.0006529,12 C77.4480076,12 77,12.4438648 77,13 C77,13.5522847 77.4484532,14 78.0006529,14 L89.027347,14 C89.5799924,14 90.028,13.5561352 90.028,13 C90.028,12.4477153 89.5795467,12 89.027347,12 L78.0006529,12 L78.0006529,12 Z" id="message" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M107.950737,21.9834667 C109.580384,21.9834667 110.901474,20.8678797 110.901474,19.4917333 C110.901474,18.1155869 109.580384,17 107.950737,17 C106.32109,17 105,18.1155869 105,19.4917333 C105,20.8678797 106.32109,21.9834667 107.950737,21.9834667 L107.950737,21.9834667 Z M107.950737,13.9834667 C109.580384,13.9834667 110.901474,12.8678797 110.901474,11.4917333 C110.901474,10.1155869 109.580384,9 107.950737,9 C106.32109,9 105,10.1155869 105,11.4917333 C105,12.8678797 106.32109,13.9834667 107.950737,13.9834667 L107.950737,13.9834667 Z M107.950737,6.98346666 C109.580384,6.98346666 110.901474,5.86787972 110.901474,4.49173333 C110.901474,3.11558694 109.580384,2 107.950737,2 C106.32109,2 105,3.11558694 105,4.49173333 C105,5.86787972 106.32109,6.98346666 107.950737,6.98346666 L107.950737,6.98346666 Z" id="tools" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M132.638681,5.44695652 C134.095985,5.44695652 135.277363,4.22761384 135.277363,2.72347826 C135.277363,1.21934268 134.095985,0 132.638681,0 C131.181378,0 130,1.21934268 130,2.72347826 C130,4.22761384 131.181378,5.44695652 132.638681,5.44695652 L132.638681,5.44695652 L132.638681,5.44695652 Z M136.22322,6.31121739 L128.698934,6.31121739 C128.055945,6.31121739 127.53478,6.84913043 127.53478,7.51226087 L127.53478,14.3783478 C127.53478,15.0422609 128.055945,15.5793913 128.698934,15.5793913 L129.057077,15.5793913 L129.057077,24.0706957 L135.727835,24.0706957 L135.727835,15.5793913 L136.22322,15.5793913 C136.866209,15.5793913 137.386868,15.042 137.386868,14.3783478 L137.386868,7.51226087 C137.386615,6.8493913 136.866209,6.31121739 136.22322,6.31121739 L136.22322,6.31121739 L136.22322,6.31121739 Z" id="person" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M5.92009147,43.374 C3.47609147,43.358 1.50109147,41.359 1.51609147,38.916 C1.53409147,36.491 3.51809147,34.516 5.94709147,34.516 L5.97609147,34.516 C7.15809147,34.523 8.26709147,34.992 9.09709147,35.834 C9.92809147,36.674 10.3820915,37.791 10.3750915,38.974 C10.3650915,40.15 9.90309147,41.258 9.06709147,42.087 C8.23309147,42.917 7.12309147,43.374 5.94909147,43.374 L5.92009147,43.374 M5.98309147,33 L5.94509147,33 C2.68109147,33 0.0220914661,35.636 9.14660647e-05,38.907 C-0.0179085339,42.191 2.62309147,44.869 5.90709147,44.89 L5.94909147,44.89 C7.03809147,44.89 8.06209147,44.596 8.94009147,44.08 L12.5530915,47.695 L12.6450915,47.783 C12.7820915,47.92 12.9600915,47.988 13.1390915,47.988 C13.3180915,47.988 13.4970915,47.92 13.6330915,47.783 L14.7970915,46.622 C15.0690915,46.348 15.0690915,45.905 14.7970915,45.633 L14.7060915,45.54 L11.0880915,41.924 C11.5930915,41.058 11.8830915,40.056 11.8900915,38.983 C11.9140915,35.699 9.26709147,33.022 5.98309147,33" id="Search" fill-opacity="0.5" fill="#ECECEC" sketch:type="MSShapeGroup"></path>
<path d="M20,67.09 L20,64.814 L19.678,64.709 L17.242,63.914 L16.592,62.344 L17.842,59.701 L16.232,58.09 L15.93,58.246 L13.644,59.405 L12.076,58.755 L11.09,56 L8.814,56 L7.914,58.758 L6.344,59.408 L3.699,58.16 L2.09,59.768 L2.244,60.072 L3.402,62.356 L2.754,63.925 L0,64.911 L0,67.187 L0.32,67.291 L2.758,68.088 L3.408,69.656 L2.158,72.301 L3.768,73.911 L4.068,73.757 L6.353,72.597 L7.924,73.248 L8.91,76 L11.186,76 L11.291,75.68 L12.086,73.244 L13.654,72.594 L16.299,73.842 L17.908,72.234 L17.756,71.932 L16.596,69.648 L17.246,68.078 L20,67.09 L20,67.09 Z M10,69.188 C8.24,69.188 6.812,67.762 6.812,66 C6.812,64.24 8.24,62.815 10,62.815 C11.76,62.815 13.185,64.24 13.185,66 C13.185,67.762 11.76,69.188 10,69.188 L10,69.188 L10,69.188 Z" id="cog" fill="#4D4D4D" sketch:type="MSShapeGroup"></path>
<path d="M31,66 L31,59 L30,59 L30,66 L23,66 L23,67 L30,67 L30,74 L31,74 L31,67 L38,67 L38,66 L31,66 L31,66 Z" id="green-plus" stroke="#38AE6A" stroke-width="2" sketch:type="MSShapeGroup"></path>
@ -48,11 +48,11 @@
<path d="M302.175676,150.983471 C302.783784,150.586777 303.290541,149.991736 303.594595,149.297521 C302.986486,149.694215 302.277027,149.892562 301.567568,149.991736 C300.959459,149.396694 300.148649,149 299.337838,149 C297.614865,149 296.195946,150.38843 296.195946,152.07438 C296.195946,152.272727 296.195946,152.570248 296.297297,152.768595 C293.662162,152.669421 291.432432,151.380165 289.912162,149.595041 C289.608108,150.090909 289.506757,150.586777 289.506757,151.082645 C289.506757,152.173554 290.013514,153.066116 290.925676,153.661157 C290.418919,153.661157 289.912162,153.46281 289.506757,153.264463 C289.506757,154.752066 290.621622,155.942149 292.040541,156.239669 C291.736486,156.338843 291.533784,156.338843 291.22973,156.338843 C291.027027,156.338843 290.824324,156.338843 290.621622,156.239669 C291.027027,157.429752 292.141892,158.322314 293.560811,158.322314 C292.445946,159.115702 291.128378,159.61157 289.709459,159.61157 L289,159.61157 C290.418919,160.504132 292.040541,161 293.763514,161 C299.540541,161 302.581081,156.338843 302.581081,152.371901 L302.581081,151.975207 C303.087838,151.578512 303.594595,151.082645 304,150.487603 C303.391892,150.68595 302.885135,150.884298 302.175676,150.983471 L302.175676,150.983471 L302.175676,150.983471 Z" id="white-twitter" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M321.477026,147.553638 L315.974463,153.109896 L317.159843,154.306505 L322.662407,148.750246 L321.477026,147.553638 L321.477026,147.553638 Z M314.68,154.365057 L314.68,155.542857 L315.88896,155.542857 L316.48144,154.953957 L315.28432,153.826257 L314.68,154.365057 L314.68,154.365057 Z M317.07408,156.592857 L313.56,156.592857 L313.56,153.254007 L318.84,148.253907 L318.84,147.142857 L311.8,147.142857 L311.8,151.642857 L307,151.642857 L307,162.142857 L318.84,162.142857 L318.84,154.920657 L317.07408,156.592857 L317.07408,156.592857 Z M307,150.442857 L310.52,150.442857 L310.52,147.142857 L307,150.442857 L307,150.442857 Z" id="white-note" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M331.405533,156.216441 C328.929541,153.8896 328.929541,152.776762 328.929541,152.776762 L330.683368,150.955756 C330.373869,149.235917 329.23904,146.40324 327.27888,147.111409 C325.31872,147.718411 324.596556,150.551088 325.215554,152.270927 C328.310543,160.465456 335.429019,161.982961 336.460682,161.982961 C339.03984,162.185295 340.690501,160.566623 341,158.138614 C341,158.239781 338.317676,156.621109 337.07968,156.418775 L335.016354,158.442115 C335.016354,158.442115 333.881524,158.543282 331.405533,156.216441 L331.405533,156.216441 Z" id="white-phone" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M60.1875,168.146809 C60.1875,167.330851 60.125,166.57766 60,165.761702 C59.75,164.192553 58.9375,163.376596 57.3125,163.188298 C56.75,163.125532 56.125,163.062766 55.5625,163.062766 L4.6875,163.062766 C3.875,163.062766 3.125,163.188298 2.3125,163.31383 C1.125,163.502128 0.4375,164.318085 0.1875,165.510638 C0.0625,166.26383 0,166.954255 0,167.707447 L0,201.475532 L0,202.417021 C0.125,204.92766 1.0625,205.869149 3.5625,205.869149 C6.875,205.931915 10.375,205.931915 13.75,205.931915 C14.4375,205.931915 15.5625,205.994681 15.5625,205.994681 L15.5625,207.061702 C15.5625,211.204255 15.625,215.346808 15.625,219.489362 C15.625,220.305319 15.625,221.246808 16.5625,221.68617 C17.5,222.062766 18.0625,221.309574 18.625,220.744681 C23.8125,215.974468 28.9375,211.267021 34.125,206.559574 C34.625,206.120213 35.0625,205.994681 35.6875,205.994681 L54.6875,205.994681 C55.5,205.994681 56.25,205.931915 57.0625,205.869149 C58.9375,205.680851 59.75,204.990425 60,203.107447 C60.0625,202.542553 60.125,201.914894 60.125,201.35 C60.1875,190.303191 60.1875,179.256383 60.1875,168.146809 L60.1875,168.146809 L60.1875,168.146809 Z M45.6875,183.587234 C46.3125,187.290425 44.75,189.487234 42.3125,189.926596 C39.9375,190.365957 37.625,188.796808 37,185.093617 L45.6875,183.587234 L45.6875,183.587234 Z M18.25,189.989362 C15.875,189.55 14.25,187.353191 14.875,183.65 L23.5625,185.156383 C22.875,188.859574 20.625,190.365957 18.25,189.989362 L18.25,189.989362 L18.25,189.989362 Z M38,197.897872 C38.4375,198.4 38.4375,199.215957 37.9375,199.655319 C37.4375,200.094681 36.625,200.094681 36.1875,199.592553 C34.5625,197.835106 32.4375,196.893617 30.0625,196.893617 C27.75,196.893617 25.5,197.897872 23.9375,199.592553 C23.6875,199.843617 23.375,199.969149 23,199.969149 C22.6875,199.969149 22.375,199.843617 22.125,199.655319 C21.625,199.215957 21.5625,198.4 22.0625,197.897872 C24.125,195.638298 27,194.382979 30,194.382979 C33,194.382979 35.9375,195.638298 38,197.897872 L38,197.897872 L38,197.897872 Z" id="super-bad" fill="#F35910" sketch:type="MSShapeGroup"></path>
<path d="M121.202991,168.146809 C121.202991,167.330851 121.140491,166.57766 121.015491,165.761702 C120.765491,164.192553 119.952991,163.376596 118.327991,163.188298 C117.765491,163.125532 117.140491,163.062766 116.577991,163.062766 L65.7029905,163.062766 C64.8904905,163.062766 64.1404905,163.188298 63.3279905,163.31383 C62.1404905,163.502128 61.4529905,164.318085 61.2029905,165.510638 C61.0779905,166.26383 61.0154905,166.954255 61.0154905,167.707447 L61.0154905,201.475532 L61.0154905,202.417021 C61.1404905,204.92766 62.0779905,205.869149 64.5779905,205.869149 C67.8904905,205.931915 71.3904905,205.931915 74.7654905,205.931915 C75.4529905,205.931915 76.5779905,205.994681 76.5779905,205.994681 L76.5779905,207.061702 C76.5779905,211.204255 76.6404905,215.346808 76.6404905,219.489362 C76.6404905,220.305319 76.6404905,221.246808 77.5779905,221.68617 C78.5154905,222.062766 79.0779905,221.309574 79.6404905,220.744681 C84.8279905,215.974468 89.9529905,211.267021 95.1404905,206.559574 C95.6404905,206.120213 96.0779905,205.994681 96.7029905,205.994681 L115.702991,205.994681 C116.515491,205.994681 117.265491,205.931915 118.077991,205.869149 C119.952991,205.680851 120.765491,204.990425 121.015491,203.107447 C121.077991,202.542553 121.140491,201.914894 121.140491,201.35 C121.202991,190.303191 121.202991,179.256383 121.202991,168.146809 L121.202991,168.146809 L121.202991,168.146809 Z M96.0154905,196.893617 C96.0154905,197.584043 95.4529905,198.148936 94.7654905,198.148936 L87.2654905,198.148936 C86.5779905,198.148936 86.0154905,197.584043 86.0154905,196.893617 C86.0154905,196.203192 86.5779905,195.638298 87.2654905,195.638298 L94.7654905,195.638298 C95.4529905,195.638298 96.0154905,196.203192 96.0154905,196.893617 L96.0154905,196.893617 L96.0154905,196.893617 Z M98.4529905,182.457447 L107.265491,182.457447 C107.265491,186.223404 105.265491,188.106383 102.890491,188.106383 C100.51549,188.106383 98.4529905,186.223404 98.4529905,182.457447 L98.4529905,182.457447 L98.4529905,182.457447 Z M75.3279905,182.457447 L84.1404905,182.457447 C84.1404905,186.223404 82.1404905,188.106383 79.7654905,188.106383 C77.3904905,188.106383 75.3279905,186.223404 75.3279905,182.457447 L75.3279905,182.457447 L75.3279905,182.457447 Z" id="bad" fill="#F6820B" sketch:type="MSShapeGroup"></path>
<path d="M182.218481,168.146809 C182.218481,167.330851 182.155981,166.57766 182.030981,165.761702 C181.780981,164.192553 180.968481,163.376596 179.343481,163.188298 C178.780981,163.125532 178.155981,163.062766 177.593481,163.062766 L126.718481,163.062766 C125.905981,163.062766 125.155981,163.188298 124.343481,163.31383 C123.155981,163.502128 122.468481,164.318085 122.218481,165.510638 C122.093481,166.26383 122.030981,166.954255 122.030981,167.707447 L122.030981,201.475532 L122.030981,202.417021 C122.155981,204.92766 123.093481,205.869149 125.593481,205.869149 C128.905981,205.931915 132.405981,205.931915 135.780981,205.931915 C136.468481,205.931915 137.593481,205.994681 137.593481,205.994681 L137.593481,207.061702 C137.593481,211.204255 137.655981,215.346808 137.655981,219.489362 C137.655981,220.305319 137.655981,221.246808 138.593481,221.68617 C139.530981,222.062766 140.093481,221.309574 140.655981,220.744681 C145.843481,215.974468 150.968481,211.267021 156.155981,206.559574 C156.655981,206.120213 157.093481,205.994681 157.718481,205.994681 L176.718481,205.994681 C177.530981,205.994681 178.280981,205.931915 179.093481,205.869149 C180.968481,205.680851 181.780981,204.990425 182.030981,203.107447 C182.093481,202.542553 182.155981,201.914894 182.155981,201.35 C182.218481,190.303191 182.218481,179.256383 182.218481,168.146809 L182.218481,168.146809 L182.218481,168.146809 Z M144.718481,181.453192 C144.718481,183.901064 142.718481,185.846809 140.343481,185.846809 C137.905981,185.846809 135.968481,183.838298 135.968481,181.453192 C135.968481,179.005319 137.968481,177.059574 140.343481,177.059574 C142.718481,176.996808 144.718481,179.005319 144.718481,181.453192 L144.718481,181.453192 L144.718481,181.453192 Z M167.843481,181.453192 C167.843481,183.901064 165.843481,185.846809 163.468481,185.846809 C161.030981,185.846809 159.093481,183.838298 159.093481,181.453192 C159.093481,179.005319 161.093481,177.059574 163.468481,177.059574 C165.843481,176.996808 167.843481,179.005319 167.843481,181.453192 L167.843481,181.453192 L167.843481,181.453192 Z M160.155981,193.755319 C160.155981,194.445745 159.593481,195.010638 158.905981,195.010638 L145.155981,195.010638 C144.468481,195.010638 143.905981,194.445745 143.905981,193.755319 C143.905981,193.064894 144.468481,192.5 145.155981,192.5 L158.905981,192.5 C159.593481,192.5 160.155981,193.064894 160.155981,193.755319 L160.155981,193.755319 L160.155981,193.755319 Z" id="ok" fill="#FAAB00" sketch:type="MSShapeGroup"></path>
<path d="M243.218481,168.146809 C243.218481,167.330851 243.155981,166.57766 243.030981,165.761702 C242.780981,164.192553 241.968481,163.376596 240.343481,163.188298 C239.780981,163.125532 239.155981,163.062766 238.593481,163.062766 L187.718481,163.062766 C186.905981,163.062766 186.155981,163.188298 185.343481,163.31383 C184.155981,163.502128 183.468481,164.318085 183.218481,165.510638 C183.093481,166.26383 183.030981,166.954255 183.030981,167.707447 L183.030981,201.475532 L183.030981,202.417021 C183.155981,204.92766 184.093481,205.869149 186.593481,205.869149 C189.905981,205.931915 193.343481,205.931915 196.655981,205.931915 C197.343481,205.931915 198.405981,205.994681 198.405981,205.994681 L198.405981,207.061702 C198.405981,211.204255 198.530981,215.346808 198.593481,219.489362 C198.593481,220.305319 198.655981,221.246808 199.593481,221.68617 C200.530981,222.062766 201.093481,221.309574 201.655981,220.744681 C206.843481,215.974468 211.968481,211.267021 217.155981,206.559574 C217.655981,206.120213 218.093481,205.994681 218.718481,205.994681 L237.718481,205.994681 C238.530981,205.994681 239.280981,205.931915 240.093481,205.869149 C241.968481,205.680851 242.780981,204.990425 243.030981,203.107447 C243.093481,202.542553 243.155981,201.914894 243.155981,201.35 C243.218481,190.303191 243.218481,179.256383 243.218481,168.146809 L243.218481,168.146809 L243.218481,168.146809 Z M201.780981,183.33617 C199.343481,183.33617 197.405981,181.32766 197.405981,178.942553 C197.405981,176.494681 199.405981,174.548936 201.780981,174.548936 C204.218481,174.548936 206.155981,176.557447 206.155981,178.942553 C206.218481,181.32766 204.218481,183.33617 201.780981,183.33617 L201.780981,183.33617 L201.780981,183.33617 Z M229.343481,178.942553 C229.343481,181.390425 227.343481,183.33617 224.968481,183.33617 C222.530981,183.33617 220.593481,181.32766 220.593481,178.942553 C220.593481,176.494681 222.593481,174.548936 224.968481,174.548936 C227.343481,174.48617 229.343481,176.494681 229.343481,178.942553 L229.343481,178.942553 L229.343481,178.942553 Z M221.093481,190.303191 C221.593481,190.742553 221.655981,191.558511 221.155981,192.060638 C219.093481,194.320213 216.218481,195.575532 213.155981,195.575532 C210.093481,195.575532 207.218481,194.320213 205.155981,192.060638 C204.718481,191.558511 204.718481,190.742553 205.218481,190.303191 C205.718481,189.86383 206.530981,189.86383 206.968481,190.365957 C208.593481,192.123404 210.718481,193.064894 213.093481,193.064894 C215.405981,193.064894 217.655981,192.060638 219.218481,190.365957 C219.780981,189.86383 220.593481,189.86383 221.093481,190.303191 L221.093481,190.303191 L221.093481,190.303191 Z" id="happy" fill="#A9AC41" sketch:type="MSShapeGroup"></path>
<path d="M304.003335,168.146809 C304.003335,167.330851 303.940835,166.57766 303.815835,165.761702 C303.565835,164.192553 302.753335,163.376596 301.128335,163.188298 C300.565835,163.125532 299.940835,163.062766 299.378335,163.062766 L248.503335,163.062766 C247.690835,163.062766 246.940835,163.188298 246.128335,163.31383 C244.940835,163.502128 244.253335,164.318085 244.003335,165.510638 C243.878335,166.26383 243.815835,166.954255 243.815835,167.707447 L243.815835,201.475532 L243.815835,202.417021 C243.940835,204.92766 244.878335,205.869149 247.378335,205.869149 C250.690835,205.931915 254.128335,205.931915 257.440835,205.931915 C258.128335,205.931915 259.190835,205.994681 259.190835,205.994681 L259.190835,207.061702 C259.190835,211.204255 259.315835,215.346808 259.378335,219.489362 C259.378335,220.305319 259.440835,221.246808 260.378335,221.68617 C261.315835,222.062766 261.878335,221.309574 262.440835,220.744681 C267.628335,215.974468 272.753335,211.267021 277.940835,206.559574 C278.440835,206.120213 278.878335,205.994681 279.503335,205.994681 L298.503335,205.994681 C299.315835,205.994681 300.065835,205.931915 300.878335,205.869149 C302.753335,205.680851 303.565835,204.990425 303.815835,203.107447 C303.878335,202.542553 303.940835,201.914894 303.940835,201.35 C304.003335,190.303191 304.003335,179.256383 304.003335,168.146809 L304.003335,168.146809 L304.003335,168.146809 Z M263.315835,183.712766 L284.565835,183.712766 C284.565835,188.734043 279.815835,193.943617 273.940835,193.943617 C268.065835,193.943617 263.315835,188.734043 263.315835,183.712766 L263.315835,183.712766 L263.315835,183.712766 Z M267.440835,178.691489 L257.440835,178.691489 C256.753335,178.691489 256.190835,178.126596 256.190835,177.43617 C256.190835,176.745745 256.753335,176.180851 257.440835,176.180851 L258.065835,176.180851 C258.440835,173.230851 260.253335,171.787234 262.378335,171.787234 C264.503335,171.787234 266.315835,173.293617 266.690835,176.180851 L267.440835,176.180851 C268.128335,176.180851 268.690835,176.745745 268.690835,177.43617 C268.690835,178.126596 268.128335,178.691489 267.440835,178.691489 L267.440835,178.691489 L267.440835,178.691489 Z M291.815835,177.43617 C291.815835,178.126596 291.253335,178.691489 290.565835,178.691489 L280.565835,178.691489 C279.878335,178.691489 279.315835,178.126596 279.315835,177.43617 C279.315835,176.745745 279.878335,176.180851 280.565835,176.180851 L281.190835,176.180851 C281.565835,173.230851 283.378335,171.787234 285.503335,171.787234 C287.628335,171.787234 289.440835,173.293617 289.815835,176.180851 L290.565835,176.180851 C291.253335,176.180851 291.815835,176.745745 291.815835,177.43617 L291.815835,177.43617 L291.815835,177.43617 Z" id="super-happy" fill="#38AE6A" sketch:type="MSShapeGroup"></path>
<path d="M60,168.107871 C60,167.288089 59.9376947,166.531367 59.8130841,165.711585 C59.5638629,164.135082 58.7538941,163.315301 57.1339564,163.12612 C56.5732087,163.06306 55.9501558,163 55.3894081,163 L4.6728972,163 C3.86292835,163 3.1152648,163.12612 2.30529595,163.252241 C1.12149533,163.441421 0.436137072,164.261202 0.186915888,165.459345 C0.062305296,166.216067 0,166.909727 0,167.66645 L0,201.592798 L0,202.538699 C0.124610592,205.061105 1.05919003,206.007006 3.55140187,206.007006 C6.85358255,206.070067 10.3426791,206.070067 13.7071651,206.070067 C14.3925234,206.070067 15.5140187,206.133127 15.5140187,206.133127 L15.5140187,207.205149 C15.5140187,211.367117 15.576324,215.529085 15.576324,219.691054 C15.576324,220.510835 15.576324,221.456737 16.5109034,221.898158 C17.4454829,222.276519 18.0062305,221.519797 18.5669782,220.952256 C23.7383178,216.159687 28.847352,211.430177 34.0186916,206.700667 C34.517134,206.259247 34.953271,206.133127 35.576324,206.133127 L54.517134,206.133127 C55.3271028,206.133127 56.0747664,206.070067 56.8847352,206.007006 C58.7538941,205.817826 59.5638629,205.124164 59.8130841,203.232361 C59.8753894,202.664819 59.9376947,202.034219 59.9376947,201.466677 C60,190.368094 60,179.269513 60,168.107871 L60,168.107871 L60,168.107871 Z M45.6875,183.587234 C46.3125,187.290425 44.75,189.487234 42.3125,189.926596 C39.9375,190.365957 37.625,188.796808 37,185.093617 L45.6875,183.587234 L45.6875,183.587234 Z M18.25,189.989362 C15.875,189.55 14.25,187.353191 14.875,183.65 L23.5625,185.156383 C22.875,188.859574 20.625,190.365957 18.25,189.989362 L18.25,189.989362 L18.25,189.989362 Z M38,197.897872 C38.4375,198.4 38.4375,199.215957 37.9375,199.655319 C37.4375,200.094681 36.625,200.094681 36.1875,199.592553 C34.5625,197.835106 32.4375,196.893617 30.0625,196.893617 C27.75,196.893617 25.5,197.897872 23.9375,199.592553 C23.6875,199.843617 23.375,199.969149 23,199.969149 C22.6875,199.969149 22.375,199.843617 22.125,199.655319 C21.625,199.215957 21.5625,198.4 22.0625,197.897872 C24.125,195.638298 27,194.382979 30,194.382979 C33,194.382979 35.9375,195.638298 38,197.897872 L38,197.897872 L38,197.897872 Z" id="super-bad" fill="#F35910" sketch:type="MSShapeGroup"></path>
<path d="M121,168.107871 C121,167.288089 120.937695,166.531367 120.813084,165.711585 C120.563863,164.135082 119.753894,163.315301 118.133956,163.12612 C117.573209,163.06306 116.950156,163 116.389408,163 L65.6728972,163 C64.8629283,163 64.1152648,163.12612 63.3052959,163.252241 C62.1214953,163.441421 61.4361371,164.261202 61.1869159,165.459345 C61.0623053,166.216067 61,166.909727 61,167.66645 L61,201.592798 L61,202.538699 C61.1246106,205.061105 62.05919,206.007006 64.5514018,206.007006 C67.8535825,206.070067 71.342679,206.070067 74.707165,206.070067 C75.3925232,206.070067 76.5140186,206.133127 76.5140186,206.133127 L76.5140186,207.205149 C76.5140186,211.367117 76.5763239,215.529085 76.5763239,219.691054 C76.5763239,220.510835 76.5763239,221.456737 77.5109033,221.898158 C78.4454827,222.276519 79.0062304,221.519797 79.566978,220.952256 C84.7383176,216.159687 89.8473518,211.430177 95.0186913,206.700667 C95.5171337,206.259247 95.9532707,206.133127 96.5763237,206.133127 L115.517134,206.133127 C116.327103,206.133127 117.074766,206.070067 117.884735,206.007006 C119.753894,205.817826 120.563863,205.124164 120.813084,203.232361 C120.875389,202.664819 120.937695,202.034219 120.937695,201.466677 C121,190.368094 121,179.269513 121,168.107871 L121,168.107871 L121,168.107871 Z M96.0154905,196.893617 C96.0154905,197.584043 95.4529905,198.148936 94.7654905,198.148936 L87.2654905,198.148936 C86.5779905,198.148936 86.0154905,197.584043 86.0154905,196.893617 C86.0154905,196.203192 86.5779905,195.638298 87.2654905,195.638298 L94.7654905,195.638298 C95.4529905,195.638298 96.0154905,196.203192 96.0154905,196.893617 L96.0154905,196.893617 L96.0154905,196.893617 Z M98.4529905,182.457447 L107.265491,182.457447 C107.265491,186.223404 105.265491,188.106383 102.890491,188.106383 C100.51549,188.106383 98.4529905,186.223404 98.4529905,182.457447 L98.4529905,182.457447 L98.4529905,182.457447 Z M75.3279905,182.457447 L84.1404905,182.457447 C84.1404905,186.223404 82.1404905,188.106383 79.7654905,188.106383 C77.3904905,188.106383 75.3279905,186.223404 75.3279905,182.457447 L75.3279905,182.457447 L75.3279905,182.457447 Z" id="bad" fill="#F6820B" sketch:type="MSShapeGroup"></path>
<path d="M182,168.107871 C182,167.288089 181.937695,166.531367 181.813084,165.711585 C181.563863,164.135082 180.753894,163.315301 179.133956,163.12612 C178.573209,163.06306 177.950156,163 177.389408,163 L126.672897,163 C125.862928,163 125.115265,163.12612 124.305296,163.252241 C123.121495,163.441421 122.436137,164.261202 122.186916,165.459345 C122.062305,166.216067 122,166.909727 122,167.66645 L122,201.592798 L122,202.538699 C122.124611,205.061105 123.05919,206.007006 125.551402,206.007006 C128.853583,206.070067 132.342679,206.070067 135.707165,206.070067 C136.392523,206.070067 137.514019,206.133127 137.514019,206.133127 L137.514019,207.205149 C137.514019,211.367117 137.576324,215.529085 137.576324,219.691054 C137.576324,220.510835 137.576324,221.456737 138.510903,221.898158 C139.445483,222.276519 140.006231,221.519797 140.566978,220.952256 C145.738318,216.159687 150.847352,211.430177 156.018692,206.700667 C156.517134,206.259247 156.953271,206.133127 157.576324,206.133127 L176.517134,206.133127 C177.327103,206.133127 178.074766,206.070067 178.884735,206.007006 C180.753894,205.817826 181.563863,205.124164 181.813084,203.232361 C181.875389,202.664819 181.937695,202.034219 181.937695,201.466677 C182,190.368094 182,179.269513 182,168.107871 L182,168.107871 L182,168.107871 Z M144.718481,181.453192 C144.718481,183.901064 142.718481,185.846809 140.343481,185.846809 C137.905981,185.846809 135.968481,183.838298 135.968481,181.453192 C135.968481,179.005319 137.968481,177.059574 140.343481,177.059574 C142.718481,176.996808 144.718481,179.005319 144.718481,181.453192 L144.718481,181.453192 L144.718481,181.453192 Z M167.843481,181.453192 C167.843481,183.901064 165.843481,185.846809 163.468481,185.846809 C161.030981,185.846809 159.093481,183.838298 159.093481,181.453192 C159.093481,179.005319 161.093481,177.059574 163.468481,177.059574 C165.843481,176.996808 167.843481,179.005319 167.843481,181.453192 L167.843481,181.453192 L167.843481,181.453192 Z M160.155981,193.755319 C160.155981,194.445745 159.593481,195.010638 158.905981,195.010638 L145.155981,195.010638 C144.468481,195.010638 143.905981,194.445745 143.905981,193.755319 C143.905981,193.064894 144.468481,192.5 145.155981,192.5 L158.905981,192.5 C159.593481,192.5 160.155981,193.064894 160.155981,193.755319 L160.155981,193.755319 L160.155981,193.755319 Z" id="ok" fill="#FAAB00" sketch:type="MSShapeGroup"></path>
<path d="M243,168.107871 C243,167.288089 242.937695,166.531367 242.813084,165.711585 C242.563863,164.135082 241.753894,163.315301 240.133956,163.12612 C239.573209,163.06306 238.950156,163 238.389408,163 L187.672897,163 C186.862928,163 186.115265,163.12612 185.305296,163.252241 C184.121495,163.441421 183.436137,164.261202 183.186916,165.459345 C183.062305,166.216067 183,166.909727 183,167.66645 L183,201.592798 L183,202.538699 C183.124611,205.061105 184.05919,206.007006 186.551402,206.007006 C189.853583,206.070067 193.280374,206.070067 196.582555,206.070067 C197.267913,206.070067 198.327103,206.133127 198.327103,206.133127 L198.327103,207.205149 C198.327103,211.367117 198.451713,215.529085 198.514019,219.691054 C198.514019,220.510835 198.576324,221.456737 199.510903,221.898158 C200.445483,222.276519 201.006231,221.519797 201.566978,220.952256 C206.738318,216.159687 211.847352,211.430177 217.018692,206.700667 C217.517134,206.259247 217.953271,206.133127 218.576324,206.133127 L237.517134,206.133127 C238.327103,206.133127 239.074766,206.070067 239.884735,206.007006 C241.753894,205.817826 242.563863,205.124164 242.813084,203.232361 C242.875389,202.664819 242.937695,202.034219 242.937695,201.466677 C243,190.368094 243,179.269513 243,168.107871 L243,168.107871 L243,168.107871 Z M201.780981,183.33617 C199.343481,183.33617 197.405981,181.32766 197.405981,178.942553 C197.405981,176.494681 199.405981,174.548936 201.780981,174.548936 C204.218481,174.548936 206.155981,176.557447 206.155981,178.942553 C206.218481,181.32766 204.218481,183.33617 201.780981,183.33617 L201.780981,183.33617 L201.780981,183.33617 Z M229.343481,178.942553 C229.343481,181.390425 227.343481,183.33617 224.968481,183.33617 C222.530981,183.33617 220.593481,181.32766 220.593481,178.942553 C220.593481,176.494681 222.593481,174.548936 224.968481,174.548936 C227.343481,174.48617 229.343481,176.494681 229.343481,178.942553 L229.343481,178.942553 L229.343481,178.942553 Z M221.093481,190.303191 C221.593481,190.742553 221.655981,191.558511 221.155981,192.060638 C219.093481,194.320213 216.218481,195.575532 213.155981,195.575532 C210.093481,195.575532 207.218481,194.320213 205.155981,192.060638 C204.718481,191.558511 204.718481,190.742553 205.218481,190.303191 C205.718481,189.86383 206.530981,189.86383 206.968481,190.365957 C208.593481,192.123404 210.718481,193.064894 213.093481,193.064894 C215.405981,193.064894 217.655981,192.060638 219.218481,190.365957 C219.780981,189.86383 220.593481,189.86383 221.093481,190.303191 L221.093481,190.303191 L221.093481,190.303191 Z" id="happy" fill="#A9AC41" sketch:type="MSShapeGroup"></path>
<path d="M304,168.107871 C304,167.288089 303.937695,166.531367 303.813084,165.711585 C303.563863,164.135082 302.753894,163.315301 301.133956,163.12612 C300.573209,163.06306 299.950156,163 299.389408,163 L248.672897,163 C247.862928,163 247.115265,163.12612 246.305296,163.252241 C245.121495,163.441421 244.436137,164.261202 244.186916,165.459345 C244.062305,166.216067 244,166.909727 244,167.66645 L244,201.592798 L244,202.538699 C244.124611,205.061105 245.05919,206.007006 247.551402,206.007006 C250.853583,206.070067 254.280374,206.070067 257.582555,206.070067 C258.267913,206.070067 259.327103,206.133127 259.327103,206.133127 L259.327103,207.205149 C259.327103,211.367117 259.451713,215.529085 259.514019,219.691054 C259.514019,220.510835 259.576324,221.456737 260.510903,221.898158 C261.445483,222.276519 262.006231,221.519797 262.566978,220.952256 C267.738318,216.159687 272.847352,211.430177 278.018692,206.700667 C278.517134,206.259247 278.953271,206.133127 279.576324,206.133127 L298.517134,206.133127 C299.327103,206.133127 300.074766,206.070067 300.884735,206.007006 C302.753894,205.817826 303.563863,205.124164 303.813084,203.232361 C303.875389,202.664819 303.937695,202.034219 303.937695,201.466677 C304,190.368094 304,179.269513 304,168.107871 L304,168.107871 L304,168.107871 Z M263.315835,183.712766 L284.565835,183.712766 C284.565835,188.734043 279.815835,193.943617 273.940835,193.943617 C268.065835,193.943617 263.315835,188.734043 263.315835,183.712766 L263.315835,183.712766 L263.315835,183.712766 Z M267.440835,178.691489 L257.440835,178.691489 C256.753335,178.691489 256.190835,178.126596 256.190835,177.43617 C256.190835,176.745745 256.753335,176.180851 257.440835,176.180851 L258.065835,176.180851 C258.440835,173.230851 260.253335,171.787234 262.378335,171.787234 C264.503335,171.787234 266.315835,173.293617 266.690835,176.180851 L267.440835,176.180851 C268.128335,176.180851 268.690835,176.745745 268.690835,177.43617 C268.690835,178.126596 268.128335,178.691489 267.440835,178.691489 L267.440835,178.691489 L267.440835,178.691489 Z M291.815835,177.43617 C291.815835,178.126596 291.253335,178.691489 290.565835,178.691489 L280.565835,178.691489 C279.878335,178.691489 279.315835,178.126596 279.315835,177.43617 C279.315835,176.745745 279.878335,176.180851 280.565835,176.180851 L281.190835,176.180851 C281.565835,173.230851 283.378335,171.787234 285.503335,171.787234 C287.628335,171.787234 289.440835,173.293617 289.815835,176.180851 L290.565835,176.180851 C291.253335,176.180851 291.815835,176.745745 291.815835,177.43617 L291.815835,177.43617 L291.815835,177.43617 Z" id="super-happy" fill="#38AE6A" sketch:type="MSShapeGroup"></path>
<g id="stopwatch" sketch:type="MSLayerGroup" transform="translate(0.000000, 223.000000)">
<path d="M10.5,24.8 C9.5,23.9 8.4,22.9 7.5,22 L13.7,15.8 C14.5,16.7 15.4,17.7 16.3,18.7 C17.1,18.1 17.7,17.6 18.3,17.2 C22.2,14.3 26.5,12.3 31.2,11.2 C31.9,11 32.1,10.8 32.1,10.1 C32,8.4 32.1,6.7 32.1,4.9 L47.5,4.9 L47.5,10.9 C60.3,14.2 69.4,21.8 74,34.1 C77.6,43.7 77,53.3 72.6,62.5 C63.7,81.1 41.2,88.4 22.7,78.7 C3.7,68.8 -3.2,43.3 10.5,24.8 L10.5,24.8 L10.5,24.8 Z M40.0481625,75 C55.1817335,75 67.6921523,62.8930829 67.9948237,47.5576545 C68.2974951,31.4150983 55.282624,19.3081812 40.5526149,19.0055082 C25.3181533,18.7028353 12.2023918,30.9106434 12.0006108,46.5487447 C11.8997204,62.489519 24.3092486,75 40.0481625,75 L40.0481625,75 L40.0481625,75 Z M14.9,12.4 C14.6,12.9 14.5,13.5 14.1,13.9 C11.2,16.8 8.3,19.7 5.5,22.6 C4.8,23.3 4,23.4 3.1,23.1 C1.8,22.7 1,21.8 0.6,20.6 C0.3,19.7 0.4,18.9 1.1,18.1 L9.7,9.5 C10.3,8.9 11.1,8.7 11.9,8.9 C13.4,9.2 14.7,10.8 14.9,12.4 L14.9,12.4 L14.9,12.4 Z M33.7,3.9 C33.5,2.5 34,1.3 35.3,0.8 C38.2,-0.3 41.2,-0.3 44.2,0.8 C45.4,1.2 46,2.4 45.9,3.9 L33.7,3.9 L33.7,3.9 Z" id="Shape" fill="#A9BCC4" sketch:type="MSShapeGroup"></path>
<circle id="inlay" opacity="0.3" sketch:type="MSShapeGroup" cx="39.9019608" cy="46.9019608" r="24.9019608"></circle>
@ -70,7 +70,7 @@
<path d="M17.6,6.9 L7.7,2.9 L10,6.9 L7.7,11 L17.6,6.9 L17.6,6.9 Z" id="Shape" fill="#A9BCC4"></path>
</g>
</g>
<path d="M175.06066,286.954195 L175.202702,286.812154 L175.302365,286.637743 C175.414487,286.441529 175.551135,286.139765 175.678636,285.741324 C176.498746,283.17848 175.915105,280.18732 173.06066,277.332875 C170.243699,274.515914 167.118112,274.085348 164.328491,275.097711 C163.823841,275.280849 163.443803,275.472287 163.205002,275.621537 L163.050513,275.718093 L162.923629,275.848822 L146.423629,292.848822 L146.347668,292.933258 C146.158935,293.159738 145.914201,293.515622 145.675224,293.984613 C144.849092,295.605898 144.703461,297.396954 145.752299,299.09123 C146.076339,299.614679 146.505633,300.100791 147.039723,300.545867 C149.292783,302.423417 151.404521,302.890769 153.098516,302.442358 C153.341124,302.378139 153.532621,302.304275 153.67082,302.235176 L153.888539,302.126317 L154.06066,301.954195 L168.06066,287.954195 L168.5,287.514855 L168.5,286.893535 C168.5,286.259579 168.359026,285.413735 167.919766,284.535214 C167.698156,284.091994 167.414366,283.686581 167.06066,283.332875 C166.478935,282.75115 165.737193,282.469799 164.928583,282.427241 C164.327068,282.395582 163.731987,282.494762 163.15132,282.674969 C162.852797,282.767614 162.615784,282.863127 162.45787,282.937928 L162.229833,283.045946 L162.049687,283.222628 L151.649687,293.422628 L153.750313,295.564442 L164.150313,285.364442 L163.74213,285.649142 C163.780517,285.630958 163.889613,285.586994 164.040517,285.540162 C164.310615,285.456338 164.572677,285.412661 164.770907,285.423094 C164.889274,285.429324 164.929866,285.444721 164.93934,285.454195 C165.054384,285.569239 165.256262,285.58804 165.33934,285.754195 C165.532892,286.141299 165.499999,285.983741 165.499999,286.193535 L165.499999,286.393535 L151.93934,299.832875 L152.32918,299.551894 C152.086278,299.606979 151.74747,299.618798 151.311607,299.522337 C150.619626,299.369193 149.834748,298.96993 148.960277,298.241203 C148.667836,297.997503 148.452815,297.754023 148.303094,297.512166 C147.893415,296.850376 147.952546,296.123142 148.348213,295.346646 C148.475447,295.096949 148.596925,294.9203 148.652332,294.853812 L148.576371,294.938248 L165.076371,277.938248 L164.794998,278.165532 C164.864839,278.121882 165.059218,278.023967 165.351894,277.917754 C167.122972,277.275024 169.021733,277.536588 170.93934,279.454195 C172.959895,281.47475 173.313754,283.288278 172.821364,284.826996 C172.761365,285.014492 172.710513,285.12679 172.697635,285.149327 L172.93934,284.832875 L157.93934,299.832875 L160.06066,301.954195 L175.06066,286.954195 L175.06066,286.954195 Z" id="paper-clip" fill="#D9D9D9" sketch:type="MSShapeGroup"></path>
<path d="M175.06066,286.954195 L175.202702,286.812154 L175.302365,286.637743 C175.414487,286.441529 175.551135,286.139765 175.678636,285.741324 C176.498746,283.17848 175.915105,280.18732 173.06066,277.332875 C170.243699,274.515914 167.118112,274.085348 164.328491,275.097711 C163.823841,275.280849 163.443803,275.472287 163.205002,275.621537 L163.050513,275.718093 L162.923629,275.848822 L146.423629,292.848822 L146.347668,292.933258 C146.158935,293.159738 145.914201,293.515622 145.675224,293.984613 C144.849092,295.605898 144.703461,297.396954 145.752299,299.09123 C146.076339,299.614679 146.505633,300.100791 147.039723,300.545867 C149.292783,302.423417 151.404521,302.890769 153.098516,302.442358 C153.341124,302.378139 153.532621,302.304275 153.67082,302.235176 L153.888539,302.126317 L154.06066,301.954195 L168.06066,287.954195 L168.5,287.514855 L168.5,286.893535 C168.5,286.259579 168.359026,285.413735 167.919766,284.535214 C167.698156,284.091994 167.414366,283.686581 167.06066,283.332875 C166.478935,282.75115 165.737193,282.469799 164.928583,282.427241 C164.327068,282.395582 163.731987,282.494762 163.15132,282.674969 C162.852797,282.767614 162.615784,282.863127 162.45787,282.937928 L162.229833,283.045946 L162.049687,283.222628 L151.649687,293.422628 L153.750313,295.564442 L164.150313,285.364442 L163.74213,285.649142 C163.780517,285.630958 163.889613,285.586994 164.040517,285.540162 C164.310615,285.456338 164.572677,285.412661 164.770907,285.423094 C164.889274,285.429324 164.929866,285.444721 164.93934,285.454195 C165.054384,285.569239 165.256262,285.58804 165.33934,285.754195 C165.532892,286.141299 165.499999,285.983741 165.499999,286.193535 L165.499999,286.393535 L151.93934,299.832875 L152.32918,299.551894 C152.086278,299.606979 151.74747,299.618798 151.311607,299.522337 C150.619626,299.369193 149.834748,298.96993 148.960277,298.241203 C148.667836,297.997503 148.452815,297.754023 148.303094,297.512166 C147.893415,296.850376 147.952546,296.123142 148.348213,295.346646 C148.475447,295.096949 148.596925,294.9203 148.652332,294.853812 L148.576371,294.938248 L165.076371,277.938248 L164.794998,278.165532 C164.864839,278.121882 165.059218,278.023967 165.351894,277.917754 C167.122972,277.275024 169.021733,277.536588 170.93934,279.454195 C172.959895,281.47475 173.313754,283.288278 172.821364,284.826996 C172.761365,285.014492 172.710513,285.12679 172.697635,285.149327 L172.93934,284.832875 L157.93934,299.832875 L160.06066,301.954195 L175.06066,286.954195 L175.06066,286.954195 Z" id="paper-clip" opacity="0.15" fill="#000000" sketch:type="MSShapeGroup"></path>
<g id="total" sketch:type="MSLayerGroup" transform="translate(216.000000, 224.000000)">
<path d="M37.5,83 L0,83 L10,75 L47.5,75 L37.5,83 L37.5,83 Z" id="Shape" opacity="0.4" fill="#A9BCC4" sketch:type="MSShapeGroup"></path>
<path d="M37.5,80 L0,80 L10,73 L47.5,73 L37.5,80 L37.5,80 Z" id="Shape" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -296,6 +296,18 @@ test( "htmlClanup", function() {
result = App.Utils.htmlClanup( $(source) )
equal( result.html(), should, source )
source = "<div><small>some link to somewhere</small></a>"
//should = "<div>some link to somewhere</div>"
should = "some link to somewhere"
result = App.Utils.htmlClanup( $(source) )
equal( result.html(), should, source )
source = "<div><time>some link to somewhere</time></a>"
//should = "<div>some link to somewhere</div>"
should = "some link to somewhere"
result = App.Utils.htmlClanup( $(source) )
equal( result.html(), should, source )
source = "<div><h1>some link to somewhere</h1><p><hr></p></div>"
should = "<div>some link to somewhere</div><p></p><p></p>"
result = App.Utils.htmlClanup( $(source) )
@ -439,4 +451,92 @@ test( "check signature", function() {
});
// replace tags
test( "check replace tags", function() {
var message = "<div>#{user.firstname} #{user.lastname}</div>"
var result = '<div>Bob Smith</div>'
var data = {
user: {
firstname: 'Bob',
lastname: 'Smith',
},
}
var verify = App.Utils.replaceTags( message, data )
equal( verify, result )
message = "<div>#{user.firstname} #{user.lastname}</div>"
result = '<div>Bob Smith</div>'
data = {
user: {
firstname: function() { return 'Bob' },
lastname: function() { return 'Smith' },
},
}
verify = App.Utils.replaceTags( message, data )
equal( verify, result )
message = "<div>#{user.firstname} #{user.lastname}</div>"
result = '<div>Bob </div>'
data = {
user: {
firstname: 'Bob',
},
}
verify = App.Utils.replaceTags( message, data )
equal( verify, result )
});
// check if last line is a empty line
test( "check if last line is a empty line", function() {
var message = "123"
var result = false
var verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div>123</div>"
result = false
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<p><div>123 </div></p>"
result = false
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div></div>"
result = true
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div class=\"some_class\"></div>"
result = true
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div class=\"some_class\"></div> "
result = true
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div class=\"some_class\"></div> \n \n\t"
result = true
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div class=\"some_class\"> </div> \n \n\t"
result = true
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
message = "<div class=\"some_class\"\n> \n</div> \n \n\t"
result = true
verify = App.Utils.lastLineEmpty( message )
equal( verify, result, message )
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -295,7 +295,7 @@ EventMachine.run {
idle_time_in_min = 4
# web sockets
# close unused web socket sessions
@clients.each { |client_id, client|
if ( client[:last_ping] + ( 60 * idle_time_in_min ) ) < Time.now
log 'notice', "closing idle websocket connection", client_id
@ -312,10 +312,10 @@ EventMachine.run {
end
}
# close unused sessions
# close unused ajax long polling sessions
clients = Sessions.destory_idle_sessions(idle_time_in_min)
clients.each { |client_id|
log 'notice', "closing idle connection", client_id
log 'notice', "closing idle long polling connection", client_id
}
end

View file

@ -2050,6 +2050,28 @@ Some Text',
},
},
},
{
:data => 'From: Some Body <somebody@example.com>
To: Bob <bod@example.com>
Cc: any@example.com
Subject: some subject
Some Text',
:trusted => false,
:success => true,
:result => {
0 => {
:group => group2.name,
:priority => '2 normal',
:title => 'some subject',
},
1 => {
:sender => 'Customer',
:type => 'email',
:internal => true,
},
},
},
]
process(files)
PostmasterFilter.destroy_all