Improved collection handling.
This commit is contained in:
parent
8bbe1c9289
commit
422ae18a2d
25 changed files with 1477 additions and 1061 deletions
|
@ -95,8 +95,8 @@ class App.Controller extends Spine.Controller
|
|||
|
||||
# if no content exists, try firstname/lastname
|
||||
if !object[row.name]['name']
|
||||
if object[row.name]['firstname'] || object[row.name]['lastname']
|
||||
object[row.name]['name'] = (object[row.name]['firstname'] || '') + ' ' + (object[row.name]['lastname'] || '')
|
||||
if object[row.name]['realname']
|
||||
object[row.name]['name'] = object[row.name]['realname']
|
||||
|
||||
# if it isnt a object, create one
|
||||
else if typeof object[row.name] isnt 'object'
|
||||
|
@ -112,7 +112,7 @@ class App.Controller extends Spine.Controller
|
|||
|
||||
# execute callback on content
|
||||
if row.callback
|
||||
object[row.name]['name'] = row.callback(object[row.name]['name'])
|
||||
object[row.name]['name'] = row.callback( object[row.name]['name'] )
|
||||
|
||||
# lookup relation
|
||||
if !object[row.name]['name']
|
||||
|
@ -120,7 +120,7 @@ class App.Controller extends Spine.Controller
|
|||
for attribute in attributes
|
||||
if rowWithoutId is attribute.name
|
||||
if attribute.relation && App[attribute.relation]
|
||||
record = App[attribute.relation].find( object[rowWithoutId] )
|
||||
record = App.Collection.find( attribute.relation, object[rowWithoutId] )
|
||||
object[row.name]['name'] = record.name
|
||||
|
||||
# @log 'table', 'header', header, 'overview', data_types, 'objects', objects
|
||||
|
@ -158,12 +158,12 @@ class App.Controller extends Spine.Controller
|
|||
{ name: 'ticket_priority', translate: true },
|
||||
{ name: 'group' },
|
||||
{ name: 'owner', class: 'user-data', data: { id: true } },
|
||||
{ name: 'created_at', callback: @humanTime },
|
||||
{ name: 'last_contact', callback: @humanTime },
|
||||
{ name: 'last_contact_agent', callback: @humanTime },
|
||||
{ name: 'last_contact_customer', callback: @humanTime },
|
||||
{ name: 'first_response', callback: @humanTime },
|
||||
{ name: 'close_time', callback: @humanTime },
|
||||
{ name: 'created_at', callback: @frontendTime },
|
||||
{ name: 'last_contact', callback: @frontendTime },
|
||||
{ name: 'last_contact_agent', callback: @frontendTime },
|
||||
{ name: 'last_contact_customer', callback: @frontendTime },
|
||||
{ name: 'first_response', callback: @frontendTime },
|
||||
{ name: 'close_time', callback: @frontendTime },
|
||||
]
|
||||
shown_all_attributes = []
|
||||
for all_attribute in all_attributes
|
||||
|
@ -190,25 +190,38 @@ class App.Controller extends Spine.Controller
|
|||
humanTime: (time) =>
|
||||
current = new Date()
|
||||
created = new Date(time)
|
||||
diff = (current - created) / 1000
|
||||
string = ''
|
||||
diff = ( current - created ) / 1000
|
||||
if diff >= 86400
|
||||
unit = Math.round( (diff / 86400) )
|
||||
if unit > 1
|
||||
return unit + ' ' + T('days')
|
||||
else
|
||||
return unit + ' ' + T('day')
|
||||
unit = Math.round( ( diff / 86400 ) )
|
||||
# if unit > 1
|
||||
# return unit + ' ' + T('days')
|
||||
# else
|
||||
# return unit + ' ' + T('day')
|
||||
string = unit + ' ' + T('d')
|
||||
if diff >= 3600
|
||||
unit = Math.round( (diff / 3600) )
|
||||
if unit > 1
|
||||
return unit + ' ' + T('hours')
|
||||
unit = Math.round( ( diff / 3600 ) % 24 )
|
||||
# if unit > 1
|
||||
# return unit + ' ' + T('hours')
|
||||
# else
|
||||
# return unit + ' ' + T('hour')
|
||||
if string isnt ''
|
||||
string = string + ' ' + unit + ' ' + T('h')
|
||||
return string
|
||||
else
|
||||
return unit + ' ' + T('hour')
|
||||
if diff <= 3600
|
||||
unit = Math.round( (diff / 60) )
|
||||
if unit > 1
|
||||
return unit + ' ' + T('minutes')
|
||||
string = unit + ' ' + T('h')
|
||||
if diff <= 86400
|
||||
unit = Math.round( ( diff / 60 ) % 60 )
|
||||
# if unit > 1
|
||||
# return unit + ' ' + T('minutes')
|
||||
# else
|
||||
# return unit + ' ' + T('minute')
|
||||
if string isnt ''
|
||||
string = string + ' ' + unit + ' ' + T('m')
|
||||
return string
|
||||
else
|
||||
return unit + ' ' + T('minute')
|
||||
string = unit + ' ' + T('m')
|
||||
return string
|
||||
|
||||
userInfo: (data) =>
|
||||
# start customer info controller
|
||||
|
@ -230,6 +243,21 @@ class App.Controller extends Spine.Controller
|
|||
@navigate '#login'
|
||||
return false
|
||||
|
||||
frontendTime: (timestamp) ->
|
||||
'<span class="humanTimeFromNow" data-time="' + timestamp + '">?</span>'
|
||||
|
||||
frontendTimeUpdate: ->
|
||||
update = =>
|
||||
ui = @
|
||||
$('.humanTimeFromNow').each( ->
|
||||
# console.log('rewrite frontendTimeUpdate', this)
|
||||
timestamp = $(this).data('time')
|
||||
time = ui.humanTime( timestamp )
|
||||
$(this).attr( 'title', Ts(timestamp) )
|
||||
$(this).text( time )
|
||||
)
|
||||
@interval( update, 30000, 'frontendTimeUpdate' )
|
||||
|
||||
clearInterval: (interval_id) =>
|
||||
# check global var
|
||||
if !@intervalID
|
||||
|
@ -237,13 +265,13 @@ class App.Controller extends Spine.Controller
|
|||
|
||||
clearInterval( @intervalID[interval_id] ) if @intervalID[interval_id]
|
||||
|
||||
interval: (action, interval, interval_id) =>
|
||||
interval: (callback, interval, interval_id) =>
|
||||
|
||||
# check global var
|
||||
if !@intervalID
|
||||
@intervalID = {}
|
||||
|
||||
action()
|
||||
callback()
|
||||
|
||||
# auto save
|
||||
every = (ms, cb) -> setInterval cb, ms
|
||||
|
@ -253,7 +281,7 @@ class App.Controller extends Spine.Controller
|
|||
|
||||
# request new data
|
||||
@intervalID[interval_id] = every interval, () =>
|
||||
action()
|
||||
callback()
|
||||
|
||||
userPopups: (position = 'right') ->
|
||||
|
||||
|
@ -267,11 +295,11 @@ class App.Controller extends Spine.Controller
|
|||
placement: position,
|
||||
title: ->
|
||||
user_id = $(@).data('id')
|
||||
user = App.User.find(user_id)
|
||||
(user.firstname || '') + ' ' + (user.lastname || '')
|
||||
user = App.Collection.find( 'User', user_id )
|
||||
user.realname
|
||||
content: ->
|
||||
user_id = $(@).data('id')
|
||||
user = App.User.find(user_id)
|
||||
user = App.Collection.find( 'User', user_id )
|
||||
|
||||
# get display data
|
||||
data = []
|
||||
|
@ -322,9 +350,8 @@ class App.Controller extends Spine.Controller
|
|||
type = $(@).filter('[data-type]').data('type')
|
||||
data = tickets[type] || []
|
||||
|
||||
# set human time
|
||||
for ticket in data
|
||||
|
||||
# set human time
|
||||
ticket.humanTime = controller.humanTime(ticket.created_at)
|
||||
|
||||
# insert data
|
||||
|
@ -333,129 +360,6 @@ class App.Controller extends Spine.Controller
|
|||
)
|
||||
)
|
||||
|
||||
loadCollection: (params) ->
|
||||
|
||||
# remember in store if not already requested
|
||||
if !params.localStorage
|
||||
if params.type == 'User'
|
||||
for user_id, user of params.data
|
||||
data = {}
|
||||
data[params.type] = {}
|
||||
data[params.type][ user_id ] = user
|
||||
App.Store.write( 'collection::' + params.type + '::' + user_id, { type: params.type, localStorage: true, collections: data } )
|
||||
else
|
||||
for object in params.data
|
||||
data = {}
|
||||
data[params.type] = [ object ]
|
||||
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, collections: data } )
|
||||
|
||||
# users
|
||||
if params.type == 'User'
|
||||
for user_id, user of params.data
|
||||
|
||||
# set socal media links
|
||||
if user['accounts']
|
||||
for account of user['accounts']
|
||||
if account == 'twitter'
|
||||
user['accounts'][account]['link'] = 'http://twitter.com/' + user['accounts'][account]['username']
|
||||
if account == 'facebook'
|
||||
user['accounts'][account]['link'] = 'https://www.facebook.com/profile.php?id=' + user['accounts'][account]['uid']
|
||||
|
||||
# set image url
|
||||
if user && !user['image']
|
||||
user['image'] = 'http://placehold.it/48x48'
|
||||
|
||||
# set realname
|
||||
user['realname'] = ''
|
||||
if user['firstname']
|
||||
user['realname'] = user['firstname']
|
||||
if user['lastname']
|
||||
if user['realname'] isnt ''
|
||||
user['realname'] = user['realname'] + ' '
|
||||
user['realname'] = user['realname'] + user['lastname']
|
||||
|
||||
# load in collection if needed
|
||||
if !params.collection
|
||||
App.User.refresh( user, options: { clear: true } )
|
||||
|
||||
# tickets
|
||||
else if params.type == 'Ticket'
|
||||
for ticket in params.data
|
||||
|
||||
# set human time
|
||||
ticket.humanTime = @humanTime(ticket.created_at)
|
||||
|
||||
# priority
|
||||
ticket.ticket_priority = App.TicketPriority.find(ticket.ticket_priority_id)
|
||||
|
||||
# state
|
||||
ticket.ticket_state = App.TicketState.find(ticket.ticket_state_id)
|
||||
|
||||
# group
|
||||
ticket.group = App.Group.find(ticket.group_id)
|
||||
|
||||
# customer
|
||||
if ticket.customer_id and App.User.exists(ticket.customer_id)
|
||||
user = App.User.find(ticket.customer_id)
|
||||
ticket.customer = user
|
||||
|
||||
# owner
|
||||
if ticket.owner_id and App.User.exists(ticket.owner_id)
|
||||
user = App.User.find(ticket.owner_id)
|
||||
ticket.owner = user
|
||||
|
||||
# load in collection if needed
|
||||
if !params.collection
|
||||
App.Ticket.refresh( ticket, options: { clear: true } )
|
||||
|
||||
# articles
|
||||
else if params.type == 'TicketArticle'
|
||||
for article in params.data
|
||||
|
||||
# add user
|
||||
article.created_by = App.User.find(article.created_by_id)
|
||||
|
||||
# set human time
|
||||
article.humanTime = @humanTime(article.created_at)
|
||||
|
||||
# add possible actions
|
||||
article.article_type = App.TicketArticleType.find( article.ticket_article_type_id )
|
||||
article.article_sender = App.TicketArticleSender.find( article.ticket_article_sender_id )
|
||||
|
||||
# load in collection if needed
|
||||
if !params.collection
|
||||
App.TicketArticle.refresh( article, options: { clear: true } )
|
||||
|
||||
# history
|
||||
else if params.type == 'History'
|
||||
for histroy in params.data
|
||||
|
||||
# add user
|
||||
histroy.created_by = App.User.find(histroy.created_by_id)
|
||||
|
||||
# set human time
|
||||
histroy.humanTime = @humanTime(histroy.created_at)
|
||||
|
||||
# add possible actions
|
||||
if histroy.history_attribute_id
|
||||
histroy.attribute = App.HistoryAttribute.find( histroy.history_attribute_id )
|
||||
if histroy.history_type_id
|
||||
histroy.type = App.HistoryType.find( histroy.history_type_id )
|
||||
if histroy.history_object_id
|
||||
histroy.object = App.HistoryObject.find( histroy.history_object_id )
|
||||
|
||||
# load in collection if needed
|
||||
if !params.collection
|
||||
App.History.refresh( histroy, options: { clear: true } )
|
||||
|
||||
# all the rest
|
||||
else
|
||||
for object in params.data
|
||||
|
||||
# load in collection if needed
|
||||
if !params.collection
|
||||
App[params.type].refresh( object, options: { clear: true } )
|
||||
|
||||
ws_send: (data) ->
|
||||
Spine.trigger( 'ws:send', JSON.stringify(data) )
|
||||
|
||||
|
|
|
@ -418,7 +418,8 @@ class App.ControllerForm extends App.Controller
|
|||
# if record.name.toString() is attribute.value.toString()
|
||||
# record.selected = 'selected'
|
||||
# record.checked = 'checked'
|
||||
if ( attribute.value && record.value && _.include(attribute.value, record.value) ) || ( attribute.value && record.name && _.include(attribute.value, record.name) )
|
||||
|
||||
else if ( attribute.value && record.value && _.include(attribute.value, record.value) ) || ( attribute.value && record.name && _.include(attribute.value, record.name) )
|
||||
record.selected = 'selected'
|
||||
record.checked = 'checked'
|
||||
|
||||
|
|
|
@ -37,13 +37,13 @@ class App.DashboardActivityStream extends App.Controller
|
|||
items = data.activity_stream
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
@loadCollection( type: 'Ticket', data: data.tickets )
|
||||
App.Collection.load( type: 'Ticket', data: data.tickets )
|
||||
|
||||
# load article collection
|
||||
@loadCollection( type: 'TicketArticle', data: data.articles )
|
||||
App.Collection.load( type: 'TicketArticle', data: data.articles )
|
||||
|
||||
@render(items)
|
||||
|
||||
|
@ -51,15 +51,15 @@ class App.DashboardActivityStream extends App.Controller
|
|||
|
||||
# load user data
|
||||
for item in items
|
||||
item.created_by = App.User.find( item.created_by_id )
|
||||
item.created_by = App.Collection.find( 'User', item.created_by_id )
|
||||
|
||||
# load ticket data
|
||||
for item in items
|
||||
item.data = {}
|
||||
if item.history_object is 'Ticket'
|
||||
item.data.title = App.Ticket.find( item.o_id ).title
|
||||
item.data.title = App.Collection.find( 'Ticket', item.o_id ).title
|
||||
if item.history_object is 'Ticket::Article'
|
||||
article = App.TicketArticle.find( item.o_id )
|
||||
article = App.Collection.find( 'TicketArticle', item.o_id )
|
||||
item.history_object = 'Article'
|
||||
item.sub_o_id = article.id
|
||||
item.o_id = article.ticket_id
|
||||
|
|
|
@ -24,10 +24,10 @@ class App.DashboardRecentViewed extends App.Controller
|
|||
@items = data.recent_viewed
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
@loadCollection( type: 'Ticket', data: data.tickets )
|
||||
App.Collection.load( type: 'Ticket', data: data.tickets )
|
||||
|
||||
@render()
|
||||
)
|
||||
|
@ -36,13 +36,11 @@ class App.DashboardRecentViewed extends App.Controller
|
|||
|
||||
# load user data
|
||||
for item in @items
|
||||
# @log 'load', item.created_by_id
|
||||
item.created_by = App.User.find(item.created_by_id)
|
||||
item.created_by = App.Collection.find( 'User', item.created_by_id )
|
||||
|
||||
# load ticket data
|
||||
for item in @items
|
||||
# @log 'load', item.o_id
|
||||
item.ticket = App.Ticket.find(item.o_id)
|
||||
item.ticket = App.Collection.find( 'User', item.o_id )
|
||||
|
||||
html = App.view('dashboard/recent_viewed')(
|
||||
head: 'Recent Viewed',
|
||||
|
|
|
@ -84,7 +84,7 @@ class App.DashboardTicket extends App.Controller
|
|||
while i < end
|
||||
i = i + 1
|
||||
if @ticket_list[ i - 1 ]
|
||||
@tickets_in_table.push App.Ticket.find( @ticket_list[ i - 1 ] )
|
||||
@tickets_in_table.push App.Collection.find( 'Ticket', @ticket_list[ i - 1 ] )
|
||||
|
||||
shown_all_attributes = @ticketTableAttributes( App.Overview.find(@overview.id).view.d.overview )
|
||||
table = @table(
|
||||
|
@ -102,6 +102,9 @@ class App.DashboardTicket extends App.Controller
|
|||
html.find('.table-overview').append(table)
|
||||
@html html
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
# start user popups
|
||||
@userPopups()
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class Index extends App.Controller
|
|||
@edit_form = cache.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: cache.users )
|
||||
App.Collection.load( type: 'User', data: cache.users )
|
||||
|
||||
@render()
|
||||
else
|
||||
|
@ -59,18 +59,18 @@ class Index extends App.Controller
|
|||
@edit_form = data.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
if data.ticket && data.articles
|
||||
@loadCollection( type: 'Ticket', data: [data.ticket] )
|
||||
App.Collection.load( type: 'Ticket', data: [data.ticket] )
|
||||
|
||||
# load article collections
|
||||
@loadCollection( type: 'TicketArticle', data: data.articles || [] )
|
||||
App.Collection.load( type: 'TicketArticle', data: data.articles || [] )
|
||||
|
||||
# render page
|
||||
t = App.Ticket.find(params.ticket_id).attributes()
|
||||
a = App.TicketArticle.find(params.article_id)
|
||||
t = App.Collection.find( 'Ticket', params.ticket_id ).attributes()
|
||||
a = App.Collection.find( 'TicketArticle', params.article_id )
|
||||
|
||||
# reset owner
|
||||
t.owner_id = 0
|
||||
|
@ -86,9 +86,9 @@ class Index extends App.Controller
|
|||
# set defaults
|
||||
defaults = template['options'] || {}
|
||||
if !( 'ticket_state_id' of defaults )
|
||||
defaults['ticket_state_id'] = App.TicketState.findByAttribute( 'name', 'new' ).id
|
||||
defaults['ticket_state_id'] = App.Collection.findByAttribute( 'TicketState', 'name', 'new' ).id
|
||||
if !( 'ticket_priority_id' of defaults )
|
||||
defaults['ticket_priority_id'] = App.TicketPriority.findByAttribute( 'name', '2 normal' ).id
|
||||
defaults['ticket_priority_id'] = App.Collection.findByAttribute( 'TicketPriority', 'name', '2 normal' ).id
|
||||
|
||||
# remember customers
|
||||
if $('#create_customer_id').val()
|
||||
|
@ -163,10 +163,10 @@ class Index extends App.Controller
|
|||
@log 'updateAttributes', params
|
||||
|
||||
# find sender_id
|
||||
sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' )
|
||||
type = App.TicketArticleType.findByAttribute( 'name', 'phone' )
|
||||
sender = App.Collection.findByAttribute( 'TicketArticleSender', 'name', 'Customer' )
|
||||
type = App.Collection.findByAttribute( 'TicketArticleType', 'name', 'phone' )
|
||||
if params.group_id
|
||||
group = App.Group.find(params.group_id)
|
||||
group = App.Collection.find( 'Group', params.group_id )
|
||||
|
||||
# create article
|
||||
params['article'] = {
|
||||
|
@ -248,7 +248,7 @@ class UserNew extends App.ControllerModal
|
|||
user = new App.User
|
||||
|
||||
# find role_id
|
||||
role = App.Role.findByAttribute( 'name', 'Customer' )
|
||||
role = App.Collection.findByAttribute( 'Role', 'name', 'Customer' )
|
||||
params.role_ids = role.id
|
||||
@log 'updateAttributes', params
|
||||
user.load(params)
|
||||
|
|
|
@ -14,23 +14,23 @@ class App.TicketHistory extends App.ControllerModal
|
|||
@ticket = data.ticket
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
@loadCollection( type: 'Ticket', data: [data.ticket] )
|
||||
App.Collection.load( type: 'Ticket', data: [data.ticket] )
|
||||
|
||||
# load history_type collections
|
||||
@loadCollection( type: 'HistoryType', data: data.history_types )
|
||||
App.Collection.load( type: 'HistoryType', data: data.history_types )
|
||||
|
||||
# load history_object collections
|
||||
@loadCollection( type: 'HistoryObject', data: data.history_objects )
|
||||
App.Collection.load( type: 'HistoryObject', data: data.history_objects )
|
||||
|
||||
# load history_attributes collections
|
||||
@loadCollection( type: 'HistoryAttribute', data: data.history_attributes )
|
||||
App.Collection.load( type: 'HistoryAttribute', data: data.history_attributes )
|
||||
|
||||
# load history collections
|
||||
App.History.deleteAll()
|
||||
@loadCollection( type: 'History', data: data.history )
|
||||
App.Collection.deleteAll( 'History' )
|
||||
App.Collection.load( type: 'History', data: data.history )
|
||||
|
||||
# render page
|
||||
@render()
|
||||
|
@ -39,7 +39,7 @@ class App.TicketHistory extends App.ControllerModal
|
|||
render: ->
|
||||
|
||||
@html App.view('agent_ticket_history')(
|
||||
objects: App.History.all(),
|
||||
objects: App.Collection.all( 'History' ),
|
||||
)
|
||||
|
||||
@modalShow()
|
||||
|
|
|
@ -24,13 +24,16 @@ class App.TicketMerge extends App.ControllerModal
|
|||
success: (data, status, xhr) =>
|
||||
|
||||
if data['result'] is 'success'
|
||||
@loadCollection( type: 'Ticket', data: [data.master_ticket] )
|
||||
@loadCollection( type: 'Ticket', data: [data.slave_ticket] )
|
||||
|
||||
# update collection
|
||||
App.Collection.load( type: 'Ticket', data: [data.master_ticket] )
|
||||
App.Collection.load( type: 'Ticket', data: [data.slave_ticket] )
|
||||
|
||||
# hide dialog
|
||||
@modalHide()
|
||||
|
||||
# view ticket
|
||||
@log 'nav...', App.Ticket.find( data.master_ticket['id'] )
|
||||
@log 'nav...', App.Collection.find( 'Ticket', data.master_ticket['id'] )
|
||||
@navigate '#ticket/zoom/' + data.master_ticket['id']
|
||||
|
||||
# notify UI
|
||||
|
|
|
@ -77,7 +77,7 @@ class Index extends App.Controller
|
|||
|
||||
@ticket_list_show = []
|
||||
for ticket_id in @ticket_list
|
||||
@ticket_list_show.push App.Ticket.find(ticket_id)
|
||||
@ticket_list_show.push App.Collection.find( 'Ticket', ticket_id )
|
||||
|
||||
# remeber bulk attributes
|
||||
@bulk = data.bulk
|
||||
|
@ -159,6 +159,9 @@ class Index extends App.Controller
|
|||
# start user popups
|
||||
@userPopups()
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
# start bulk action observ
|
||||
@el.find('.bulk-action').append( @bulk_form() )
|
||||
|
||||
|
|
|
@ -54,28 +54,26 @@ class Index extends App.Controller
|
|||
@edit_form = data.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
@loadCollection( type: 'Ticket', data: [data.ticket] )
|
||||
App.Collection.load( type: 'Ticket', data: [data.ticket] )
|
||||
|
||||
# load article collections
|
||||
@loadCollection( type: 'TicketArticle', data: data.articles || [] )
|
||||
App.Collection.load( type: 'TicketArticle', data: data.articles )
|
||||
|
||||
# render page
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
|
||||
return if !App.Ticket.exists(@ticket_id)
|
||||
|
||||
# get data
|
||||
if !@ticket
|
||||
@ticket = App.Ticket.find(@ticket_id)
|
||||
@ticket = App.Collection.find( 'Ticket', @ticket_id )
|
||||
if !@articles
|
||||
@articles = []
|
||||
for article_id in @ticket.article_ids
|
||||
article = App.TicketArticle.find(article_id)
|
||||
article = App.Collection.find( 'TicketArticle', article_id )
|
||||
@articles.push article
|
||||
|
||||
# rework articles
|
||||
|
@ -146,6 +144,9 @@ class Index extends App.Controller
|
|||
# show ticket action row
|
||||
@ticket_action_row()
|
||||
|
||||
# show frontend times
|
||||
@frontendTimeUpdate()
|
||||
|
||||
# scrall to article if given
|
||||
if @article_id
|
||||
offset = document.getElementById( 'article-' + @article_id ).offsetTop
|
||||
|
@ -345,11 +346,11 @@ class Index extends App.Controller
|
|||
|
||||
# find sender_id
|
||||
if @isRole('Customer')
|
||||
sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' )
|
||||
type = App.TicketArticleType.findByAttribute( 'name', 'web' )
|
||||
sender = App.Collection.findByAttribute( 'TicketArticleSender', 'name', 'Customer' )
|
||||
type = App.Collection.findByAttribute( 'TicketArticleType', 'name', 'web' )
|
||||
params['ticket_article_type_id'] = type.id
|
||||
else
|
||||
sender = App.TicketArticleSender.findByAttribute( 'name', 'Agent' )
|
||||
sender = App.Collection.findByAttribute( 'TicketArticleSender', 'name', 'Agent' )
|
||||
params.ticket_article_sender_id = sender.id
|
||||
@log 'updateAttributes', params, sender, sender.id
|
||||
article.load(params)
|
||||
|
|
|
@ -31,7 +31,7 @@ class Index extends App.Controller
|
|||
@edit_form = cache.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: cache.users )
|
||||
App.Collection.load( type: 'User', data: cache.users )
|
||||
|
||||
@render()
|
||||
else
|
||||
|
@ -53,18 +53,18 @@ class Index extends App.Controller
|
|||
@edit_form = data.edit_form
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
if data.ticket && data.articles
|
||||
@loadCollection( type: 'Ticket', data: [data.ticket] )
|
||||
App.Collection.load( type: 'Ticket', data: [data.ticket] )
|
||||
|
||||
# load article collections
|
||||
@loadCollection( type: 'TicketArticle', data: data.articles || [] )
|
||||
App.Collection.load( type: 'TicketArticle', data: data.articles || [] )
|
||||
|
||||
# render page
|
||||
t = App.Ticket.find(params.ticket_id).attributes()
|
||||
a = App.TicketArticle.find(params.article_id)
|
||||
t = App.Collection.find( 'Ticket', params.ticket_id ).attributes()
|
||||
a = App.Collection.find( 'TicketArticle', params.article_id )
|
||||
|
||||
# reset owner
|
||||
t.owner_id = 0
|
||||
|
@ -80,9 +80,9 @@ class Index extends App.Controller
|
|||
# set defaults
|
||||
defaults = template['options'] || {}
|
||||
if !( 'ticket_state_id' of defaults )
|
||||
defaults['ticket_state_id'] = App.TicketState.findByAttribute( 'name', 'new' )
|
||||
defaults['ticket_state_id'] = App.Collection.findByAttribute( 'TicketState', 'name', 'new' )
|
||||
if !( 'ticket_priority_id' of defaults )
|
||||
defaults['ticket_priority_id'] = App.TicketPriority.findByAttribute( 'name', '2 normal' )
|
||||
defaults['ticket_priority_id'] = App.Collection.findByAttribute( 'TicketPriority', 'name', '2 normal' )
|
||||
|
||||
# generate form
|
||||
configure_attributes = [
|
||||
|
@ -126,11 +126,11 @@ class Index extends App.Controller
|
|||
params.customer_id = Session['id']
|
||||
|
||||
# set prio
|
||||
priority = App.TicketPriority.findByAttribute( 'name', '2 normal' )
|
||||
priority = App.Collection.findByAttribute( 'TicketPriority', 'name', '2 normal' )
|
||||
params.ticket_state_id = priority.id
|
||||
|
||||
# set state
|
||||
state = App.TicketState.findByAttribute( 'name', 'new' )
|
||||
state = App.Collection.findByAttribute( 'TicketState', 'name', 'new' )
|
||||
params.ticket_priority_id = state.id
|
||||
|
||||
# fillup params
|
||||
|
@ -142,10 +142,10 @@ class Index extends App.Controller
|
|||
@log 'updateAttributes', params
|
||||
|
||||
# find sender_id
|
||||
sender = App.TicketArticleSender.findByAttribute( 'name', 'Customer' )
|
||||
type = App.TicketArticleType.findByAttribute( 'name', 'web' )
|
||||
sender = App.Collection.findByAttribute( 'TicketArticleSender', 'name', 'Customer' )
|
||||
type = App.Collection.findByAttribute( 'TicketArticleType', 'name', 'web' )
|
||||
if params.group_id
|
||||
group = App.Group.find(params.group_id)
|
||||
group = App.Collection.find( 'Group', params.group_id )
|
||||
|
||||
# create article
|
||||
params['article'] = {
|
||||
|
|
|
@ -35,7 +35,7 @@ class Index extends App.Controller
|
|||
@master_user = data.master_user
|
||||
|
||||
# load group collection
|
||||
@loadCollection( type: 'Group', data: data.groups )
|
||||
App.Collection.load( type: 'Group', data: data.groups )
|
||||
|
||||
# render page
|
||||
@render()
|
||||
|
@ -80,7 +80,7 @@ class Index extends App.Controller
|
|||
@params.invite = true
|
||||
|
||||
# find agent role
|
||||
role = App.Role.findByAttribute('name', 'Agent')
|
||||
role = App.Collection.findByAttribute( 'Role', 'name', 'Agent' )
|
||||
if role
|
||||
@params.role_ids = role.id
|
||||
else
|
||||
|
|
|
@ -26,10 +26,10 @@ class App.LinkInfo extends App.Controller
|
|||
@links = data.links
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
@loadCollection( type: 'Ticket', data: data.tickets )
|
||||
App.Collection.load( type: 'Ticket', data: data.tickets )
|
||||
|
||||
@render()
|
||||
)
|
||||
|
@ -42,7 +42,7 @@ class App.LinkInfo extends App.Controller
|
|||
list[ item['link_type'] ] = []
|
||||
|
||||
if item['link_object'] is 'Ticket'
|
||||
ticket = App.Ticket.find( item['link_object_value'] )
|
||||
ticket = App.Collection.find( 'Ticket', item['link_object_value'] )
|
||||
if ticket.ticket_state.name is 'merged'
|
||||
ticket.css = 'merged'
|
||||
list[ item['link_type'] ].push ticket
|
||||
|
|
|
@ -170,10 +170,10 @@ class App.Navigation extends App.Controller
|
|||
items = data.recent_viewed
|
||||
|
||||
# load user collection
|
||||
@loadCollection( type: 'User', data: data.users )
|
||||
App.Collection.load( type: 'User', data: data.users )
|
||||
|
||||
# load ticket collection
|
||||
@loadCollection( type: 'Ticket', data: data.tickets )
|
||||
App.Collection.load( type: 'Ticket', data: data.tickets )
|
||||
|
||||
# remove old views
|
||||
for key of Config.NavBarRight
|
||||
|
@ -190,7 +190,7 @@ class App.Navigation extends App.Controller
|
|||
if prio is 8000
|
||||
divider = true
|
||||
navheader = 'Recent Viewed'
|
||||
ticket = App.Ticket.find(item.o_id)
|
||||
ticket = App.Collection.find( 'Ticket', item.o_id )
|
||||
prio++
|
||||
Config.NavBarRight['RecendViewed::' + ticket.id + '-' + prio ] = {
|
||||
prio: prio,
|
||||
|
|
|
@ -11,7 +11,7 @@ class App.TemplateUI extends App.Controller
|
|||
|
||||
# fetch item on demand
|
||||
fetch_needed = 1
|
||||
if App.Template.count() > 0
|
||||
if App.Collection.count( 'Template' ) > 0
|
||||
fetch_needed = 0
|
||||
@render()
|
||||
|
||||
|
@ -23,7 +23,7 @@ class App.TemplateUI extends App.Controller
|
|||
@log 'loading....'
|
||||
@render()
|
||||
App.Template.unbind 'refresh'
|
||||
App.Template.fetch()
|
||||
App.Collection.fetch( 'Template' )
|
||||
|
||||
render: =>
|
||||
@configure_attributes = [
|
||||
|
@ -32,7 +32,7 @@ class App.TemplateUI extends App.Controller
|
|||
|
||||
template = {}
|
||||
if @template_id
|
||||
template = App.Template.find(@template_id)
|
||||
template = App.Collection.find( 'Template', @template_id )
|
||||
|
||||
# insert data
|
||||
@html App.view('template')(
|
||||
|
@ -49,7 +49,7 @@ class App.TemplateUI extends App.Controller
|
|||
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
template = App.Template.find( params['template_id'] )
|
||||
template = App.Collection.find( 'Template', params['template_id'] )
|
||||
if confirm('Sure?')
|
||||
template.destroy()
|
||||
@template_id = undefined
|
||||
|
@ -61,7 +61,7 @@ class App.TemplateUI extends App.Controller
|
|||
# get params
|
||||
params = @formParam(e.target)
|
||||
|
||||
template = App.Template.find( params['template_id'] )
|
||||
template = App.Collection.find( 'Template', params['template_id'] )
|
||||
Spine.trigger 'ticket_create_rerender', template.attributes()
|
||||
|
||||
create: (e) =>
|
||||
|
@ -72,7 +72,7 @@ class App.TemplateUI extends App.Controller
|
|||
name = params['template_name']
|
||||
# delete params['template_name']
|
||||
|
||||
template = App.Template.findByAttribute( 'name', name )
|
||||
template = App.Collection.findByAttribute( 'Template', 'name', name )
|
||||
if !template
|
||||
template = new App.Template
|
||||
|
||||
|
|
|
@ -6,29 +6,9 @@ class App.UserInfo extends App.Controller
|
|||
|
||||
constructor: ->
|
||||
super
|
||||
App.Collection.find( 'User', @user_id, @render )
|
||||
|
||||
# fetch item on demand
|
||||
fetch_needed = 1
|
||||
if App.User.exists(@user_id)
|
||||
@log 'exists.user...', @user_id
|
||||
fetch_needed = 0
|
||||
@render(@user_id)
|
||||
|
||||
if fetch_needed
|
||||
@reload(@user_id)
|
||||
|
||||
reload: (user_id) =>
|
||||
App.User.bind 'refresh', =>
|
||||
@log 'loading.user...', user_id
|
||||
App.User.unbind 'refresh'
|
||||
@render(user_id)
|
||||
App.User.fetch( id: user_id )
|
||||
|
||||
render: (user_id) ->
|
||||
|
||||
# load user collection
|
||||
user = App.User.find(user_id)
|
||||
@loadCollection( type: 'User', data: { new: user }, collection: true )
|
||||
render: (user) =>
|
||||
|
||||
# get display data
|
||||
data = []
|
||||
|
@ -39,20 +19,20 @@ class App.UserInfo extends App.Controller
|
|||
|
||||
# insert data
|
||||
@html App.view('user_info')(
|
||||
user: App.User.find(user_id),
|
||||
user: user,
|
||||
data: data,
|
||||
)
|
||||
|
||||
@userTicketPopups(
|
||||
selector: '.user-tickets',
|
||||
user_id: user_id,
|
||||
user_id: user.id,
|
||||
)
|
||||
|
||||
update: (e) =>
|
||||
|
||||
# update changes
|
||||
note = $(e.target).parent().find('[data-type=edit]').val()
|
||||
user = App.User.find(@user_id)
|
||||
user = App.Collection.find( 'User', @user_id )
|
||||
if user.note isnt note
|
||||
user.updateAttributes( note: note )
|
||||
@log 'update', e, note, user
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#= require ./lib/bootstrap-tab.js
|
||||
#= require ./lib/bootstrap-transition.js
|
||||
|
||||
#= require ./lib/underscore.coffee
|
||||
#= require ./lib/underscore-1.3.3.js
|
||||
#= require ./lib/ba-linkify.js
|
||||
#= require ./lib/jquery.tagsinput.js
|
||||
#= require ./lib/jquery.noty.js
|
||||
|
@ -28,6 +28,7 @@
|
|||
#= require ./lib/auth.js.coffee
|
||||
#= require ./lib/i18n.js.coffee
|
||||
#= require ./lib/store.js.coffee
|
||||
#= require ./lib/collection.js.coffee
|
||||
#= require_tree ./models
|
||||
#= require_tree ./controllers
|
||||
#= require_tree ./views
|
||||
|
|
|
@ -65,9 +65,8 @@ class App.Auth
|
|||
App.WebSocket.auth()
|
||||
|
||||
# refresh/load default collections
|
||||
controller = new App.Controller
|
||||
for key, value of data.default_collections
|
||||
controller.loadCollection( type: key, data: value )
|
||||
App.Collection.load( type: key, data: value )
|
||||
|
||||
# rebuild navbar with new navbar items
|
||||
Spine.trigger 'navrebuild', data.session
|
||||
|
|
222
app/assets/javascripts/app/lib/collection.js.coffee
Normal file
222
app/assets/javascripts/app/lib/collection.js.coffee
Normal file
|
@ -0,0 +1,222 @@
|
|||
class App.Collection
|
||||
_instance = undefined
|
||||
|
||||
@init: ->
|
||||
_instance = new _Singleton
|
||||
|
||||
@load: ( args ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.load( args )
|
||||
|
||||
@find: ( type, id, callback ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.find( type, id, callback )
|
||||
|
||||
@get: ( args ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.get( args )
|
||||
|
||||
@all: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.all( type )
|
||||
|
||||
@deleteAll: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.deleteAll( type )
|
||||
|
||||
@findByAttribute: ( type, key, value ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.findByAttribute( type, key, value )
|
||||
|
||||
@count: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.count( type )
|
||||
|
||||
@fetch: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.fetch( type )
|
||||
|
||||
class _Singleton
|
||||
|
||||
constructor: (@args) ->
|
||||
|
||||
# add trigger - bind new events
|
||||
Spine.bind 'loadCollection', (data) =>
|
||||
|
||||
# load collections
|
||||
if data.collections
|
||||
for type of data.collections
|
||||
|
||||
console.log 'loadCollection:trigger', type, data.collections[type]
|
||||
@load( localStorage: data.localStorage, type: type, data: data.collections[type] )
|
||||
|
||||
# find collections to load
|
||||
@_loadCollectionAll()
|
||||
|
||||
_loadCollectionAll: ->
|
||||
list = App.Store.list()
|
||||
for key in list
|
||||
parts = key.split('::')
|
||||
if parts[0] is 'collection'
|
||||
data = App.Store.get( key )
|
||||
if data && data.localStorage
|
||||
console.log('load INIT', data)
|
||||
@load( data )
|
||||
|
||||
load: (params) ->
|
||||
console.log( 'load', params )
|
||||
|
||||
return if _.isEmpty( params.data )
|
||||
|
||||
if _.isArray( params.data )
|
||||
for object in params.data
|
||||
console.log( 'load ARRAY', object)
|
||||
App[params.type].refresh( object, options: { clear: true } )
|
||||
|
||||
# remember in store if not already requested from local storage
|
||||
if !params.localStorage
|
||||
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, data: [ object ] } )
|
||||
return
|
||||
|
||||
# if _.isObject( params.data )
|
||||
for key, object of params.data
|
||||
console.log( 'load OB', object)
|
||||
App[params.type].refresh( object, options: { clear: true } )
|
||||
|
||||
# remember in store if not already requested from local storage
|
||||
if !params.localStorage
|
||||
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, data: [ object ] } )
|
||||
|
||||
find: ( type, id, callback ) ->
|
||||
|
||||
console.log( 'find', type, id )
|
||||
# if App[type].exists( id ) && !callback
|
||||
if App[type].exists( id )
|
||||
console.log( 'find exists', type, id )
|
||||
data = App[type].find( id )
|
||||
if callback
|
||||
callback( data )
|
||||
else
|
||||
console.log( 'find not loaded!', type, id )
|
||||
if callback
|
||||
App[type].bind 'refresh', ->
|
||||
console.log 'loaded..' + type + '..', id
|
||||
App[type].unbind 'refresh'
|
||||
data = App.Collection.find( type, id )
|
||||
callback( data )
|
||||
console.log 'loading..' + type + '..', id
|
||||
App[type].fetch( id: id )
|
||||
return true
|
||||
return false
|
||||
|
||||
# users
|
||||
if type == 'User'
|
||||
|
||||
# set socal media links
|
||||
if data['accounts']
|
||||
for account of data['accounts']
|
||||
if account == 'twitter'
|
||||
data['accounts'][account]['link'] = 'http://twitter.com/' + data['accounts'][account]['username']
|
||||
if account == 'facebook'
|
||||
data['accounts'][account]['link'] = 'https://www.facebook.com/profile.php?id=' + data['accounts'][account]['uid']
|
||||
|
||||
# set image url
|
||||
if data && !data['image']
|
||||
data['image'] = 'http://placehold.it/48x48'
|
||||
|
||||
# set realname
|
||||
data['realname'] = ''
|
||||
if data['firstname']
|
||||
data['realname'] = data['firstname']
|
||||
if data['lastname']
|
||||
if data['realname'] isnt ''
|
||||
data['realname'] = data['realname'] + ' '
|
||||
data['realname'] = data['realname'] + data['lastname']
|
||||
|
||||
return data
|
||||
|
||||
# tickets
|
||||
else if type == 'Ticket'
|
||||
|
||||
# priority
|
||||
data.ticket_priority = @find( 'TicketPriority', data.ticket_priority_id )
|
||||
|
||||
# state
|
||||
data.ticket_state = @find( 'TicketState', data.ticket_state_id )
|
||||
|
||||
# group
|
||||
data.group = @find( 'Group', data.group_id )
|
||||
|
||||
# customer
|
||||
if data.customer_id
|
||||
data.customer = @find( 'User', data.customer_id )
|
||||
|
||||
# owner
|
||||
if data.owner_id
|
||||
data.owner = @find( 'User', data.owner_id )
|
||||
|
||||
# add created & updated
|
||||
if data.created_by_id
|
||||
data.created_by = @find( 'User', data.created_by_id )
|
||||
if data.updated_by_id
|
||||
data.updated_by = @find( 'User', data.updated_by_id )
|
||||
|
||||
return data
|
||||
|
||||
# articles
|
||||
else if type == 'TicketArticle'
|
||||
|
||||
# add created & updated
|
||||
data.created_by = @find( 'User', data.created_by_id )
|
||||
|
||||
# add possible actions
|
||||
data.article_type = @find( 'TicketArticleType', data.ticket_article_type_id )
|
||||
data.article_sender = @find( 'TicketArticleSender', data.ticket_article_sender_id )
|
||||
|
||||
return data
|
||||
|
||||
# history
|
||||
else if type == 'History'
|
||||
|
||||
# add user
|
||||
data.created_by = @find( 'User', data.created_by_id )
|
||||
|
||||
# add possible actions
|
||||
if data.history_attribute_id
|
||||
data.attribute = @find( 'HistoryAttribute', data.history_attribute_id )
|
||||
if data.history_type_id
|
||||
data.type = @find( 'HistoryType', data.history_type_id )
|
||||
if data.history_object_id
|
||||
data.object = @find( 'HistoryObject', data.history_object_id )
|
||||
|
||||
return data
|
||||
|
||||
else
|
||||
return data
|
||||
|
||||
get: (params) ->
|
||||
console.log('get')
|
||||
App[params.type].refresh( object, options: { clear: true } )
|
||||
|
||||
all: (type) ->
|
||||
App[type].all()
|
||||
|
||||
deleteAll: (type) ->
|
||||
App[type].deleteAll()
|
||||
|
||||
findByAttribute: ( type, key, value ) ->
|
||||
App[type].findByAttribute( key, value )
|
||||
|
||||
count: ( type ) ->
|
||||
App[type].count()
|
||||
|
||||
fetch: ( type ) ->
|
||||
App[type].fetch()
|
|
@ -5,36 +5,26 @@ class App.Run extends App.Controller
|
|||
@log 'RUN app'
|
||||
@el = $('#app')
|
||||
|
||||
# init collections
|
||||
App.Collection.init()
|
||||
|
||||
# create web socket connection
|
||||
App.WebSocket.connect()
|
||||
|
||||
# init of i18n
|
||||
new App.i18n
|
||||
|
||||
# bind new events
|
||||
Spine.bind 'loadCollection', (data) =>
|
||||
|
||||
# load collections
|
||||
if data.collections
|
||||
for key of data.collections
|
||||
|
||||
@log 'loadCollection', key, data.collections[key]
|
||||
@loadCollection( localStorage: data.localStorage, type: key, data: data.collections[key] )
|
||||
|
||||
# load collections
|
||||
App.Store.load()
|
||||
|
||||
# start navigation controller
|
||||
new App.Navigation( el: @el.find('#navigation') );
|
||||
new App.Navigation( el: @el.find('#navigation') )
|
||||
|
||||
# check if session already exists/try to get session data from server
|
||||
App.Auth.loginCheck()
|
||||
|
||||
# start notify controller
|
||||
new App.Notify( el: @el.find('#notify') );
|
||||
new App.Notify( el: @el.find('#notify') )
|
||||
|
||||
# start content
|
||||
new App.Content( el: @el.find('#content') );
|
||||
new App.Content( el: @el.find('#content') )
|
||||
|
||||
# bind to fill selected text into
|
||||
$(@el).bind('mouseup', =>
|
||||
|
|
|
@ -3,10 +3,6 @@ class App.Store
|
|||
@renew: ->
|
||||
_instance = new _Singleton
|
||||
|
||||
@load: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
|
||||
@write: (key, value) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
|
@ -22,10 +18,10 @@ class App.Store
|
|||
_instance ?= new _Singleton
|
||||
_instance.delete(args)
|
||||
|
||||
@clear: (args) ->
|
||||
@clear: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.clear(args)
|
||||
_instance.clear()
|
||||
|
||||
@list: () ->
|
||||
if _instance == undefined
|
||||
|
@ -34,94 +30,32 @@ class App.Store
|
|||
|
||||
# The actual Singleton class
|
||||
class _Singleton
|
||||
store: {}
|
||||
|
||||
constructor: (@args) ->
|
||||
# write to local storage
|
||||
write: (key, value) ->
|
||||
localStorage.setItem( key, JSON.stringify( value ) )
|
||||
|
||||
# find collections to load
|
||||
@_loadCollectionAll()
|
||||
@_loadCollectionType('TicketPriority')
|
||||
@_loadCollectionType('TicketStateType')
|
||||
@_loadCollectionType('TicketState')
|
||||
@_loadCollectionType('TicketArticleSender')
|
||||
@_loadCollectionType('TicketArticleType')
|
||||
@_loadCollectionType('Group')
|
||||
@_loadCollectionType('Role')
|
||||
@_loadCollectionType('Organization')
|
||||
@_loadCollectionType('User')
|
||||
@_loadCollectionType()
|
||||
# get item
|
||||
get: (key) ->
|
||||
value = localStorage.getItem( key )
|
||||
return if !value
|
||||
object = JSON.parse( value )
|
||||
return object
|
||||
|
||||
_loadCollectionAll: ->
|
||||
@all = {}
|
||||
@rest = {}
|
||||
# delete item
|
||||
delete: (key) ->
|
||||
localStorage.removeItem( key )
|
||||
|
||||
# clear local storage
|
||||
clear: ->
|
||||
localStorage.clear()
|
||||
|
||||
# return list of all keys
|
||||
list: ->
|
||||
list = []
|
||||
logLength = localStorage.length-1;
|
||||
for count in [0..logLength]
|
||||
key = localStorage.key( count )
|
||||
if key
|
||||
value = localStorage.getItem( key )
|
||||
data = JSON.parse( value )
|
||||
@all[key] = data
|
||||
|
||||
_loadCollectionType: (type) ->
|
||||
# console.log('STORE NEW' + logLength)
|
||||
toGo = @all
|
||||
if !_.isEmpty( @rest )
|
||||
toGo = _.clone( @rest )
|
||||
@rest = {}
|
||||
for key, data of toGo
|
||||
# console.log('STORE NEW' + count + '-' + key, data)
|
||||
if data['collections']
|
||||
data['localStorage'] = true
|
||||
|
||||
if type
|
||||
if data['type'] is type
|
||||
@_loadCollection(data)
|
||||
else
|
||||
@rest[key] = data
|
||||
else
|
||||
@_loadCollection(data)
|
||||
|
||||
_loadCollection: (data) ->
|
||||
console.log('fire', 'loadCollection', data )
|
||||
Spine.trigger( 'loadCollection', data )
|
||||
|
||||
write: (key, value) ->
|
||||
|
||||
# write to instance
|
||||
@store[ key ] = value
|
||||
|
||||
# write to local storage
|
||||
localStorage.setItem( key, JSON.stringify( value ) )
|
||||
|
||||
get: (key) ->
|
||||
|
||||
# return from instance
|
||||
return @store[ key ] if @store[ key ]
|
||||
|
||||
# if not, return from local storage
|
||||
value = localStorage.getItem( key )
|
||||
object = JSON.parse( value )
|
||||
return object if object
|
||||
|
||||
# return undefined if not in storage
|
||||
return undefined
|
||||
|
||||
delete: (key) ->
|
||||
delete @store[ key ]
|
||||
|
||||
clear: (action) ->
|
||||
|
||||
console.log 'Store:clear', action
|
||||
|
||||
# clear instance data
|
||||
@store = {}
|
||||
|
||||
# clear local storage
|
||||
if action is 'all'
|
||||
localStorage.clear()
|
||||
|
||||
list: () ->
|
||||
list = []
|
||||
for key of @store
|
||||
list.push key
|
||||
list.push key
|
||||
list
|
1059
app/assets/javascripts/app/lib/underscore-1.3.3.js
Normal file
1059
app/assets/javascripts/app/lib/underscore-1.3.3.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,682 +0,0 @@
|
|||
# **Underscore.coffee
|
||||
# (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.**
|
||||
# Underscore is freely distributable under the terms of the
|
||||
# [MIT license](http://en.wikipedia.org/wiki/MIT_License).
|
||||
# Portions of Underscore are inspired by or borrowed from
|
||||
# [Prototype.js](http://prototypejs.org/api), Oliver Steele's
|
||||
# [Functional](http://osteele.com), and John Resig's
|
||||
# [Micro-Templating](http://ejohn.org).
|
||||
# For all details and documentation:
|
||||
# http://documentcloud.github.com/underscore/
|
||||
|
||||
|
||||
# Baseline setup
|
||||
# --------------
|
||||
|
||||
# Establish the root object, `window` in the browser, or `global` on the server.
|
||||
root = this
|
||||
|
||||
|
||||
# Save the previous value of the `_` variable.
|
||||
previousUnderscore = root._
|
||||
|
||||
|
||||
# Establish the object that gets thrown to break out of a loop iteration.
|
||||
# `StopIteration` is SOP on Mozilla.
|
||||
breaker = if typeof(StopIteration) is 'undefined' then '__break__' else StopIteration
|
||||
|
||||
|
||||
# Helper function to escape **RegExp** contents, because JS doesn't have one.
|
||||
escapeRegExp = (string) -> string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1')
|
||||
|
||||
|
||||
# Save bytes in the minified (but not gzipped) version:
|
||||
ArrayProto = Array.prototype
|
||||
ObjProto = Object.prototype
|
||||
|
||||
|
||||
# Create quick reference variables for speed access to core prototypes.
|
||||
slice = ArrayProto.slice
|
||||
unshift = ArrayProto.unshift
|
||||
toString = ObjProto.toString
|
||||
hasOwnProperty = ObjProto.hasOwnProperty
|
||||
propertyIsEnumerable = ObjProto.propertyIsEnumerable
|
||||
|
||||
|
||||
# All **ECMA5** native implementations we hope to use are declared here.
|
||||
nativeForEach = ArrayProto.forEach
|
||||
nativeMap = ArrayProto.map
|
||||
nativeReduce = ArrayProto.reduce
|
||||
nativeReduceRight = ArrayProto.reduceRight
|
||||
nativeFilter = ArrayProto.filter
|
||||
nativeEvery = ArrayProto.every
|
||||
nativeSome = ArrayProto.some
|
||||
nativeIndexOf = ArrayProto.indexOf
|
||||
nativeLastIndexOf = ArrayProto.lastIndexOf
|
||||
nativeIsArray = Array.isArray
|
||||
nativeKeys = Object.keys
|
||||
|
||||
|
||||
# Create a safe reference to the Underscore object for use below.
|
||||
_ = (obj) -> new wrapper(obj)
|
||||
|
||||
|
||||
# Export the Underscore object for **CommonJS**.
|
||||
if typeof(exports) != 'undefined' then exports._ = _
|
||||
|
||||
|
||||
# Export Underscore to global scope.
|
||||
root._ = _
|
||||
|
||||
|
||||
# Current version.
|
||||
_.VERSION = '1.1.0'
|
||||
|
||||
|
||||
# Collection Functions
|
||||
# --------------------
|
||||
|
||||
# The cornerstone, an **each** implementation.
|
||||
# Handles objects implementing **forEach**, arrays, and raw objects.
|
||||
_.each = (obj, iterator, context) ->
|
||||
try
|
||||
if nativeForEach and obj.forEach is nativeForEach
|
||||
obj.forEach iterator, context
|
||||
else if _.isNumber obj.length
|
||||
iterator.call context, obj[i], i, obj for i in [0...obj.length]
|
||||
else
|
||||
iterator.call context, val, key, obj for own key, val of obj
|
||||
catch e
|
||||
throw e if e isnt breaker
|
||||
obj
|
||||
|
||||
|
||||
# Return the results of applying the iterator to each element. Use JavaScript
|
||||
# 1.6's version of **map**, if possible.
|
||||
_.map = (obj, iterator, context) ->
|
||||
return obj.map(iterator, context) if nativeMap and obj.map is nativeMap
|
||||
results = []
|
||||
_.each obj, (value, index, list) ->
|
||||
results.push iterator.call context, value, index, list
|
||||
results
|
||||
|
||||
|
||||
# **Reduce** builds up a single result from a list of values. Also known as
|
||||
# **inject**, or **foldl**. Uses JavaScript 1.8's version of **reduce**, if possible.
|
||||
_.reduce = (obj, iterator, memo, context) ->
|
||||
if nativeReduce and obj.reduce is nativeReduce
|
||||
iterator = _.bind iterator, context if context
|
||||
return obj.reduce iterator, memo
|
||||
_.each obj, (value, index, list) ->
|
||||
memo = iterator.call context, memo, value, index, list
|
||||
memo
|
||||
|
||||
|
||||
# The right-associative version of **reduce**, also known as **foldr**. Uses
|
||||
# JavaScript 1.8's version of **reduceRight**, if available.
|
||||
_.reduceRight = (obj, iterator, memo, context) ->
|
||||
if nativeReduceRight and obj.reduceRight is nativeReduceRight
|
||||
iterator = _.bind iterator, context if context
|
||||
return obj.reduceRight iterator, memo
|
||||
reversed = _.clone(_.toArray(obj)).reverse()
|
||||
_.reduce reversed, iterator, memo, context
|
||||
|
||||
|
||||
# Return the first value which passes a truth test.
|
||||
_.detect = (obj, iterator, context) ->
|
||||
result = null
|
||||
_.each obj, (value, index, list) ->
|
||||
if iterator.call context, value, index, list
|
||||
result = value
|
||||
_.breakLoop()
|
||||
result
|
||||
|
||||
|
||||
# Return all the elements that pass a truth test. Use JavaScript 1.6's
|
||||
# **filter**, if it exists.
|
||||
_.filter = (obj, iterator, context) ->
|
||||
return obj.filter iterator, context if nativeFilter and obj.filter is nativeFilter
|
||||
results = []
|
||||
_.each obj, (value, index, list) ->
|
||||
results.push value if iterator.call context, value, index, list
|
||||
results
|
||||
|
||||
|
||||
# Return all the elements for which a truth test fails.
|
||||
_.reject = (obj, iterator, context) ->
|
||||
results = []
|
||||
_.each obj, (value, index, list) ->
|
||||
results.push value if not iterator.call context, value, index, list
|
||||
results
|
||||
|
||||
|
||||
# Determine whether all of the elements match a truth test. Delegate to
|
||||
# JavaScript 1.6's **every**, if it is present.
|
||||
_.every = (obj, iterator, context) ->
|
||||
iterator ||= _.identity
|
||||
return obj.every iterator, context if nativeEvery and obj.every is nativeEvery
|
||||
result = true
|
||||
_.each obj, (value, index, list) ->
|
||||
_.breakLoop() unless (result = result and iterator.call(context, value, index, list))
|
||||
result
|
||||
|
||||
|
||||
# Determine if at least one element in the object matches a truth test. Use
|
||||
# JavaScript 1.6's **some**, if it exists.
|
||||
_.some = (obj, iterator, context) ->
|
||||
iterator ||= _.identity
|
||||
return obj.some iterator, context if nativeSome and obj.some is nativeSome
|
||||
result = false
|
||||
_.each obj, (value, index, list) ->
|
||||
_.breakLoop() if (result = iterator.call(context, value, index, list))
|
||||
result
|
||||
|
||||
|
||||
# Determine if a given value is included in the array or object,
|
||||
# based on `===`.
|
||||
_.include = (obj, target) ->
|
||||
return _.indexOf(obj, target) isnt -1 if nativeIndexOf and obj.indexOf is nativeIndexOf
|
||||
return true for own key, val of obj when val is target
|
||||
false
|
||||
|
||||
|
||||
# Invoke a method with arguments on every item in a collection.
|
||||
_.invoke = (obj, method) ->
|
||||
args = _.rest arguments, 2
|
||||
(if method then val[method] else val).apply(val, args) for val in obj
|
||||
|
||||
|
||||
# Convenience version of a common use case of **map**: fetching a property.
|
||||
_.pluck = (obj, key) ->
|
||||
_.map(obj, (val) -> val[key])
|
||||
|
||||
|
||||
# Return the maximum item or (item-based computation).
|
||||
_.max = (obj, iterator, context) ->
|
||||
return Math.max.apply(Math, obj) if not iterator and _.isArray(obj)
|
||||
result = computed: -Infinity
|
||||
_.each obj, (value, index, list) ->
|
||||
computed = if iterator then iterator.call(context, value, index, list) else value
|
||||
computed >= result.computed and (result = {value: value, computed: computed})
|
||||
result.value
|
||||
|
||||
|
||||
# Return the minimum element (or element-based computation).
|
||||
_.min = (obj, iterator, context) ->
|
||||
return Math.min.apply(Math, obj) if not iterator and _.isArray(obj)
|
||||
result = computed: Infinity
|
||||
_.each obj, (value, index, list) ->
|
||||
computed = if iterator then iterator.call(context, value, index, list) else value
|
||||
computed < result.computed and (result = {value: value, computed: computed})
|
||||
result.value
|
||||
|
||||
|
||||
# Sort the object's values by a criterion produced by an iterator.
|
||||
_.sortBy = (obj, iterator, context) ->
|
||||
_.pluck(((_.map obj, (value, index, list) ->
|
||||
{value: value, criteria: iterator.call(context, value, index, list)}
|
||||
).sort((left, right) ->
|
||||
a = left.criteria; b = right.criteria
|
||||
if a < b then -1 else if a > b then 1 else 0
|
||||
)), 'value')
|
||||
|
||||
|
||||
# Use a comparator function to figure out at what index an object should
|
||||
# be inserted so as to maintain order. Uses binary search.
|
||||
_.sortedIndex = (array, obj, iterator) ->
|
||||
iterator ||= _.identity
|
||||
low = 0
|
||||
high = array.length
|
||||
while low < high
|
||||
mid = (low + high) >> 1
|
||||
if iterator(array[mid]) < iterator(obj) then low = mid + 1 else high = mid
|
||||
low
|
||||
|
||||
|
||||
# Convert anything iterable into a real, live array.
|
||||
_.toArray = (iterable) ->
|
||||
return [] if (!iterable)
|
||||
return iterable.toArray() if (iterable.toArray)
|
||||
return iterable if (_.isArray(iterable))
|
||||
return slice.call(iterable) if (_.isArguments(iterable))
|
||||
_.values(iterable)
|
||||
|
||||
|
||||
# Return the number of elements in an object.
|
||||
_.size = (obj) -> _.toArray(obj).length
|
||||
|
||||
|
||||
# Array Functions
|
||||
# ---------------
|
||||
|
||||
# Get the first element of an array. Passing `n` will return the first N
|
||||
# values in the array. Aliased as **head**. The `guard` check allows it to work
|
||||
# with **map**.
|
||||
_.first = (array, n, guard) ->
|
||||
if n and not guard then slice.call(array, 0, n) else array[0]
|
||||
|
||||
|
||||
# Returns everything but the first entry of the array. Aliased as **tail**.
|
||||
# Especially useful on the arguments object. Passing an `index` will return
|
||||
# the rest of the values in the array from that index onward. The `guard`
|
||||
# check allows it to work with **map**.
|
||||
_.rest = (array, index, guard) ->
|
||||
slice.call(array, if _.isUndefined(index) or guard then 1 else index)
|
||||
|
||||
|
||||
# Get the last element of an array.
|
||||
_.last = (array) -> array[array.length - 1]
|
||||
|
||||
|
||||
# Trim out all falsy values from an array.
|
||||
_.compact = (array) -> item for item in array when item
|
||||
|
||||
|
||||
# Return a completely flattened version of an array.
|
||||
_.flatten = (array) ->
|
||||
_.reduce array, (memo, value) ->
|
||||
return memo.concat(_.flatten(value)) if _.isArray value
|
||||
memo.push value
|
||||
memo
|
||||
, []
|
||||
|
||||
|
||||
# Return a version of the array that does not contain the specified value(s).
|
||||
_.without = (array) ->
|
||||
values = _.rest arguments
|
||||
val for val in _.toArray(array) when not _.include values, val
|
||||
|
||||
|
||||
# Produce a duplicate-free version of the array. If the array has already
|
||||
# been sorted, you have the option of using a faster algorithm.
|
||||
_.uniq = (array, isSorted) ->
|
||||
memo = []
|
||||
for el, i in _.toArray array
|
||||
memo.push el if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el))
|
||||
memo
|
||||
|
||||
|
||||
# Produce an array that contains every item shared between all the
|
||||
# passed-in arrays.
|
||||
_.intersect = (array) ->
|
||||
rest = _.rest arguments
|
||||
_.select _.uniq(array), (item) ->
|
||||
_.all rest, (other) ->
|
||||
_.indexOf(other, item) >= 0
|
||||
|
||||
|
||||
# Zip together multiple lists into a single array -- elements that share
|
||||
# an index go together.
|
||||
_.zip = ->
|
||||
length = _.max _.pluck arguments, 'length'
|
||||
results = new Array length
|
||||
for i in [0...length]
|
||||
results[i] = _.pluck arguments, String i
|
||||
results
|
||||
|
||||
|
||||
# If the browser doesn't supply us with **indexOf** (I'm looking at you, MSIE),
|
||||
# we need this function. Return the position of the first occurrence of an
|
||||
# item in an array, or -1 if the item is not included in the array.
|
||||
_.indexOf = (array, item) ->
|
||||
return array.indexOf item if nativeIndexOf and array.indexOf is nativeIndexOf
|
||||
i = 0; l = array.length
|
||||
while l - i
|
||||
if array[i] is item then return i else i++
|
||||
-1
|
||||
|
||||
|
||||
# Provide JavaScript 1.6's **lastIndexOf**, delegating to the native function,
|
||||
# if possible.
|
||||
_.lastIndexOf = (array, item) ->
|
||||
return array.lastIndexOf(item) if nativeLastIndexOf and array.lastIndexOf is nativeLastIndexOf
|
||||
i = array.length
|
||||
while i
|
||||
if array[i] is item then return i else i--
|
||||
-1
|
||||
|
||||
|
||||
# Generate an integer Array containing an arithmetic progression. A port of
|
||||
# [the native Python **range** function](http://docs.python.org/library/functions.html#range).
|
||||
_.range = (start, stop, step) ->
|
||||
a = arguments
|
||||
solo = a.length <= 1
|
||||
i = start = if solo then 0 else a[0]
|
||||
stop = if solo then a[0] else a[1]
|
||||
step = a[2] or 1
|
||||
len = Math.ceil((stop - start) / step)
|
||||
return [] if len <= 0
|
||||
range = new Array len
|
||||
idx = 0
|
||||
loop
|
||||
return range if (if step > 0 then i - stop else stop - i) >= 0
|
||||
range[idx] = i
|
||||
idx++
|
||||
i+= step
|
||||
|
||||
|
||||
# Function Functions
|
||||
# ------------------
|
||||
|
||||
# Create a function bound to a given object (assigning `this`, and arguments,
|
||||
# optionally). Binding with arguments is also known as **curry**.
|
||||
_.bind = (func, obj) ->
|
||||
args = _.rest arguments, 2
|
||||
-> func.apply obj or root, args.concat arguments
|
||||
|
||||
|
||||
# Bind all of an object's methods to that object. Useful for ensuring that
|
||||
# all callbacks defined on an object belong to it.
|
||||
_.bindAll = (obj) ->
|
||||
funcs = if arguments.length > 1 then _.rest(arguments) else _.functions(obj)
|
||||
_.each funcs, (f) -> obj[f] = _.bind obj[f], obj
|
||||
obj
|
||||
|
||||
|
||||
# Delays a function for the given number of milliseconds, and then calls
|
||||
# it with the arguments supplied.
|
||||
_.delay = (func, wait) ->
|
||||
args = _.rest arguments, 2
|
||||
setTimeout((-> func.apply(func, args)), wait)
|
||||
|
||||
|
||||
# Memoize an expensive function by storing its results.
|
||||
_.memoize = (func, hasher) ->
|
||||
memo = {}
|
||||
hasher or= _.identity
|
||||
->
|
||||
key = hasher.apply this, arguments
|
||||
return memo[key] if key of memo
|
||||
memo[key] = func.apply this, arguments
|
||||
|
||||
|
||||
# Defers a function, scheduling it to run after the current call stack has
|
||||
# cleared.
|
||||
_.defer = (func) ->
|
||||
_.delay.apply _, [func, 1].concat _.rest arguments
|
||||
|
||||
|
||||
# Returns the first function passed as an argument to the second,
|
||||
# allowing you to adjust arguments, run code before and after, and
|
||||
# conditionally execute the original function.
|
||||
_.wrap = (func, wrapper) ->
|
||||
-> wrapper.apply wrapper, [func].concat arguments
|
||||
|
||||
|
||||
# Returns a function that is the composition of a list of functions, each
|
||||
# consuming the return value of the function that follows.
|
||||
_.compose = ->
|
||||
funcs = arguments
|
||||
->
|
||||
args = arguments
|
||||
for i in [funcs.length - 1..0] by -1
|
||||
args = [funcs[i].apply(this, args)]
|
||||
args[0]
|
||||
|
||||
|
||||
# Object Functions
|
||||
# ----------------
|
||||
|
||||
# Retrieve the names of an object's properties.
|
||||
_.keys = nativeKeys or (obj) ->
|
||||
return _.range 0, obj.length if _.isArray(obj)
|
||||
key for key, val of obj
|
||||
|
||||
|
||||
# Retrieve the values of an object's properties.
|
||||
_.values = (obj) ->
|
||||
_.map obj, _.identity
|
||||
|
||||
|
||||
# Return a sorted list of the function names available in Underscore.
|
||||
_.functions = (obj) ->
|
||||
_.filter(_.keys(obj), (key) -> _.isFunction(obj[key])).sort()
|
||||
|
||||
|
||||
# Extend a given object with all of the properties in a source object.
|
||||
_.extend = (obj) ->
|
||||
for source in _.rest(arguments)
|
||||
obj[key] = val for key, val of source
|
||||
obj
|
||||
|
||||
|
||||
# Create a (shallow-cloned) duplicate of an object.
|
||||
_.clone = (obj) ->
|
||||
return obj.slice 0 if _.isArray obj
|
||||
_.extend {}, obj
|
||||
|
||||
|
||||
# Invokes interceptor with the obj, and then returns obj.
|
||||
# The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
|
||||
_.tap = (obj, interceptor) ->
|
||||
interceptor obj
|
||||
obj
|
||||
|
||||
|
||||
# Perform a deep comparison to check if two objects are equal.
|
||||
_.isEqual = (a, b) ->
|
||||
# Check object identity.
|
||||
return true if a is b
|
||||
# Different types?
|
||||
atype = typeof(a); btype = typeof(b)
|
||||
return false if atype isnt btype
|
||||
# Basic equality test (watch out for coercions).
|
||||
return true if `a == b`
|
||||
# One is falsy and the other truthy.
|
||||
return false if (!a and b) or (a and !b)
|
||||
# One of them implements an `isEqual()`?
|
||||
return a.isEqual(b) if a.isEqual
|
||||
# Check dates' integer values.
|
||||
return a.getTime() is b.getTime() if _.isDate(a) and _.isDate(b)
|
||||
# Both are NaN?
|
||||
return false if _.isNaN(a) and _.isNaN(b)
|
||||
# Compare regular expressions.
|
||||
if _.isRegExp(a) and _.isRegExp(b)
|
||||
return a.source is b.source and
|
||||
a.global is b.global and
|
||||
a.ignoreCase is b.ignoreCase and
|
||||
a.multiline is b.multiline
|
||||
# If a is not an object by this point, we can't handle it.
|
||||
return false if atype isnt 'object'
|
||||
# Check for different array lengths before comparing contents.
|
||||
return false if a.length and (a.length isnt b.length)
|
||||
# Nothing else worked, deep compare the contents.
|
||||
aKeys = _.keys(a); bKeys = _.keys(b)
|
||||
# Different object sizes?
|
||||
return false if aKeys.length isnt bKeys.length
|
||||
# Recursive comparison of contents.
|
||||
return false for key, val of a when !(key of b) or !_.isEqual(val, b[key])
|
||||
true
|
||||
|
||||
|
||||
# Is a given array or object empty?
|
||||
_.isEmpty = (obj) ->
|
||||
return obj.length is 0 if _.isArray(obj) or _.isString(obj)
|
||||
return false for own key of obj
|
||||
true
|
||||
|
||||
|
||||
# Is a given value a DOM element?
|
||||
_.isElement = (obj) -> obj and obj.nodeType is 1
|
||||
|
||||
|
||||
# Is a given value an array?
|
||||
_.isArray = nativeIsArray or (obj) -> !!(obj and obj.concat and obj.unshift and not obj.callee)
|
||||
|
||||
|
||||
# Is a given variable an arguments object?
|
||||
_.isArguments = (obj) -> obj and obj.callee
|
||||
|
||||
|
||||
# Is the given value a function?
|
||||
_.isFunction = (obj) -> !!(obj and obj.constructor and obj.call and obj.apply)
|
||||
|
||||
|
||||
# Is the given value a string?
|
||||
_.isString = (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr))
|
||||
|
||||
|
||||
# Is a given value a number?
|
||||
_.isNumber = (obj) -> (obj is +obj) or toString.call(obj) is '[object Number]'
|
||||
|
||||
|
||||
# Is a given value a boolean?
|
||||
_.isBoolean = (obj) -> obj is true or obj is false
|
||||
|
||||
|
||||
# Is a given value a Date?
|
||||
_.isDate = (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear)
|
||||
|
||||
|
||||
# Is the given value a regular expression?
|
||||
_.isRegExp = (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false))
|
||||
|
||||
|
||||
# Is the given value NaN -- this one is interesting. `NaN != NaN`, and
|
||||
# `isNaN(undefined) == true`, so we make sure it's a number first.
|
||||
_.isNaN = (obj) -> _.isNumber(obj) and window.isNaN(obj)
|
||||
|
||||
|
||||
# Is a given value equal to null?
|
||||
_.isNull = (obj) -> obj is null
|
||||
|
||||
|
||||
# Is a given variable undefined?
|
||||
_.isUndefined = (obj) -> typeof obj is 'undefined'
|
||||
|
||||
|
||||
# Utility Functions
|
||||
# -----------------
|
||||
|
||||
# Run Underscore.js in noConflict mode, returning the `_` variable to its
|
||||
# previous owner. Returns a reference to the Underscore object.
|
||||
_.noConflict = ->
|
||||
root._ = previousUnderscore
|
||||
this
|
||||
|
||||
|
||||
# Keep the identity function around for default iterators.
|
||||
_.identity = (value) -> value
|
||||
|
||||
|
||||
# Run a function `n` times.
|
||||
_.times = (n, iterator, context) ->
|
||||
iterator.call context, i for i in [0...n]
|
||||
|
||||
|
||||
# Break out of the middle of an iteration.
|
||||
_.breakLoop = -> throw breaker
|
||||
|
||||
|
||||
# Add your own custom functions to the Underscore object, ensuring that
|
||||
# they're correctly added to the OOP wrapper as well.
|
||||
_.mixin = (obj) ->
|
||||
for name in _.functions(obj)
|
||||
addToWrapper name, _[name] = obj[name]
|
||||
|
||||
|
||||
# Generate a unique integer id (unique within the entire client session).
|
||||
# Useful for temporary DOM ids.
|
||||
idCounter = 0
|
||||
_.uniqueId = (prefix) ->
|
||||
(prefix or '') + idCounter++
|
||||
|
||||
|
||||
# By default, Underscore uses **ERB**-style template delimiters, change the
|
||||
# following template settings to use alternative delimiters.
|
||||
_.templateSettings = {
|
||||
start: '<%'
|
||||
end: '%>'
|
||||
interpolate: /<%=(.+?)%>/g
|
||||
}
|
||||
|
||||
|
||||
# JavaScript templating a-la **ERB**, pilfered from John Resig's
|
||||
# *Secrets of the JavaScript Ninja*, page 83.
|
||||
# Single-quote fix from Rick Strahl.
|
||||
# With alterations for arbitrary delimiters, and to preserve whitespace.
|
||||
_.template = (str, data) ->
|
||||
c = _.templateSettings
|
||||
endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+escapeRegExp(c.end)+")","g")
|
||||
fn = new Function 'obj',
|
||||
'var p=[],print=function(){p.push.apply(p,arguments);};' +
|
||||
'with(obj||{}){p.push(\'' +
|
||||
str.replace(/\r/g, '\\r')
|
||||
.replace(/\n/g, '\\n')
|
||||
.replace(/\t/g, '\\t')
|
||||
.replace(endMatch,"✄")
|
||||
.split("'").join("\\'")
|
||||
.split("✄").join("'")
|
||||
.replace(c.interpolate, "',$1,'")
|
||||
.split(c.start).join("');")
|
||||
.split(c.end).join("p.push('") +
|
||||
"');}return p.join('');"
|
||||
if data then fn(data) else fn
|
||||
|
||||
|
||||
# Aliases
|
||||
# -------
|
||||
|
||||
_.forEach = _.each
|
||||
_.foldl = _.inject = _.reduce
|
||||
_.foldr = _.reduceRight
|
||||
_.select = _.filter
|
||||
_.all = _.every
|
||||
_.any = _.some
|
||||
_.contains = _.include
|
||||
_.head = _.first
|
||||
_.tail = _.rest
|
||||
_.methods = _.functions
|
||||
|
||||
|
||||
# Setup the OOP Wrapper
|
||||
# ---------------------
|
||||
|
||||
# If Underscore is called as a function, it returns a wrapped object that
|
||||
# can be used OO-style. This wrapper holds altered versions of all the
|
||||
# underscore functions. Wrapped objects may be chained.
|
||||
wrapper = (obj) ->
|
||||
this._wrapped = obj
|
||||
this
|
||||
|
||||
|
||||
# Helper function to continue chaining intermediate results.
|
||||
result = (obj, chain) ->
|
||||
if chain then _(obj).chain() else obj
|
||||
|
||||
|
||||
# A method to easily add functions to the OOP wrapper.
|
||||
addToWrapper = (name, func) ->
|
||||
wrapper.prototype[name] = ->
|
||||
args = _.toArray arguments
|
||||
unshift.call args, this._wrapped
|
||||
result func.apply(_, args), this._chain
|
||||
|
||||
|
||||
# Add all ofthe Underscore functions to the wrapper object.
|
||||
_.mixin _
|
||||
|
||||
|
||||
# Add all mutator Array functions to the wrapper.
|
||||
_.each ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], (name) ->
|
||||
method = Array.prototype[name]
|
||||
wrapper.prototype[name] = ->
|
||||
method.apply(this._wrapped, arguments)
|
||||
result(this._wrapped, this._chain)
|
||||
|
||||
|
||||
# Add all accessor Array functions to the wrapper.
|
||||
_.each ['concat', 'join', 'slice'], (name) ->
|
||||
method = Array.prototype[name]
|
||||
wrapper.prototype[name] = ->
|
||||
result(method.apply(this._wrapped, arguments), this._chain)
|
||||
|
||||
|
||||
# Start chaining a wrapped Underscore object.
|
||||
wrapper::chain = ->
|
||||
this._chain = true
|
||||
this
|
||||
|
||||
|
||||
# Extracts the result from a wrapped and chained object.
|
||||
wrapper::value = -> this._wrapped
|
|
@ -21,7 +21,7 @@
|
|||
<%= @ticket.group.name %> -
|
||||
<%- T(@ticket.ticket_state.name) %> -
|
||||
<%- T(@ticket.ticket_priority.name) %> -
|
||||
<%- @ticket.humanTime %>
|
||||
<span class="humanTimeFromNow" data-time="<%- @ticket.created_at %>">?</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<a href="<%= action.href %>" data-type="<%= action.type %>" class="<% if action.class: %><%= action.class %><% end %>"><%= T(action.name) %></a>
|
||||
<% end %>
|
||||
<% end %>
|
||||
- <%- article.humanTime %> <%- T('ago') %>
|
||||
- <span class="humanTimeFromNow" data-time="<%- article.created_at %>">?</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if article.to: %>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<% for ticket in @tickets: %>
|
||||
<div class="row">
|
||||
<div class="customer-info"><a href="#ticket/zoom/<%= ticket.id %>" title="<%= ticket.title %>">T:<%= ticket.number %></a> <%= ticket.humanTime %><br/><%= ticket.title %></div>
|
||||
<div class="customer-info"><a href="#ticket/zoom/<%= ticket.id %>" title="<%= ticket.title %>">T:<%= ticket.number %></a> <span title="<%= ticket.created_at_short %>"><%= ticket.humanTime %></span><br/><%= ticket.title %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
Loading…
Reference in a new issue