Added text module feature.
This commit is contained in:
parent
e4506dd1a3
commit
898ee67a88
22 changed files with 590 additions and 67 deletions
|
@ -12,23 +12,21 @@ class App.ControllerGenericNew extends App.ControllerModal
|
||||||
render: ->
|
render: ->
|
||||||
|
|
||||||
@html App.view('generic/admin/new')( head: @pageData.object )
|
@html App.view('generic/admin/new')( head: @pageData.object )
|
||||||
|
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @el.find('#object_new'),
|
el: @el.find('#object_new'),
|
||||||
model: @genericObject,
|
model: App[ @genericObject ],
|
||||||
params: @item,
|
params: @item,
|
||||||
required: @required,
|
required: @required,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
@modalShow()
|
@modalShow()
|
||||||
|
|
||||||
submit: (e) ->
|
submit: (e) ->
|
||||||
@log 'submit'
|
@log 'submit'
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
params = @formParam(e.target)
|
params = @formParam( e.target )
|
||||||
|
|
||||||
object = new @genericObject
|
object = new App[ @genericObject ]
|
||||||
object.load(params)
|
object.load(params)
|
||||||
|
|
||||||
# validate
|
# validate
|
||||||
|
@ -53,7 +51,7 @@ class App.ControllerGenericNew extends App.ControllerModal
|
||||||
ui.modalHide()
|
ui.modalHide()
|
||||||
App.Collection.find( ui.pageData.object, @id, callbackReload , true )
|
App.Collection.find( ui.pageData.object, @id, callbackReload , true )
|
||||||
|
|
||||||
error: =>
|
error: ->
|
||||||
ui.log 'errors'
|
ui.log 'errors'
|
||||||
ui.modalHide()
|
ui.modalHide()
|
||||||
)
|
)
|
||||||
|
@ -64,28 +62,27 @@ class App.ControllerGenericEdit extends App.ControllerModal
|
||||||
@log 'ControllerGenericEditWindow', params
|
@log 'ControllerGenericEditWindow', params
|
||||||
|
|
||||||
# fetch item on demand
|
# fetch item on demand
|
||||||
if @genericObject.exists(params.id)
|
if App[ @genericObject ].exists( params.id )
|
||||||
@item = @genericObject.find(params.id)
|
@item = App[ @genericObject ].find( params.id )
|
||||||
@render()
|
@render()
|
||||||
else
|
else
|
||||||
@genericObject.bind 'refresh', =>
|
App[ @genericObject ].bind 'refresh', =>
|
||||||
@log 'changed....'
|
@log 'changed....'
|
||||||
@item = @genericObject.find(params.id)
|
@item = App[ @genericObject ].find( params.id )
|
||||||
@render()
|
@render()
|
||||||
@genericObject.unbind 'refresh'
|
App[ @genericObject ].unbind 'refresh'
|
||||||
@genericObject.fetch( id: params.id)
|
App[ @genericObject ].fetch( id: params.id )
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
@html App.view('generic/admin/edit')( head: @pageData.object )
|
|
||||||
|
|
||||||
|
@html App.view('generic/admin/edit')( head: @pageData.object )
|
||||||
new App.ControllerForm(
|
new App.ControllerForm(
|
||||||
el: @el.find('#object_edit'),
|
el: @el.find('#object_edit'),
|
||||||
model: @genericObject,
|
model: App[ @genericObject ],
|
||||||
params: @item,
|
params: @item,
|
||||||
required: @required,
|
required: @required,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
@modalShow()
|
@modalShow()
|
||||||
|
|
||||||
submit: (e) ->
|
submit: (e) ->
|
||||||
|
@ -139,8 +136,8 @@ class App.ControllerGenericIndex extends App.Controller
|
||||||
@navupdate @pageData.navupdate
|
@navupdate @pageData.navupdate
|
||||||
|
|
||||||
# bind render after a change is done
|
# bind render after a change is done
|
||||||
@genericObject.bind 'refresh change', @render
|
App[ @genericObject ].bind 'refresh change', @render
|
||||||
@genericObject.bind 'ajaxError', (rec, msg) =>
|
App[ @genericObject ].bind 'ajaxError', (rec, msg) =>
|
||||||
@log 'ajax notice', msg.status
|
@log 'ajax notice', msg.status
|
||||||
if msg.status is 401
|
if msg.status is 401
|
||||||
@log 'ajax error', rec, msg, msg.status
|
@log 'ajax error', rec, msg, msg.status
|
||||||
|
@ -149,16 +146,16 @@ class App.ControllerGenericIndex extends App.Controller
|
||||||
@navigate 'login'
|
@navigate 'login'
|
||||||
|
|
||||||
# execute fetch, if needed
|
# execute fetch, if needed
|
||||||
if !@genericObject.count() || true
|
if !App[ @genericObject ].count() || true
|
||||||
# if !@genericObject.count()
|
# if !App[ @genericObject ].count()
|
||||||
|
|
||||||
# prerender without content
|
# prerender without content
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
# fetch all
|
# fetch all
|
||||||
# @log 'oooo', @genericObject.model
|
# @log 'oooo', App[ @genericObject ].model
|
||||||
# @genericObject.deleteAll()
|
# App[ @genericObject ].deleteAll()
|
||||||
@genericObject.fetch()
|
App[ @genericObject ].fetch()
|
||||||
else
|
else
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
|
@ -166,7 +163,10 @@ class App.ControllerGenericIndex extends App.Controller
|
||||||
|
|
||||||
return if Config['ActiveController'] isnt @pageData.navupdate
|
return if Config['ActiveController'] isnt @pageData.navupdate
|
||||||
|
|
||||||
objects = @genericObject.all()
|
objects = App.Collection.all(
|
||||||
|
type: @genericObject,
|
||||||
|
sortBy: @defaultSortBy || 'name',
|
||||||
|
)
|
||||||
|
|
||||||
# remove ignored items from collection
|
# remove ignored items from collection
|
||||||
if @ignoreObjectIDs
|
if @ignoreObjectIDs
|
||||||
|
@ -185,21 +185,21 @@ class App.ControllerGenericIndex extends App.Controller
|
||||||
# append content table
|
# append content table
|
||||||
new App.ControllerTable(
|
new App.ControllerTable(
|
||||||
el: @el.find('.table-overview'),
|
el: @el.find('.table-overview'),
|
||||||
model: @genericObject,
|
model: App[ @genericObject ],
|
||||||
objects: objects,
|
objects: objects,
|
||||||
)
|
)
|
||||||
|
|
||||||
edit: (e) =>
|
edit: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
item = $(e.target).item(@genericObject)
|
item = $(e.target).item( App[ @genericObject ] )
|
||||||
new App.ControllerGenericEdit(
|
new App.ControllerGenericEdit(
|
||||||
id: item.id,
|
id: item.id,
|
||||||
pageData: @pageData,
|
pageData: @pageData,
|
||||||
genericObject: @genericObject
|
genericObject: @genericObject
|
||||||
)
|
)
|
||||||
|
|
||||||
destroy: (e) ->
|
destroy: (e) ->
|
||||||
item = $(e.target).item(@genericObject)
|
item = $(e.target).item( App[ @genericObject ] )
|
||||||
item.destroy() if confirm('Sure?')
|
item.destroy() if confirm('Sure?')
|
||||||
|
|
||||||
new: (e) ->
|
new: (e) ->
|
||||||
|
|
|
@ -138,6 +138,11 @@ class Index extends App.Controller
|
||||||
template_id: template['id'],
|
template_id: template['id'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# show text module UI
|
||||||
|
new App.TextModuleUI(
|
||||||
|
el: @el.find('#text_module'),
|
||||||
|
)
|
||||||
|
|
||||||
localUserInfo: (params) =>
|
localUserInfo: (params) =>
|
||||||
@userInfo( user_id: params.customer_id )
|
@userInfo( user_id: params.customer_id )
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ class App.TicketHistory extends App.ControllerModal
|
||||||
render: ->
|
render: ->
|
||||||
|
|
||||||
@html App.view('agent_ticket_history')(
|
@html App.view('agent_ticket_history')(
|
||||||
objects: App.Collection.all( 'History' ),
|
objects: App.Collection.all( type: 'History' ),
|
||||||
)
|
)
|
||||||
|
|
||||||
@modalShow()
|
@modalShow()
|
||||||
|
|
|
@ -203,6 +203,12 @@ class Index extends App.Controller
|
||||||
object: @ticket,
|
object: @ticket,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# show text module UI
|
||||||
|
if !@isRole('Customer')
|
||||||
|
new App.TextModuleUI(
|
||||||
|
el: @el.find('#text_module'),
|
||||||
|
)
|
||||||
|
|
||||||
show_toogle: (e) ->
|
show_toogle: (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
$(e.target).hide()
|
$(e.target).hide()
|
||||||
|
@ -320,12 +326,12 @@ class Index extends App.Controller
|
||||||
# @log 'reply ', article, @el.find('[name="to"]')
|
# @log 'reply ', article, @el.find('[name="to"]')
|
||||||
|
|
||||||
# add quoted text if needed
|
# add quoted text if needed
|
||||||
if window.Session['UISelection']
|
selectedText = App.ClipBoard.getSelected()
|
||||||
|
if selectedText
|
||||||
body = @el.find('[name="body"]').val() || ''
|
body = @el.find('[name="body"]').val() || ''
|
||||||
selection = window.Session['UISelection'].trim()
|
selectedText = selectedText.replace /^(.*)$/mg, (match) =>
|
||||||
selection = selection.replace /^(.*)$/mg, (match) =>
|
|
||||||
'> ' + match
|
'> ' + match
|
||||||
body = selection + "\n" + body
|
body = selectedText + "\n" + body
|
||||||
@el.find('[name="body"]').val(body)
|
@el.find('[name="body"]').val(body)
|
||||||
|
|
||||||
# update textarea size
|
# update textarea size
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Index extends App.Controller
|
||||||
new App.ControllerGenericIndex(
|
new App.ControllerGenericIndex(
|
||||||
el: @el,
|
el: @el,
|
||||||
id: @id,
|
id: @id,
|
||||||
genericObject: App.Group,
|
genericObject: 'Group',
|
||||||
pageData: {
|
pageData: {
|
||||||
title: 'Groups',
|
title: 'Groups',
|
||||||
home: 'groups',
|
home: 'groups',
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Index extends App.Controller
|
||||||
new App.ControllerGenericIndex(
|
new App.ControllerGenericIndex(
|
||||||
el: @el,
|
el: @el,
|
||||||
id: @id,
|
id: @id,
|
||||||
genericObject: App.Organization,
|
genericObject: 'Organization',
|
||||||
pageData: {
|
pageData: {
|
||||||
title: 'Organizations',
|
title: 'Organizations',
|
||||||
home: 'organizations',
|
home: 'organizations',
|
||||||
|
|
31
app/assets/javascripts/app/controllers/text_module.js.coffee
Normal file
31
app/assets/javascripts/app/controllers/text_module.js.coffee
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
$ = jQuery.sub()
|
||||||
|
|
||||||
|
class Index extends App.Controller
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
|
||||||
|
# check authentication
|
||||||
|
return if !@authenticate()
|
||||||
|
|
||||||
|
new App.ControllerGenericIndex(
|
||||||
|
el: @el,
|
||||||
|
id: @id,
|
||||||
|
genericObject: 'TextModule',
|
||||||
|
pageData: {
|
||||||
|
title: 'TextModules',
|
||||||
|
home: 'text_modules',
|
||||||
|
object: 'TextModule',
|
||||||
|
objects: 'TextModules',
|
||||||
|
navupdate: '#text_modules',
|
||||||
|
notes: [
|
||||||
|
'TextModules are ...'
|
||||||
|
],
|
||||||
|
buttons: [
|
||||||
|
{ name: 'New TextModule', 'data-type': 'new', class: 'primary' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
Config.Routes['text_modules'] = Index
|
||||||
|
Config.NavBar['AdminTextModule'] = { prio: 2300, parent: '#admin', name: 'Text Modules', target: '#text_modules', role: ['Admin'] }
|
||||||
|
|
212
app/assets/javascripts/app/controllers/text_modules.js.coffee
Normal file
212
app/assets/javascripts/app/controllers/text_modules.js.coffee
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
$ = jQuery.sub()
|
||||||
|
|
||||||
|
class App.TextModuleUI extends App.Controller
|
||||||
|
events:
|
||||||
|
'click [data-type=text_module_save]': 'create',
|
||||||
|
'click [data-type=text_module_select]': 'select',
|
||||||
|
'click [data-type=text_module_delete]': 'delete',
|
||||||
|
'click [data-type=edit]': 'select',
|
||||||
|
'dblclick [data-type=edit]': 'paste',
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
|
||||||
|
# fetch item on demand
|
||||||
|
fetch_needed = 1
|
||||||
|
if App.Collection.count( 'TextModule' ) > 0
|
||||||
|
fetch_needed = 0
|
||||||
|
@render()
|
||||||
|
|
||||||
|
if fetch_needed
|
||||||
|
@reload()
|
||||||
|
|
||||||
|
reload: =>
|
||||||
|
App.TextModule.bind 'refresh', =>
|
||||||
|
@log 'loading....'
|
||||||
|
@render()
|
||||||
|
App.TextModule.unbind 'refresh'
|
||||||
|
App.Collection.fetch( 'TextModule' )
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
|
||||||
|
ui = @
|
||||||
|
a = $('textarea')
|
||||||
|
|
||||||
|
# remember active text element
|
||||||
|
a.bind('focusin', ->
|
||||||
|
ui.area = $(@)
|
||||||
|
)
|
||||||
|
|
||||||
|
ui.C = false
|
||||||
|
ui.CList = ''
|
||||||
|
a.bind('keydown', (e) ->
|
||||||
|
|
||||||
|
# lisen if crtl is pressed
|
||||||
|
if ui.C
|
||||||
|
key = App.ClipBoard.keycode( e.keyCode )
|
||||||
|
|
||||||
|
# remove one char
|
||||||
|
if key is 'backspace'
|
||||||
|
ui.CList = ui.CList.slice( 0, -1 )
|
||||||
|
|
||||||
|
# take over
|
||||||
|
else if key is 'enter'
|
||||||
|
# ui.CList = ui.CList.slice(0, -1)
|
||||||
|
objects = ui.objectSearch( ui.CList )
|
||||||
|
if objects[0]
|
||||||
|
ui._insert( objects[0].content, ui )
|
||||||
|
|
||||||
|
# reset search
|
||||||
|
ui.CList = ''
|
||||||
|
ui.renderTable()
|
||||||
|
|
||||||
|
# add char to search selection
|
||||||
|
else
|
||||||
|
ui.CList = ui.CList + key
|
||||||
|
|
||||||
|
console.log 'CTRL+', ui.CList
|
||||||
|
ui.el.find('#text-module-search').val( ui.CList )
|
||||||
|
ui.renderTable( ui.CList )
|
||||||
|
|
||||||
|
# start current search process
|
||||||
|
if e.ctrlKey
|
||||||
|
ui.C = true
|
||||||
|
)
|
||||||
|
|
||||||
|
# start current search process
|
||||||
|
# do code to test other keys
|
||||||
|
a.bind('keyup', (e) ->
|
||||||
|
if e.keyCode == 17
|
||||||
|
console.log 'CTRL UP - pressed ', ui.CList
|
||||||
|
ui.CList = ''
|
||||||
|
ui.C = false
|
||||||
|
ui.renderTable()
|
||||||
|
)
|
||||||
|
|
||||||
|
@configure_attributes = [
|
||||||
|
{ name: 'text_module_id', display: '', tag: 'select', multiple: false, null: true, nulloption: true, relation: 'TextModule', class: 'span2', default: @text_module_id },
|
||||||
|
]
|
||||||
|
|
||||||
|
text_module = {}
|
||||||
|
if @text_module_id
|
||||||
|
text_module = App.Collection.find( 'TextModule', @text_module_id )
|
||||||
|
|
||||||
|
# insert data
|
||||||
|
@html App.view('text_module')(
|
||||||
|
text_module: text_module,
|
||||||
|
search: @search,
|
||||||
|
)
|
||||||
|
|
||||||
|
# rerender if search phrase has changed
|
||||||
|
@el.find('#text-module-search').unbind('keyup').bind('keyup', =>
|
||||||
|
search = $('#text-module-search').val();
|
||||||
|
console.log 'SEARCH', search
|
||||||
|
@renderTable( search )
|
||||||
|
)
|
||||||
|
|
||||||
|
@renderTable('')
|
||||||
|
|
||||||
|
objectSearch: (search) =>
|
||||||
|
objects = App.Collection.all(
|
||||||
|
type: 'TextModule',
|
||||||
|
sortBy: 'name',
|
||||||
|
filter: { active: true },
|
||||||
|
filterExtended: [ { name: search }, { content: search }, { keywords: search } ],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
renderTable: (search) =>
|
||||||
|
|
||||||
|
objects = @objectSearch(search)
|
||||||
|
|
||||||
|
@el.find('#form-text-module').html('')
|
||||||
|
new App.ControllerTable(
|
||||||
|
el: @el.find('#form-text-module'),
|
||||||
|
# header: ['Name'],
|
||||||
|
overview: ['name'],
|
||||||
|
model: App.TextModule,
|
||||||
|
objects: objects,
|
||||||
|
# radio: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
paste: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).parents('tr').data('id')
|
||||||
|
text_module = App.Collection.find( 'TextModule', id )
|
||||||
|
@_insert( text_module.content, @ )
|
||||||
|
|
||||||
|
delete: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
# get params
|
||||||
|
params = @formParam(e.target)
|
||||||
|
text_module = App.Collection.find( 'TextModule', params['text_module_id'] )
|
||||||
|
if confirm('Sure?')
|
||||||
|
text_module.destroy()
|
||||||
|
@text_module_id = undefined
|
||||||
|
@render()
|
||||||
|
|
||||||
|
select: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
id = $(e.target).parents('tr').data('id')
|
||||||
|
text_module = App.Collection.find( 'TextModule', id )
|
||||||
|
@el.find('#text-module-preview-content').val( text_module.content )
|
||||||
|
|
||||||
|
create: (e) =>
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
# get params
|
||||||
|
params = @formParam(e.target)
|
||||||
|
name = params['text_module_name']
|
||||||
|
# delete params['text_module_name']
|
||||||
|
|
||||||
|
text_module = App.Collection.findByAttribute( 'TextModule', 'name', name )
|
||||||
|
if !text_module
|
||||||
|
text_module = new App.TextModule
|
||||||
|
|
||||||
|
content = App.ClipBoard.getSelectedLast()
|
||||||
|
if content
|
||||||
|
text_module.load(
|
||||||
|
name: params['text_module_name']
|
||||||
|
content: content
|
||||||
|
)
|
||||||
|
|
||||||
|
# validate form
|
||||||
|
errors = text_module.validate()
|
||||||
|
|
||||||
|
# show errors in form
|
||||||
|
if errors
|
||||||
|
@log 'error new', errors
|
||||||
|
else
|
||||||
|
ui = @
|
||||||
|
text_module.save(
|
||||||
|
success: ->
|
||||||
|
ui.text_module_id = @.id
|
||||||
|
ui.render()
|
||||||
|
ui.log 'save success!'
|
||||||
|
|
||||||
|
error: ->
|
||||||
|
ui.log 'save failed!'
|
||||||
|
)
|
||||||
|
|
||||||
|
_insert: (contentNew, ui) ->
|
||||||
|
position = ui.area.prop('selectionStart')
|
||||||
|
content = ui.area.val()
|
||||||
|
start = content.substr( 0, position )
|
||||||
|
end = content.substr( position, content.length )
|
||||||
|
|
||||||
|
# check if \n is needed
|
||||||
|
startEnd = start.substr( start.length-2, 2 )
|
||||||
|
|
||||||
|
if position is 0 || startEnd is "\n\n"
|
||||||
|
startDiver = ''
|
||||||
|
else
|
||||||
|
startDiver = "\n"
|
||||||
|
content = start + startDiver + contentNew + end
|
||||||
|
ui.area.val(content)
|
||||||
|
|
||||||
|
# update cursor position
|
||||||
|
currentPosition = (position + contentNew.length + startDiver.length )
|
||||||
|
ui.area.prop('selectionStart', currentPosition )
|
||||||
|
ui.area.prop('selectionEnd', currentPosition )
|
||||||
|
|
|
@ -10,7 +10,8 @@ class Index extends App.Controller
|
||||||
new App.ControllerGenericIndex(
|
new App.ControllerGenericIndex(
|
||||||
el: @el,
|
el: @el,
|
||||||
id: @id,
|
id: @id,
|
||||||
genericObject: App.User,
|
genericObject: 'User',
|
||||||
|
defaultSortBy: 'login',
|
||||||
ignoreObjectIDs: [1],
|
ignoreObjectIDs: [1],
|
||||||
pageData: {
|
pageData: {
|
||||||
title: 'Users',
|
title: 'Users',
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#not_used= require_tree ./lib
|
#not_used= require_tree ./lib
|
||||||
#= require_self
|
#= require_self
|
||||||
#= require ./lib/ajax.js.coffee
|
#= require ./lib/ajax.js.coffee
|
||||||
|
#= require ./lib/clipboard.js.coffee
|
||||||
#= require ./lib/websocket.js.coffee
|
#= require ./lib/websocket.js.coffee
|
||||||
#= require ./lib/auth.js.coffee
|
#= require ./lib/auth.js.coffee
|
||||||
#= require ./lib/i18n.js.coffee
|
#= require ./lib/i18n.js.coffee
|
||||||
|
|
|
@ -202,14 +202,24 @@ class _Singleton
|
||||||
|
|
||||||
get: (params) ->
|
get: (params) ->
|
||||||
console.log('get')
|
console.log('get')
|
||||||
App[params.type].refresh( object, options: { clear: true } )
|
App[ params.type ].refresh( object, options: { clear: true } )
|
||||||
|
|
||||||
all: (type) ->
|
all: (params) ->
|
||||||
all = App[type].all()
|
all = App[ params.type ].all()
|
||||||
all_complied = []
|
all_complied = []
|
||||||
for item in all
|
for item in all
|
||||||
item_new = @find( type, item.id )
|
item_new = @find( params.type, item.id )
|
||||||
all_complied.push item_new
|
all_complied.push item_new
|
||||||
|
|
||||||
|
if params.filter
|
||||||
|
all_complied = @_filter( all_complied, params.filter )
|
||||||
|
|
||||||
|
if params.filterExtended
|
||||||
|
all_complied = @_filterExtended( all_complied, params.filterExtended )
|
||||||
|
|
||||||
|
if params.sortBy
|
||||||
|
all_complied = @_sortBy( all_complied, params.sortBy )
|
||||||
|
|
||||||
return all_complied
|
return all_complied
|
||||||
|
|
||||||
deleteAll: (type) ->
|
deleteAll: (type) ->
|
||||||
|
@ -223,3 +233,40 @@ class _Singleton
|
||||||
|
|
||||||
fetch: ( type ) ->
|
fetch: ( type ) ->
|
||||||
App[type].fetch()
|
App[type].fetch()
|
||||||
|
|
||||||
|
_sortBy: ( collection, attribute ) ->
|
||||||
|
_.sortBy( collection, (item) -> return item[ attribute ].toLowerCase() )
|
||||||
|
|
||||||
|
_filter: ( collection, filter ) ->
|
||||||
|
for key, value of filter
|
||||||
|
collection = _.filter( collection, (item) ->
|
||||||
|
if item[ key ] is value
|
||||||
|
return item
|
||||||
|
)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
_filterExtended: ( collection, filters ) ->
|
||||||
|
collection = _.filter( collection, (item) ->
|
||||||
|
|
||||||
|
# check all filters
|
||||||
|
for filter in filters
|
||||||
|
|
||||||
|
# all conditions need match
|
||||||
|
matchInner = undefined
|
||||||
|
for key, value of filter
|
||||||
|
|
||||||
|
if matchInner isnt false
|
||||||
|
reg = new RegExp( value, 'i' )
|
||||||
|
if item[ key ] isnt undefined && item[ key ] isnt null && item[ key ].match( reg )
|
||||||
|
matchInner = true
|
||||||
|
else
|
||||||
|
matchInner = false
|
||||||
|
|
||||||
|
# if all matched, add item to new collection
|
||||||
|
if matchInner is true
|
||||||
|
return item
|
||||||
|
|
||||||
|
return
|
||||||
|
)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
|
|
@ -27,19 +27,7 @@ class App.Run extends App.Controller
|
||||||
new App.Content( el: @el.find('#content') )
|
new App.Content( el: @el.find('#content') )
|
||||||
|
|
||||||
# bind to fill selected text into
|
# bind to fill selected text into
|
||||||
$(@el).bind('mouseup', =>
|
App.ClipBoard.bind( @el )
|
||||||
window.Session['UISelection'] = @getSelected() + ''
|
|
||||||
)
|
|
||||||
|
|
||||||
getSelected: ->
|
|
||||||
text = '';
|
|
||||||
if window.getSelection
|
|
||||||
text = window.getSelection()
|
|
||||||
else if document.getSelection
|
|
||||||
text = document.getSelection()
|
|
||||||
else if document.selection
|
|
||||||
text = document.selection.createRange().text
|
|
||||||
text
|
|
||||||
|
|
||||||
class App.Content extends Spine.Controller
|
class App.Content extends Spine.Controller
|
||||||
className: 'container'
|
className: 'container'
|
||||||
|
|
|
@ -29,7 +29,7 @@ class _Singleton extends Spine.Controller
|
||||||
|
|
||||||
send: (data) =>
|
send: (data) =>
|
||||||
return if !@supported
|
return if !@supported
|
||||||
console.log 'ws:send trying', data, @ws, @ws.readyState
|
# console.log 'ws:send trying', data, @ws, @ws.readyState
|
||||||
|
|
||||||
# A value of 0 indicates that the connection has not yet been established.
|
# A value of 0 indicates that the connection has not yet been established.
|
||||||
# A value of 1 indicates that the connection is established and communication is possible.
|
# A value of 1 indicates that the connection is established and communication is possible.
|
||||||
|
@ -38,7 +38,7 @@ class _Singleton extends Spine.Controller
|
||||||
if @ws.readyState is 0
|
if @ws.readyState is 0
|
||||||
@queue.push data
|
@queue.push data
|
||||||
else
|
else
|
||||||
console.log( 'ws:send', data )
|
# console.log( 'ws:send', data )
|
||||||
string = JSON.stringify( data )
|
string = JSON.stringify( data )
|
||||||
@ws.send(string)
|
@ws.send(string)
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class _Singleton extends Spine.Controller
|
||||||
ping: =>
|
ping: =>
|
||||||
return if !@supported
|
return if !@supported
|
||||||
|
|
||||||
console.log 'send websockend ping'
|
# console.log 'send websockend ping'
|
||||||
@send( { action: 'ping' } )
|
@send( { action: 'ping' } )
|
||||||
|
|
||||||
# check if ping is back within 2 min
|
# check if ping is back within 2 min
|
||||||
|
@ -73,8 +73,7 @@ class _Singleton extends Spine.Controller
|
||||||
|
|
||||||
pong: ->
|
pong: ->
|
||||||
return if !@supported
|
return if !@supported
|
||||||
|
# console.log 'received websockend ping'
|
||||||
console.log 'received websockend ping'
|
|
||||||
|
|
||||||
# test again after 1 min
|
# test again after 1 min
|
||||||
@delay @ping, 60000
|
@delay @ping, 60000
|
||||||
|
@ -111,7 +110,7 @@ class _Singleton extends Spine.Controller
|
||||||
|
|
||||||
# empty queue
|
# empty queue
|
||||||
for item in @queue
|
for item in @queue
|
||||||
console.log( 'ws:send queue', item )
|
# console.log( 'ws:send queue', item )
|
||||||
@send(item)
|
@send(item)
|
||||||
@queue = []
|
@queue = []
|
||||||
|
|
||||||
|
|
16
app/assets/javascripts/app/models/text_module.js.coffee
Normal file
16
app/assets/javascripts/app/models/text_module.js.coffee
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
class App.TextModule extends App.Model
|
||||||
|
@configure 'TextModule', 'name', 'keywords', 'content', 'active', 'group_ids', 'user_id'
|
||||||
|
@extend Spine.Model.Ajax
|
||||||
|
@url: '/api/text_modules'
|
||||||
|
@configure_attributes = [
|
||||||
|
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
|
||||||
|
{ name: 'keywords', display: 'Keywords', tag: 'input', type: 'text', limit: 100, 'null': true, 'class': 'span4' },
|
||||||
|
{ name: 'content', display: 'Content', tag: 'textarea', limit: 250, 'null': false, 'class': 'span4' },
|
||||||
|
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||||
|
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
|
||||||
|
]
|
||||||
|
@configure_overview = [
|
||||||
|
'name',
|
||||||
|
'keywords',
|
||||||
|
'content',
|
||||||
|
]
|
|
@ -7,6 +7,7 @@
|
||||||
<div class="span3">
|
<div class="span3">
|
||||||
<div id="customer_info"></div>
|
<div id="customer_info"></div>
|
||||||
<div id="ticket_template"></div>
|
<div id="ticket_template"></div>
|
||||||
|
<div id="text_module"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|
|
@ -91,9 +91,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="span3">
|
<div class="span3">
|
||||||
<div class="row" id="customer_info"></div>
|
<div id="customer_info"></div>
|
||||||
<div class="row" id="action_info"></div>
|
<div id="action_info"></div>
|
||||||
<div class="row" id="link_info"></div>
|
<div id="link_info"></div>
|
||||||
|
<div id="text_module"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
20
app/assets/javascripts/app/views/text_module.jst.eco
Normal file
20
app/assets/javascripts/app/views/text_module.jst.eco
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<div class="well">
|
||||||
|
<h3><%- @T( 'Text Modules' ) %></h3>
|
||||||
|
<%- @T( 'Search' ) %>
|
||||||
|
<br>
|
||||||
|
<input type="text" name="" id="text-module-search" class="span2" value="<%= @search %>" autocomplete="off"/>
|
||||||
|
<br>
|
||||||
|
<div id="form-text-module"></div>
|
||||||
|
<!--<button type="submit" class="btn" data-type="text_module_edit"><%- @T( 'Edit' ) %></button>-->
|
||||||
|
<!--
|
||||||
|
<button type="submit" class="btn" data-type="text_module_delete"><%- @T( 'Delete' ) %></button>
|
||||||
|
<button type="submit" class="btn" data-type="text_module_select"><%- @T( 'Apply' ) %></button>
|
||||||
|
-->
|
||||||
|
<%- @T( 'Preview ') %>
|
||||||
|
<br>
|
||||||
|
<textarea id="text-module-preview-content" class="span2"></textarea>
|
||||||
|
<hr>
|
||||||
|
<label class="" for="text_module_name"><%- @T( 'Save as Text Module' ) %></label>
|
||||||
|
<input type="text" name="text_module_name" id="text_module_name" class="span2" value="<%= @text_module.name %>"/>
|
||||||
|
<button type="submit" class="btn" data-type="text_module_save"><%- @T( 'Save' ) %></button>
|
||||||
|
</div>
|
148
app/controllers/text_modules_controller.rb
Normal file
148
app/controllers/text_modules_controller.rb
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
class TextModulesController < ApplicationController
|
||||||
|
before_filter :authentication_check
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Format:
|
||||||
|
JSON
|
||||||
|
|
||||||
|
Example:
|
||||||
|
{
|
||||||
|
"id":1,
|
||||||
|
"name":"some text_module",
|
||||||
|
"user_id": null,
|
||||||
|
"keywords":"some keywords",
|
||||||
|
"content":"some content",
|
||||||
|
"active":true,
|
||||||
|
"updated_at":"2012-09-14T17:51:53Z",
|
||||||
|
"created_at":"2012-09-14T17:51:53Z",
|
||||||
|
"updated_by_id":2.
|
||||||
|
"created_by_id":2,
|
||||||
|
}
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
GET /api/text_modules.json
|
||||||
|
|
||||||
|
Response:
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "some_name1",
|
||||||
|
...
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "some_name2",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/text_modules.json -v -u #{login}:#{password}
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def index
|
||||||
|
model_index_render(TextModule, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
GET /api/text_modules/#{id}.json
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "name_1",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/text_modules/#{id}.json -v -u #{login}:#{password}
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def show
|
||||||
|
model_show_render(TextModule, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
POST /api/text_modules.json
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
{
|
||||||
|
"name": "some name",
|
||||||
|
"keywords":"some keywords",
|
||||||
|
"content":"some content",
|
||||||
|
"active":true,
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "some_name",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/text_modules.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"name": "some_name","active": true, "note": "some note"}'
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def create
|
||||||
|
model_create_render(TextModule, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
PUT /api/text_modules/{id}.json
|
||||||
|
|
||||||
|
Payload:
|
||||||
|
{
|
||||||
|
"name": "some name",
|
||||||
|
"keywords":"some keywords",
|
||||||
|
"content":"some content",
|
||||||
|
"active":true,
|
||||||
|
}
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "some_name",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/text_modules.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}'
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def update
|
||||||
|
model_update_render(TextModule, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
|
||||||
|
Resource:
|
||||||
|
DELETE /api/text_modules/{id}.json
|
||||||
|
|
||||||
|
Response:
|
||||||
|
{}
|
||||||
|
|
||||||
|
Test:
|
||||||
|
curl http://localhost/api/text_modules.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
|
||||||
|
|
||||||
|
=end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
model_destory_render(TextModule, params)
|
||||||
|
end
|
||||||
|
end
|
4
app/models/text_module.rb
Normal file
4
app/models/text_module.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
class TextModule < ApplicationModel
|
||||||
|
validates :name, :presence => true
|
||||||
|
validates :content, :presence => true
|
||||||
|
end
|
13
config/routes/text_module.rb
Normal file
13
config/routes/text_module.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module ExtraRoutes
|
||||||
|
def add(map)
|
||||||
|
|
||||||
|
# roles
|
||||||
|
map.match '/api/text_modules', :to => 'text_modules#index', :via => :get
|
||||||
|
map.match '/api/text_modules/:id', :to => 'text_modules#show', :via => :get
|
||||||
|
map.match '/api/text_modules', :to => 'text_modules#create', :via => :post
|
||||||
|
map.match '/api/text_modules/:id', :to => 'text_modules#update', :via => :put
|
||||||
|
map.match '/api/text_modules/:id', :to => 'templates#destroy', :via => :delete
|
||||||
|
|
||||||
|
end
|
||||||
|
module_function :add
|
||||||
|
end
|
30
db/migrate/20121019140507_text_module_create.rb
Normal file
30
db/migrate/20121019140507_text_module_create.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
class TextModuleCreate < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
create_table :text_modules do |t|
|
||||||
|
t.references :user, :null => true
|
||||||
|
t.column :name, :string, :limit => 250, :null => false
|
||||||
|
t.column :keywords, :string, :limit => 500, :null => true
|
||||||
|
t.column :content, :string, :limit => 5000, :null => false
|
||||||
|
t.column :note, :string, :limit => 250, :null => true
|
||||||
|
t.column :active, :boolean, :null => false, :default => true
|
||||||
|
t.column :updated_by_id, :integer, :null => false
|
||||||
|
t.column :created_by_id, :integer, :null => false
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
add_index :text_modules, [:user_id]
|
||||||
|
add_index :text_modules, [:name]
|
||||||
|
|
||||||
|
create_table :text_modules_groups, :id => false do |t|
|
||||||
|
t.integer :text_module_id
|
||||||
|
t.integer :group_id
|
||||||
|
end
|
||||||
|
add_index :text_modules_groups, [:text_module_id]
|
||||||
|
add_index :text_modules_groups, [:group_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
drop_table :text_modules_groups
|
||||||
|
drop_table :text_modules
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue