Restructured of lib directory.
This commit is contained in:
parent
c3d7391e02
commit
e27664ec1c
34 changed files with 16331 additions and 24 deletions
|
@ -1,40 +1,30 @@
|
||||||
#s#= require json2
|
#s#= require json2
|
||||||
#= require ./lib/jquery-1.8.1.min.js
|
#= require ./lib/core/jquery-1.8.1.min.js
|
||||||
#= require ./lib/ui/jquery-ui-1.8.23.custom.min.js
|
#= require ./lib/core/jquery-ui-1.8.23.custom.min.js
|
||||||
|
#= require ./lib/core/underscore-1.3.3.js
|
||||||
|
|
||||||
|
#not_used= require_tree ./lib/spine
|
||||||
#= require ./lib/spine/spine.js
|
#= require ./lib/spine/spine.js
|
||||||
#= require ./lib/spine/ajax.js
|
#= require ./lib/spine/ajax.js
|
||||||
#= require ./lib/spine/route.js
|
#= require ./lib/spine/route.js
|
||||||
|
|
||||||
#= require ./lib/bootstrap-dropdown.js
|
#not_used= require_tree ./lib/bootstrap
|
||||||
#= require ./lib/bootstrap-tooltip.js
|
#= require ./lib/bootstrap/bootstrap-dropdown.js
|
||||||
#= require ./lib/bootstrap-popover.js
|
#= require ./lib/bootstrap/bootstrap-tooltip.js
|
||||||
#= require ./lib/bootstrap-modal.js
|
#= require ./lib/bootstrap/bootstrap-popover.js
|
||||||
#= require ./lib/bootstrap-tab.js
|
#= require ./lib/bootstrap/bootstrap-modal.js
|
||||||
#= require ./lib/bootstrap-transition.js
|
#= require ./lib/bootstrap/bootstrap-tab.js
|
||||||
|
#= require ./lib/bootstrap/bootstrap-transition.js
|
||||||
|
|
||||||
#= require ./lib/underscore-1.3.3.js
|
#= require_tree ./lib/base
|
||||||
#= require ./lib/ba-linkify.js
|
|
||||||
#= require ./lib/jquery.tagsinput.js
|
|
||||||
#= require ./lib/jquery.noty.js
|
|
||||||
#= require ./lib/waypoints.js
|
|
||||||
#= require ./lib/fileuploader.js
|
|
||||||
#= require ./lib/jquery.elastic.source.js
|
|
||||||
|
|
||||||
#not_used= require_tree ./lib
|
#not_used= require_tree ./lib
|
||||||
#= require_self
|
#= require_self
|
||||||
#= require_tree ./models
|
#= require_tree ./models
|
||||||
#= require_tree ./controllers
|
#= require_tree ./controllers
|
||||||
#= require_tree ./views
|
#= require_tree ./views
|
||||||
#= require ./lib/ajax.js.coffee
|
|
||||||
#= require ./lib/clipboard.js.coffee
|
#= require_tree ./lib/app
|
||||||
#= require ./lib/websocket.js.coffee
|
|
||||||
#= require ./lib/auth.js.coffee
|
|
||||||
#= require ./lib/i18n.js.coffee
|
|
||||||
#= require ./lib/store.js.coffee
|
|
||||||
#= require ./lib/collection.js.coffee
|
|
||||||
#= require ./lib/event.js.coffee
|
|
||||||
#= require ./lib/interface_handle.js.coffee
|
|
||||||
|
|
||||||
class App extends Spine.Controller
|
class App extends Spine.Controller
|
||||||
@view: (name) ->
|
@view: (name) ->
|
||||||
|
|
66
app/assets/javascripts/app/lib/app/ajax.js.coffee
Normal file
66
app/assets/javascripts/app/lib/app/ajax.js.coffee
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
$ = jQuery.sub()
|
||||||
|
|
||||||
|
class App.Com
|
||||||
|
_instance = undefined # Must be declared here to force the closure on the class
|
||||||
|
@ajax: (args) -> # Must be a static method
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
|
||||||
|
_instance.ajax(args)
|
||||||
|
_instance
|
||||||
|
|
||||||
|
# The actual Singleton class
|
||||||
|
class _Singleton
|
||||||
|
defaults:
|
||||||
|
contentType: 'application/json'
|
||||||
|
dataType: 'json'
|
||||||
|
processData: false
|
||||||
|
headers: {'X-Requested-With': 'XMLHttpRequest'}
|
||||||
|
cache: false
|
||||||
|
async: true
|
||||||
|
|
||||||
|
queue_list: {}
|
||||||
|
count: 0
|
||||||
|
|
||||||
|
constructor: (@args) ->
|
||||||
|
|
||||||
|
# bindings
|
||||||
|
$('body').bind( 'ajaxSend', =>
|
||||||
|
@_show_spinner()
|
||||||
|
).bind( 'ajaxComplete', =>
|
||||||
|
@_hide_spinner()
|
||||||
|
)
|
||||||
|
|
||||||
|
# show error messages
|
||||||
|
$('body').bind( 'ajaxError', ( e, jqxhr, settings, exception ) ->
|
||||||
|
status = jqxhr.status
|
||||||
|
detail = jqxhr.responseText
|
||||||
|
if !status && !detail
|
||||||
|
detail = 'General communication error, maybe internet is not available!'
|
||||||
|
new App.ErrorModal(
|
||||||
|
message: 'StatusCode: ' + status
|
||||||
|
detail: detail
|
||||||
|
close: true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
ajax: (params, defaults) ->
|
||||||
|
data = $.extend({}, @defaults, defaults, params)
|
||||||
|
if params['id']
|
||||||
|
if @queue_list[ params['id'] ]
|
||||||
|
@queue_list[ params['id'] ].abort()
|
||||||
|
@queue_list[ params['id'] ] = $.ajax( data )
|
||||||
|
else
|
||||||
|
$.ajax( data )
|
||||||
|
|
||||||
|
# console.log('AJAX', params['url'] )
|
||||||
|
|
||||||
|
_show_spinner: =>
|
||||||
|
@count++
|
||||||
|
$('.spinner').show()
|
||||||
|
|
||||||
|
_hide_spinner: =>
|
||||||
|
@count--
|
||||||
|
if @count == 0
|
||||||
|
$('.spinner').hide()
|
||||||
|
|
108
app/assets/javascripts/app/lib/app/auth.js.coffee
Normal file
108
app/assets/javascripts/app/lib/app/auth.js.coffee
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
$ = jQuery.sub()
|
||||||
|
|
||||||
|
class App.Auth
|
||||||
|
|
||||||
|
@login: (params) ->
|
||||||
|
console.log 'login(...)', params
|
||||||
|
App.Com.ajax(
|
||||||
|
id: 'login',
|
||||||
|
type: 'POST',
|
||||||
|
url: '/signin',
|
||||||
|
data: JSON.stringify(params.data),
|
||||||
|
success: (data, status, xhr) =>
|
||||||
|
|
||||||
|
# clear store
|
||||||
|
App.Store.clear('all')
|
||||||
|
|
||||||
|
# execute callback
|
||||||
|
params.success(data, status, xhr)
|
||||||
|
|
||||||
|
error: (xhr, statusText, error) =>
|
||||||
|
params.error(xhr, statusText, error)
|
||||||
|
)
|
||||||
|
|
||||||
|
@loginCheck: ->
|
||||||
|
console.log 'loginCheck(...)'
|
||||||
|
App.Com.ajax(
|
||||||
|
id: 'login_check',
|
||||||
|
async: false,
|
||||||
|
type: 'GET',
|
||||||
|
url: '/signshow',
|
||||||
|
success: (data, status, xhr) =>
|
||||||
|
console.log 'logincheck:success', data
|
||||||
|
|
||||||
|
# if session is not valid
|
||||||
|
if data.error
|
||||||
|
|
||||||
|
# update config
|
||||||
|
for key, value of data.config
|
||||||
|
window.Config[key] = value
|
||||||
|
|
||||||
|
# empty session
|
||||||
|
window.Session = {}
|
||||||
|
|
||||||
|
# update websocked auth info
|
||||||
|
App.WebSocket.auth()
|
||||||
|
|
||||||
|
# rebuild navbar with new navbar items
|
||||||
|
App.Event.trigger 'navrebuild'
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
# set avatar
|
||||||
|
if !data.session.image
|
||||||
|
data.session.image = 'http://placehold.it/48x48'
|
||||||
|
|
||||||
|
# update config
|
||||||
|
for key, value of data.config
|
||||||
|
window.Config[key] = value
|
||||||
|
|
||||||
|
# store user data
|
||||||
|
for key, value of data.session
|
||||||
|
window.Session[key] = value
|
||||||
|
|
||||||
|
# update websocked auth info
|
||||||
|
App.WebSocket.auth()
|
||||||
|
|
||||||
|
# refresh/load default collections
|
||||||
|
for key, value of data.default_collections
|
||||||
|
App.Collection.reset( type: key, data: value )
|
||||||
|
|
||||||
|
# rebuild navbar with new navbar items
|
||||||
|
App.Event.trigger 'navrebuild', data.session
|
||||||
|
|
||||||
|
# rebuild navbar with updated ticket count of overviews
|
||||||
|
App.Event.trigger 'navupdate_remote'
|
||||||
|
|
||||||
|
error: (xhr, statusText, error) =>
|
||||||
|
console.log 'loginCheck:error'#, error, statusText, xhr.statusCode
|
||||||
|
|
||||||
|
# empty session
|
||||||
|
window.Session = {}
|
||||||
|
|
||||||
|
# clear store
|
||||||
|
App.Store.clear('all')
|
||||||
|
|
||||||
|
# update websocked auth info
|
||||||
|
App.WebSocket.auth()
|
||||||
|
)
|
||||||
|
|
||||||
|
@logout: ->
|
||||||
|
console.log 'logout(...)'
|
||||||
|
App.Com.ajax(
|
||||||
|
id: 'logout',
|
||||||
|
type: 'DELETE',
|
||||||
|
url: '/signout',
|
||||||
|
success: =>
|
||||||
|
|
||||||
|
# update websocked auth info
|
||||||
|
App.WebSocket.auth()
|
||||||
|
|
||||||
|
# clear store
|
||||||
|
App.Store.clear('all')
|
||||||
|
|
||||||
|
error: (xhr, statusText, error) =>
|
||||||
|
|
||||||
|
# update websocked auth info
|
||||||
|
App.WebSocket.auth()
|
||||||
|
)
|
181
app/assets/javascripts/app/lib/app/clipboard.js.coffee
Normal file
181
app/assets/javascripts/app/lib/app/clipboard.js.coffee
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
class App.ClipBoard
|
||||||
|
_instance = undefined
|
||||||
|
|
||||||
|
@bind: (el) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.bind(el)
|
||||||
|
|
||||||
|
@getSelected: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.getSelected()
|
||||||
|
|
||||||
|
@getSelectedLast: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.getSelectedLast()
|
||||||
|
|
||||||
|
@keycode: (code) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.keycode(code)
|
||||||
|
|
||||||
|
class _Singleton
|
||||||
|
constructor: ->
|
||||||
|
@selection = ''
|
||||||
|
@selectionLast = ''
|
||||||
|
|
||||||
|
# bind to fill selected text into
|
||||||
|
bind: (el) ->
|
||||||
|
$(el).bind('mouseup', =>
|
||||||
|
|
||||||
|
# check selection on mouse up
|
||||||
|
@selection = @_getSelected()
|
||||||
|
if @selection
|
||||||
|
@selectionLast = @selection
|
||||||
|
)
|
||||||
|
$(el).bind('keyup', (e) =>
|
||||||
|
|
||||||
|
# check selection on sonder key
|
||||||
|
if e.keyCode == 91
|
||||||
|
@selection = @_getSelected()
|
||||||
|
if @selection
|
||||||
|
@selectionLast = @selection
|
||||||
|
|
||||||
|
# check selection of arrow keys
|
||||||
|
if e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40
|
||||||
|
@selection = @_getSelected()
|
||||||
|
if @selection
|
||||||
|
@selectionLast = @selection
|
||||||
|
)
|
||||||
|
|
||||||
|
# get cross browser selected string
|
||||||
|
_getSelected: ->
|
||||||
|
text = '';
|
||||||
|
if window.getSelection
|
||||||
|
text = window.getSelection()
|
||||||
|
else if document.getSelection
|
||||||
|
text = document.getSelection()
|
||||||
|
else if document.selection
|
||||||
|
text = document.selection.createRange().text
|
||||||
|
if text
|
||||||
|
text = text.toString().trim()
|
||||||
|
text
|
||||||
|
|
||||||
|
# get current selection
|
||||||
|
getSelected: ->
|
||||||
|
@selection
|
||||||
|
|
||||||
|
# get latest selection
|
||||||
|
getSelectedLast: ->
|
||||||
|
@selectionLast
|
||||||
|
|
||||||
|
keycode: (code) ->
|
||||||
|
for key, value of @keycodesTable()
|
||||||
|
if value.toString() is code.toString()
|
||||||
|
return key
|
||||||
|
|
||||||
|
keycodesTable: ->
|
||||||
|
map = {
|
||||||
|
'backspace' : 8,
|
||||||
|
'tab' : 9,
|
||||||
|
'enter' : 13,
|
||||||
|
'shift' : 16,
|
||||||
|
'ctrl' : 17,
|
||||||
|
'alt' : 18,
|
||||||
|
'space' : 32,
|
||||||
|
'pause_break' : '19',
|
||||||
|
'caps_lock' : '20',
|
||||||
|
'escape' : '27',
|
||||||
|
'page_up' : '33',
|
||||||
|
'page down' : '34',
|
||||||
|
'end' : '35',
|
||||||
|
'home' : '36',
|
||||||
|
'left_arrow' : '37',
|
||||||
|
'up_arrow' : '38',
|
||||||
|
'right_arrow' : '39',
|
||||||
|
'down_arrow' : '40',
|
||||||
|
'insert' : '45',
|
||||||
|
'delete' : '46',
|
||||||
|
'0' : '48',
|
||||||
|
'1' : '49',
|
||||||
|
'2' : '50',
|
||||||
|
'3' : '51',
|
||||||
|
'4' : '52',
|
||||||
|
'5' : '53',
|
||||||
|
'6' : '54',
|
||||||
|
'7' : '55',
|
||||||
|
'8' : '56',
|
||||||
|
'9' : '57',
|
||||||
|
'a' : '65',
|
||||||
|
'b' : '66',
|
||||||
|
'c' : '67',
|
||||||
|
'd' : '68',
|
||||||
|
'e' : '69',
|
||||||
|
'f' : '70',
|
||||||
|
'g' : '71',
|
||||||
|
'h' : '72',
|
||||||
|
'i' : '73',
|
||||||
|
'j' : '74',
|
||||||
|
'k' : '75',
|
||||||
|
'l' : '76',
|
||||||
|
'm' : '77',
|
||||||
|
'n' : '78',
|
||||||
|
'o' : '79',
|
||||||
|
'p' : '80',
|
||||||
|
'q' : '81',
|
||||||
|
'r' : '82',
|
||||||
|
's' : '83',
|
||||||
|
't' : '84',
|
||||||
|
'u' : '85',
|
||||||
|
'v' : '86',
|
||||||
|
'w' : '87',
|
||||||
|
'x' : '88',
|
||||||
|
'y' : '89',
|
||||||
|
'z' : '90',
|
||||||
|
'left_window key' : '91',
|
||||||
|
'right_window key' : '92',
|
||||||
|
'select_key' : '93',
|
||||||
|
'numpad 0' : '96',
|
||||||
|
'numpad 1' : '97',
|
||||||
|
'numpad 2' : '98',
|
||||||
|
'numpad 3' : '99',
|
||||||
|
'numpad 4' : '100',
|
||||||
|
'numpad 5' : '101',
|
||||||
|
'numpad 6' : '102',
|
||||||
|
'numpad 7' : '103',
|
||||||
|
'numpad 8' : '104',
|
||||||
|
'numpad 9' : '105',
|
||||||
|
'multiply' : '106',
|
||||||
|
'add' : '107',
|
||||||
|
'subtract' : '109',
|
||||||
|
'decimal point' : '110',
|
||||||
|
'divide' : '111',
|
||||||
|
'f1' : '112',
|
||||||
|
'f2' : '113',
|
||||||
|
'f3' : '114',
|
||||||
|
'f4' : '115',
|
||||||
|
'f5' : '116',
|
||||||
|
'f6' : '117',
|
||||||
|
'f7' : '118',
|
||||||
|
'f8' : '119',
|
||||||
|
'f9' : '120',
|
||||||
|
'f10' : '121',
|
||||||
|
'f11' : '122',
|
||||||
|
'f12' : '123',
|
||||||
|
'num_lock' : '144',
|
||||||
|
'scroll_lock' : '145',
|
||||||
|
'semi_colon' : '186',
|
||||||
|
'equal_sign' : '187',
|
||||||
|
'comma' : '188',
|
||||||
|
'dash' : '189',
|
||||||
|
'period' : '190',
|
||||||
|
'forward_slash' : '191',
|
||||||
|
'grave_accent' : '192',
|
||||||
|
'open_bracket' : '219',
|
||||||
|
'backslash' : '220',
|
||||||
|
'closebracket' : '221',
|
||||||
|
'single_quote' : '222'
|
||||||
|
}
|
||||||
|
map
|
363
app/assets/javascripts/app/lib/app/collection.js.coffee
Normal file
363
app/assets/javascripts/app/lib/app/collection.js.coffee
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
class App.Collection
|
||||||
|
_instance = undefined
|
||||||
|
|
||||||
|
@init: ->
|
||||||
|
_instance = new _Singleton
|
||||||
|
|
||||||
|
@load: ( args ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.load( args )
|
||||||
|
|
||||||
|
@reset: ( args ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.reset( args )
|
||||||
|
|
||||||
|
@find: ( type, id, callback, force ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.find( type, id, callback, force )
|
||||||
|
|
||||||
|
@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 )
|
||||||
|
|
||||||
|
@observe: (args) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.observe(args)
|
||||||
|
|
||||||
|
@observeUnbindLevel: (level) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.observeUnbindLevel(level)
|
||||||
|
|
||||||
|
@_observeStats: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance._observeStats()
|
||||||
|
|
||||||
|
class _Singleton
|
||||||
|
|
||||||
|
constructor: (@args) ->
|
||||||
|
|
||||||
|
# add trigger - bind new events
|
||||||
|
App.Event.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] )
|
||||||
|
|
||||||
|
# add trigger - bind new events
|
||||||
|
App.Event.bind 'resetCollection', (data) =>
|
||||||
|
|
||||||
|
# load collections
|
||||||
|
if data.collections
|
||||||
|
for type of data.collections
|
||||||
|
|
||||||
|
console.log 'resetCollection:trigger', type, data.collections[type]
|
||||||
|
@reset( 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 )
|
||||||
|
|
||||||
|
reset: (params) ->
|
||||||
|
console.log( 'reset', params )
|
||||||
|
|
||||||
|
# empty in-memory
|
||||||
|
App[ params.type ].refresh( [], { clear: true } )
|
||||||
|
|
||||||
|
# remove permanent storage
|
||||||
|
list = App.Store.list()
|
||||||
|
for key in list
|
||||||
|
parts = key.split('::')
|
||||||
|
if parts[0] is 'collection' && parts[1] is params.type
|
||||||
|
App.Store.delete(key)
|
||||||
|
|
||||||
|
# load with new data
|
||||||
|
@load(params)
|
||||||
|
|
||||||
|
load: (params) ->
|
||||||
|
console.log( 'load', params )
|
||||||
|
|
||||||
|
return if _.isEmpty( params.data )
|
||||||
|
|
||||||
|
localStorage = params.localStorage
|
||||||
|
|
||||||
|
# load full array once
|
||||||
|
if _.isArray( params.data )
|
||||||
|
# console.log( 'load ARRAY', params.data)
|
||||||
|
App[ params.type ].refresh( params.data )
|
||||||
|
|
||||||
|
# remember in store if not already requested from local storage
|
||||||
|
if !localStorage
|
||||||
|
for object in params.data
|
||||||
|
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, data: [ object ] } )
|
||||||
|
return
|
||||||
|
|
||||||
|
# load data from object
|
||||||
|
# if _.isObject( params.data )
|
||||||
|
for key, object of params.data
|
||||||
|
# console.log( 'load OB', object)
|
||||||
|
App[ params.type ].refresh( object )
|
||||||
|
|
||||||
|
# remember in store if not already requested from local storage
|
||||||
|
if !localStorage
|
||||||
|
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, data: [ object ] } )
|
||||||
|
|
||||||
|
find: ( type, id, callback, force ) ->
|
||||||
|
|
||||||
|
# console.log( 'find', type, id, force )
|
||||||
|
# if App[type].exists( id ) && !callback
|
||||||
|
if !force && App[type].exists( id )
|
||||||
|
# console.log( 'find exists', type, id )
|
||||||
|
data = App[type].find( id )
|
||||||
|
if callback
|
||||||
|
callback( data )
|
||||||
|
else
|
||||||
|
if force
|
||||||
|
console.log( 'find forced to load!', type, id )
|
||||||
|
else
|
||||||
|
console.log( 'find not loaded!', type, id )
|
||||||
|
if callback
|
||||||
|
|
||||||
|
# execute callback if record got loaded
|
||||||
|
App[type].one 'refresh', ->
|
||||||
|
console.log 'loaded..' + type + '..', id
|
||||||
|
|
||||||
|
data = App.Collection.find( type, id )
|
||||||
|
callback( data )
|
||||||
|
|
||||||
|
# fetch object
|
||||||
|
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'
|
||||||
|
|
||||||
|
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: (params) ->
|
||||||
|
all = App[ params.type ].all()
|
||||||
|
all_complied = []
|
||||||
|
for item in all
|
||||||
|
item_new = @find( params.type, item.id )
|
||||||
|
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 )
|
||||||
|
|
||||||
|
if params.order
|
||||||
|
all_complied = @_order( all_complied, params.order )
|
||||||
|
|
||||||
|
return all_complied
|
||||||
|
|
||||||
|
deleteAll: (type) ->
|
||||||
|
App[type].deleteAll()
|
||||||
|
|
||||||
|
findByAttribute: ( type, key, value ) ->
|
||||||
|
App[type].findByAttribute( key, value )
|
||||||
|
|
||||||
|
count: ( type ) ->
|
||||||
|
App[type].count()
|
||||||
|
|
||||||
|
fetch: ( type ) ->
|
||||||
|
App[type].fetch()
|
||||||
|
|
||||||
|
_sortBy: ( collection, attribute ) ->
|
||||||
|
_.sortBy( collection, (item) ->
|
||||||
|
return '' if item[ attribute ] is undefined || item[ attribute ] is null
|
||||||
|
return item[ attribute ].toLowerCase()
|
||||||
|
)
|
||||||
|
|
||||||
|
_order: ( collection, attribute ) ->
|
||||||
|
if attribute is 'DESC'
|
||||||
|
return collection.reverse()
|
||||||
|
return collection
|
||||||
|
|
||||||
|
_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
|
||||||
|
|
||||||
|
observeUnbindLevel: (level) ->
|
||||||
|
return if !@observeCurrent
|
||||||
|
return if !@observeCurrent[level]
|
||||||
|
for observers in @observeCurrent[level]
|
||||||
|
@_observeUnbind( observers )
|
||||||
|
@observeCurrent[level] = []
|
||||||
|
|
||||||
|
observe: (data) ->
|
||||||
|
if !@observeCurrent
|
||||||
|
@observeCurrent = {}
|
||||||
|
|
||||||
|
if !@observeCurrent[ data.level ]
|
||||||
|
@observeCurrent[ data.level ] = []
|
||||||
|
|
||||||
|
@observeCurrent[ data.level ].push data.collections
|
||||||
|
for observe in data.collections
|
||||||
|
events = observe.event.split(' ')
|
||||||
|
for event in events
|
||||||
|
if App[ observe.collection ]
|
||||||
|
App[ observe.collection ].bind( event, observe.callback )
|
||||||
|
|
||||||
|
_observeUnbind: (observers) ->
|
||||||
|
for observe in observers
|
||||||
|
events = observe.event.split(' ')
|
||||||
|
for event in events
|
||||||
|
if App[ observe.collection ]
|
||||||
|
App[ observe.collection ].unbind( event, observe.callback )
|
||||||
|
|
||||||
|
_observeStats: ->
|
||||||
|
@observeCurrent
|
90
app/assets/javascripts/app/lib/app/event.js.coffee
Normal file
90
app/assets/javascripts/app/lib/app/event.js.coffee
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
class App.Event
|
||||||
|
_instance = undefined
|
||||||
|
|
||||||
|
@init: ->
|
||||||
|
_instance = new _Singleton
|
||||||
|
|
||||||
|
@bind: ( events, callback, level ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.bind( events, callback, level )
|
||||||
|
|
||||||
|
@unbind: ( events, callback, level ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.unbind( events, callback, level )
|
||||||
|
|
||||||
|
@trigger: ( events, data ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.trigger( events, data )
|
||||||
|
|
||||||
|
@unbindLevel: (level) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.unbindLevel(level)
|
||||||
|
|
||||||
|
@_allBindings: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance._allBindings()
|
||||||
|
|
||||||
|
class _Singleton
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
@eventCurrent = {}
|
||||||
|
|
||||||
|
unbindLevel: (level) ->
|
||||||
|
return if !@eventCurrent[level]
|
||||||
|
for item in @eventCurrent[level]
|
||||||
|
@unbind( item.event, item.callback, level )
|
||||||
|
@eventCurrent[level] = []
|
||||||
|
|
||||||
|
bind: ( events, callback, level ) ->
|
||||||
|
|
||||||
|
if !level
|
||||||
|
level = '_all'
|
||||||
|
|
||||||
|
if !@eventCurrent[level]
|
||||||
|
@eventCurrent[level] = []
|
||||||
|
|
||||||
|
# level boundary events
|
||||||
|
eventList = events.split(' ')
|
||||||
|
for event in eventList
|
||||||
|
|
||||||
|
# remember all events
|
||||||
|
@eventCurrent[ level ].push {
|
||||||
|
event: event,
|
||||||
|
callback: callback,
|
||||||
|
}
|
||||||
|
|
||||||
|
# bind
|
||||||
|
Spine.bind( event, callback )
|
||||||
|
|
||||||
|
unbind: ( events, callback, level ) ->
|
||||||
|
|
||||||
|
if !level
|
||||||
|
level = '_all'
|
||||||
|
|
||||||
|
if !@eventCurrent[level]
|
||||||
|
@eventCurrent[level] = []
|
||||||
|
|
||||||
|
eventList = events.split(' ')
|
||||||
|
for event in eventList
|
||||||
|
|
||||||
|
# remove from
|
||||||
|
@eventCurrent[level] = _.filter( @eventCurrent[level], (item) ->
|
||||||
|
if callback
|
||||||
|
return item if item.event isnt event && item.callback isnt callback
|
||||||
|
else
|
||||||
|
return item if item.event isnt event
|
||||||
|
)
|
||||||
|
Spine.unbind( event, callback )
|
||||||
|
|
||||||
|
trigger: ( events, data ) ->
|
||||||
|
eventList = events.split(' ')
|
||||||
|
for event in eventList
|
||||||
|
Spine.trigger event, data
|
||||||
|
|
||||||
|
_allBindings: ->
|
||||||
|
@eventCurrent
|
169
app/assets/javascripts/app/lib/app/i18n.js.coffee
Normal file
169
app/assets/javascripts/app/lib/app/i18n.js.coffee
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
$ = jQuery.sub()
|
||||||
|
|
||||||
|
class App.i18n
|
||||||
|
_instance = undefined
|
||||||
|
|
||||||
|
@init: ->
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
|
||||||
|
@translateContent: ( string, args... ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.translate_content( string, args )
|
||||||
|
|
||||||
|
@translateInline: ( string, args... ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.translate_inline( string, args )
|
||||||
|
|
||||||
|
@translateTimestamp: ( args ) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.timestamp( args )
|
||||||
|
|
||||||
|
class _Singleton
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
@locale = 'de'
|
||||||
|
@timestampFormat = 'yyyy-mm-dd HH:MM'
|
||||||
|
@set( @locale )
|
||||||
|
|
||||||
|
# $('.translation [contenteditable]')
|
||||||
|
$('body')
|
||||||
|
.delegate '.translation', 'focus', (e) =>
|
||||||
|
$this = $(e.target)
|
||||||
|
$this.data 'before', $this.html()
|
||||||
|
# console.log('11111current', $this.html())
|
||||||
|
return $this
|
||||||
|
# .delegate '.translation', 'blur keyup paste', (e) =>
|
||||||
|
.delegate '.translation', 'blur', (e) =>
|
||||||
|
$this = $(e.target)
|
||||||
|
source = $this.attr('data-text')
|
||||||
|
|
||||||
|
# get new translation
|
||||||
|
translation_new = $this.html()
|
||||||
|
translation_new = ('' + translation_new)
|
||||||
|
.replace(/<.+?>/g, '')
|
||||||
|
|
||||||
|
# set new translation
|
||||||
|
$this.html(translation_new)
|
||||||
|
|
||||||
|
# update translation
|
||||||
|
return if $this.data('before') is translation_new
|
||||||
|
console.log 'Translation Update', translation_new, $this.data 'before'
|
||||||
|
$this.data 'before', translation_new
|
||||||
|
|
||||||
|
# update runtime translation map
|
||||||
|
@map[ source ] = translation_new
|
||||||
|
|
||||||
|
# replace rest in page
|
||||||
|
$(".translation[data-text='#{source}']").html( translation_new )
|
||||||
|
|
||||||
|
# update permanent translation map
|
||||||
|
translation = App.Collection.findByAttribute( 'Translation', 'source', source )
|
||||||
|
if translation
|
||||||
|
translation.updateAttribute( 'target', translation_new )
|
||||||
|
else
|
||||||
|
translation = new App.Translation
|
||||||
|
translation.load(
|
||||||
|
locale: @locale,
|
||||||
|
source: source,
|
||||||
|
target: translation_new,
|
||||||
|
)
|
||||||
|
translation.save()
|
||||||
|
|
||||||
|
return $this
|
||||||
|
|
||||||
|
set: ( locale ) ->
|
||||||
|
@map = {}
|
||||||
|
App.Com.ajax(
|
||||||
|
id: 'i18n-set-' + locale,
|
||||||
|
type: 'GET',
|
||||||
|
url: '/translations/lang/' + locale,
|
||||||
|
async: false,
|
||||||
|
success: (data, status, xhr) =>
|
||||||
|
|
||||||
|
# set timestamp format
|
||||||
|
if data.timestampFormat
|
||||||
|
@timestampFormat = data.timestampFormat
|
||||||
|
|
||||||
|
# load translation collection
|
||||||
|
for object in data.list
|
||||||
|
|
||||||
|
# set runtime lookup table
|
||||||
|
@map[ object[1] ] = object[2]
|
||||||
|
|
||||||
|
# load in collection if needed
|
||||||
|
App.Translation.refresh( { id: object[0], source: object[1], target: object[2], locale: @locale } )
|
||||||
|
|
||||||
|
error: (xhr, statusText, error) =>
|
||||||
|
console.log 'error', error, statusText, xhr.statusCode
|
||||||
|
)
|
||||||
|
|
||||||
|
translate_inline: ( string, args... ) =>
|
||||||
|
@translate( string, args... )
|
||||||
|
|
||||||
|
translate_content: ( string, args... ) =>
|
||||||
|
translated = @translate( string, args... )
|
||||||
|
# replace = '<span class="translation" contenteditable="true" data-text="' + @escape(string) + '">' + translated + '<span class="icon-edit"></span>'
|
||||||
|
if window.Config['Translation']
|
||||||
|
replace = '<span class="translation" contenteditable="true" data-text="' + @escape(string) + '">' + translated + ''
|
||||||
|
# if !@_translated
|
||||||
|
# replace += '<span class="missing">XX</span>'
|
||||||
|
replace += '</span>'
|
||||||
|
else
|
||||||
|
translated
|
||||||
|
|
||||||
|
translate: ( string, args... ) =>
|
||||||
|
|
||||||
|
# return '' on undefined
|
||||||
|
return '' if string is undefined
|
||||||
|
|
||||||
|
# return translation
|
||||||
|
if @map[string] isnt undefined
|
||||||
|
@_translated = true
|
||||||
|
translated = @map[string]
|
||||||
|
else
|
||||||
|
@_translated = false
|
||||||
|
translated = string
|
||||||
|
|
||||||
|
# search %s
|
||||||
|
for arg in args
|
||||||
|
translated = translated.replace(/%s/, arg)
|
||||||
|
|
||||||
|
# escape
|
||||||
|
translated = @escape(translated)
|
||||||
|
|
||||||
|
# return translated string
|
||||||
|
return translated
|
||||||
|
|
||||||
|
escape: ( string ) ->
|
||||||
|
string = ( '' + string )
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/\x22/g, '"')
|
||||||
|
|
||||||
|
timestamp: ( time ) =>
|
||||||
|
s = ( num, digits ) ->
|
||||||
|
while num.toString().length < digits
|
||||||
|
num = "0" + num
|
||||||
|
return num
|
||||||
|
|
||||||
|
timeObject = new Date(time)
|
||||||
|
d = timeObject.getDate()
|
||||||
|
m = timeObject.getMonth() + 1
|
||||||
|
y = timeObject.getFullYear()
|
||||||
|
S = timeObject.getSeconds()
|
||||||
|
M = timeObject.getMinutes()
|
||||||
|
H = timeObject.getHours()
|
||||||
|
format = @timestampFormat
|
||||||
|
format = format.replace /dd/, s( d, 2 )
|
||||||
|
format = format.replace /d/, d
|
||||||
|
format = format.replace /mm/, s( m, 2 )
|
||||||
|
format = format.replace /m/, m
|
||||||
|
format = format.replace /yyyy/, y
|
||||||
|
format = format.replace /SS/, s( S, 2 )
|
||||||
|
format = format.replace /MM/, s( M, 2 )
|
||||||
|
format = format.replace /HH/, s( H, 2 )
|
||||||
|
return format
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
class App.Run extends App.Controller
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
@log 'RUN app'
|
||||||
|
@el = $('#app')
|
||||||
|
|
||||||
|
# init collections
|
||||||
|
App.Collection.init()
|
||||||
|
|
||||||
|
# create web socket connection
|
||||||
|
App.WebSocket.connect()
|
||||||
|
|
||||||
|
# init of i18n
|
||||||
|
App.i18n.init()
|
||||||
|
|
||||||
|
# start navigation controller
|
||||||
|
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') )
|
||||||
|
|
||||||
|
# start content
|
||||||
|
new App.Content( el: @el.find('#content') )
|
||||||
|
|
||||||
|
# bind to fill selected text into
|
||||||
|
App.ClipBoard.bind( @el )
|
||||||
|
|
||||||
|
class App.Content extends Spine.Controller
|
||||||
|
className: 'container'
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
super
|
||||||
|
@log 'RUN content'
|
||||||
|
|
||||||
|
for route, callback of Config.Routes
|
||||||
|
do (route, callback) =>
|
||||||
|
@route(route, (params) ->
|
||||||
|
|
||||||
|
# remove observers for page
|
||||||
|
App.Collection.observeUnbindLevel('page')
|
||||||
|
|
||||||
|
# remove events for page
|
||||||
|
App.Event.unbindLevel('page')
|
||||||
|
|
||||||
|
# unbind in controller area
|
||||||
|
@el.unbind()
|
||||||
|
@el.undelegate()
|
||||||
|
|
||||||
|
# send current controller
|
||||||
|
params_only = {}
|
||||||
|
for i of params
|
||||||
|
if typeof params[i] isnt 'object'
|
||||||
|
params_only[i] = params[i]
|
||||||
|
|
||||||
|
# tell server what we are calling right now
|
||||||
|
App.WebSocket.send(
|
||||||
|
action: 'active_controller',
|
||||||
|
controller: route,
|
||||||
|
params: params_only,
|
||||||
|
)
|
||||||
|
|
||||||
|
# remove waypoints
|
||||||
|
$('footer').waypoint('remove')
|
||||||
|
|
||||||
|
params.el = @el
|
||||||
|
new callback( params )
|
||||||
|
|
||||||
|
# scroll to top
|
||||||
|
# window.scrollTo(0,0)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spine.Route.setup()
|
61
app/assets/javascripts/app/lib/app/store.js.coffee
Normal file
61
app/assets/javascripts/app/lib/app/store.js.coffee
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
class App.Store
|
||||||
|
_instance = undefined # Must be declared here to force the closure on the class
|
||||||
|
@renew: ->
|
||||||
|
_instance = new _Singleton
|
||||||
|
|
||||||
|
@write: (key, value) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.write(key, value)
|
||||||
|
|
||||||
|
@get: (args) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.get(args)
|
||||||
|
|
||||||
|
@delete: (args) ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.delete(args)
|
||||||
|
|
||||||
|
@clear: ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.clear()
|
||||||
|
|
||||||
|
@list: () ->
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance.list()
|
||||||
|
|
||||||
|
# The actual Singleton class
|
||||||
|
class _Singleton
|
||||||
|
|
||||||
|
# write to local storage
|
||||||
|
write: (key, value) ->
|
||||||
|
localStorage.setItem( key, JSON.stringify( value ) )
|
||||||
|
|
||||||
|
# get item
|
||||||
|
get: (key) ->
|
||||||
|
value = localStorage.getItem( key )
|
||||||
|
return if !value
|
||||||
|
object = JSON.parse( value )
|
||||||
|
return object
|
||||||
|
|
||||||
|
# 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
|
||||||
|
list.push key
|
||||||
|
list
|
163
app/assets/javascripts/app/lib/app/websocket.js.coffee
Normal file
163
app/assets/javascripts/app/lib/app/websocket.js.coffee
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
$ = jQuery.sub()
|
||||||
|
|
||||||
|
class App.WebSocket
|
||||||
|
_instance = undefined # Must be declared here to force the closure on the class
|
||||||
|
@connect: (args) -> # Must be a static method
|
||||||
|
if _instance == undefined
|
||||||
|
_instance ?= new _Singleton
|
||||||
|
_instance
|
||||||
|
|
||||||
|
@close: (args) -> # Must be a static method
|
||||||
|
if _instance isnt undefined
|
||||||
|
_instance.close()
|
||||||
|
|
||||||
|
@send: (args) -> # Must be a static method
|
||||||
|
@connect()
|
||||||
|
_instance.send(args)
|
||||||
|
|
||||||
|
@auth: (args) -> # Must be a static method
|
||||||
|
@connect()
|
||||||
|
_instance.auth(args)
|
||||||
|
|
||||||
|
# The actual Singleton class
|
||||||
|
class _Singleton extends App.Controller
|
||||||
|
queue: []
|
||||||
|
supported: true
|
||||||
|
|
||||||
|
constructor: (@args) ->
|
||||||
|
@connect()
|
||||||
|
|
||||||
|
send: (data) =>
|
||||||
|
return if !@supported
|
||||||
|
# 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 1 indicates that the connection is established and communication is possible.
|
||||||
|
# A value of 2 indicates that the connection is going through the closing handshake.
|
||||||
|
# A value of 3 indicates that the connection has been closed or could not be opened.
|
||||||
|
if @ws.readyState is 0
|
||||||
|
@queue.push data
|
||||||
|
else
|
||||||
|
# console.log( 'ws:send', data )
|
||||||
|
string = JSON.stringify( data )
|
||||||
|
@ws.send(string)
|
||||||
|
|
||||||
|
auth: (data) =>
|
||||||
|
return if !@supported
|
||||||
|
|
||||||
|
# logon websocket
|
||||||
|
data = {
|
||||||
|
action: 'login',
|
||||||
|
session: window.Session
|
||||||
|
}
|
||||||
|
@send(data)
|
||||||
|
|
||||||
|
close: =>
|
||||||
|
return if !@supported
|
||||||
|
|
||||||
|
@ws.close()
|
||||||
|
|
||||||
|
ping: =>
|
||||||
|
return if !@supported
|
||||||
|
|
||||||
|
# console.log 'send websockend ping'
|
||||||
|
@send( { action: 'ping' } )
|
||||||
|
|
||||||
|
# check if ping is back within 2 min
|
||||||
|
@clearDelay('websocket-ping-check')
|
||||||
|
check = =>
|
||||||
|
console.log 'no websockend ping response, reconnect...'
|
||||||
|
@close()
|
||||||
|
@delay check, 120000, 'websocket-ping-check'
|
||||||
|
|
||||||
|
pong: ->
|
||||||
|
return if !@supported
|
||||||
|
# console.log 'received websockend ping'
|
||||||
|
|
||||||
|
# test again after 1 min
|
||||||
|
@delay @ping, 60000
|
||||||
|
|
||||||
|
connect: =>
|
||||||
|
# console.log '------------ws connect....--------------'
|
||||||
|
|
||||||
|
if !window.WebSocket
|
||||||
|
@error = new App.ErrorModal(
|
||||||
|
message: 'Sorry, no websocket support!'
|
||||||
|
)
|
||||||
|
@supported = false
|
||||||
|
return
|
||||||
|
|
||||||
|
protocol = 'ws://'
|
||||||
|
if window.location.protocol is 'https:'
|
||||||
|
protocol = 'wss://'
|
||||||
|
|
||||||
|
@ws = new window.WebSocket( protocol + window.location.hostname + ":6042/" )
|
||||||
|
|
||||||
|
# Set event handlers.
|
||||||
|
@ws.onopen = =>
|
||||||
|
console.log( 'onopen' )
|
||||||
|
|
||||||
|
# close error message show up (because try so connect again) if exists
|
||||||
|
@clearDelay('websocket-no-connection-try-reconnect')
|
||||||
|
if @error
|
||||||
|
@error.modalHide()
|
||||||
|
@error = undefined
|
||||||
|
|
||||||
|
@auth()
|
||||||
|
|
||||||
|
# empty queue
|
||||||
|
for item in @queue
|
||||||
|
# console.log( 'ws:send queue', item )
|
||||||
|
@send(item)
|
||||||
|
@queue = []
|
||||||
|
|
||||||
|
# send ping to check connection
|
||||||
|
@delay @ping, 60000
|
||||||
|
|
||||||
|
@ws.onmessage = (e) =>
|
||||||
|
pipe = JSON.parse( e.data )
|
||||||
|
console.log( 'ws:onmessage', pipe )
|
||||||
|
|
||||||
|
# go through all blocks
|
||||||
|
for item in pipe
|
||||||
|
|
||||||
|
# reset reconnect loop
|
||||||
|
if item['action'] is 'pong'
|
||||||
|
@pong()
|
||||||
|
|
||||||
|
# fill collection
|
||||||
|
if item['collection']
|
||||||
|
console.log( "ws:onmessage collection:" + item['collection'] )
|
||||||
|
App.Store.write( item['collection'], item['data'] )
|
||||||
|
|
||||||
|
# fire event
|
||||||
|
if item['event']
|
||||||
|
if typeof item['event'] is 'object'
|
||||||
|
for event in item['event']
|
||||||
|
console.log( "ws:onmessage event:" + event )
|
||||||
|
App.Event.trigger( event, item['data'] )
|
||||||
|
else
|
||||||
|
console.log( "ws:onmessage event:" + item['event'] )
|
||||||
|
App.Event.trigger( item['event'], item['data'] )
|
||||||
|
|
||||||
|
# bind to send messages
|
||||||
|
App.Event.bind 'ws:send', (data) =>
|
||||||
|
@send(data)
|
||||||
|
|
||||||
|
@ws.onclose = (e) =>
|
||||||
|
console.log( 'onclose', e )
|
||||||
|
|
||||||
|
# show error message, first try to reconnect
|
||||||
|
if !@error
|
||||||
|
message = =>
|
||||||
|
@error = new App.ErrorModal(
|
||||||
|
message: 'No connection to websocket, trying to reconnect...'
|
||||||
|
)
|
||||||
|
@delay message, 7000, 'websocket-no-connection-try-reconnect'
|
||||||
|
|
||||||
|
# try reconnect after 4.5 sec.
|
||||||
|
@delay @connect, 4500
|
||||||
|
|
||||||
|
@ws.onerror = ->
|
||||||
|
console.log( 'onerror' )
|
||||||
|
|
179
app/assets/javascripts/app/lib/base/ba-linkify.js
Normal file
179
app/assets/javascripts/app/lib/base/ba-linkify.js
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/*!
|
||||||
|
* linkify - v0.3 - 6/27/2009
|
||||||
|
* http://benalman.com/code/test/js-linkify/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009 "Cowboy" Ben Alman
|
||||||
|
* Licensed under the MIT license
|
||||||
|
* http://benalman.com/about/license/
|
||||||
|
*
|
||||||
|
* Some regexps adapted from http://userscripts.org/scripts/review/7122
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Turn text into linkified html.
|
||||||
|
//
|
||||||
|
// var html = linkify( text, options );
|
||||||
|
//
|
||||||
|
// options:
|
||||||
|
//
|
||||||
|
// callback (Function) - default: undefined - if defined, this will be called
|
||||||
|
// for each link- or non-link-chunk with two arguments, text and href. If the
|
||||||
|
// chunk is non-link, href will be omitted.
|
||||||
|
//
|
||||||
|
// punct_regexp (RegExp | Boolean) - a RegExp that can be used to trim trailing
|
||||||
|
// punctuation from links, instead of the default.
|
||||||
|
//
|
||||||
|
// This is a work in progress, please let me know if (and how) it fails!
|
||||||
|
|
||||||
|
window.linkify = (function(){
|
||||||
|
var
|
||||||
|
SCHEME = "[a-z\\d.-]+://",
|
||||||
|
IPV4 = "(?:(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.){3}(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])",
|
||||||
|
HOSTNAME = "(?:(?:[^\\s!@#$%^&*()_=+[\\]{}\\\\|;:'\",.<>/?]+)\\.)+",
|
||||||
|
TLD = "(?:ac|ad|aero|ae|af|ag|ai|al|am|an|ao|aq|arpa|ar|asia|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|biz|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|cat|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|coop|com|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|info|int|in|io|iq|ir|is|it|je|jm|jobs|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mobi|mo|mp|mq|mr|ms|mt|museum|mu|mv|mw|mx|my|mz|name|na|nc|net|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pro|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tl|tm|tn|to|tp|travel|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g|xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp|xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw)",
|
||||||
|
HOST_OR_IP = "(?:" + HOSTNAME + TLD + "|" + IPV4 + ")",
|
||||||
|
PATH = "(?:[;/][^#?<>\\s]*)?",
|
||||||
|
QUERY_FRAG = "(?:\\?[^#<>\\s]*)?(?:#[^<>\\s]*)?",
|
||||||
|
URI1 = "\\b" + SCHEME + "[^<>\\s]+",
|
||||||
|
URI2 = "\\b" + HOST_OR_IP + PATH + QUERY_FRAG + "(?!\\w)",
|
||||||
|
|
||||||
|
MAILTO = "mailto:",
|
||||||
|
EMAIL = "(?:" + MAILTO + ")?[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" + HOST_OR_IP + QUERY_FRAG + "(?!\\w)",
|
||||||
|
|
||||||
|
URI_RE = new RegExp( "(?:" + URI1 + "|" + URI2 + "|" + EMAIL + ")", "ig" ),
|
||||||
|
SCHEME_RE = new RegExp( "^" + SCHEME, "i" ),
|
||||||
|
|
||||||
|
quotes = {
|
||||||
|
"'": "`",
|
||||||
|
'>': '<',
|
||||||
|
')': '(',
|
||||||
|
']': '[',
|
||||||
|
'}': '{',
|
||||||
|
'»': '«',
|
||||||
|
'›': '‹'
|
||||||
|
},
|
||||||
|
|
||||||
|
default_options = {
|
||||||
|
callback: function( text, href ) {
|
||||||
|
// return href ? '<a href="' + href + '" title="' + href + '">' + text + '<\/a>' : text;
|
||||||
|
return href ? '<a href="' + href + '" title="' + href + '" target="_blank">' + text + '<\/a>' : text;
|
||||||
|
},
|
||||||
|
punct_regexp: /(?:[!?.,:;'"]|(?:&|&)(?:lt|gt|quot|apos|raquo|laquo|rsaquo|lsaquo);)$/
|
||||||
|
};
|
||||||
|
|
||||||
|
return function( txt, options ) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// me
|
||||||
|
txt = txt
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
// me
|
||||||
|
// Temp variables.
|
||||||
|
var arr,
|
||||||
|
i,
|
||||||
|
link,
|
||||||
|
href,
|
||||||
|
|
||||||
|
// Output HTML.
|
||||||
|
html = '',
|
||||||
|
|
||||||
|
// Store text / link parts, in order, for re-combination.
|
||||||
|
parts = [],
|
||||||
|
|
||||||
|
// Used for keeping track of indices in the text.
|
||||||
|
idx_prev,
|
||||||
|
idx_last,
|
||||||
|
idx,
|
||||||
|
link_last,
|
||||||
|
|
||||||
|
// Used for trimming trailing punctuation and quotes from links.
|
||||||
|
matches_begin,
|
||||||
|
matches_end,
|
||||||
|
quote_begin,
|
||||||
|
quote_end;
|
||||||
|
|
||||||
|
// Initialize options.
|
||||||
|
for ( i in default_options ) {
|
||||||
|
if ( options[ i ] === undefined ) {
|
||||||
|
options[ i ] = default_options[ i ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find links.
|
||||||
|
while ( arr = URI_RE.exec( txt ) ) {
|
||||||
|
|
||||||
|
link = arr[0];
|
||||||
|
idx_last = URI_RE.lastIndex;
|
||||||
|
idx = idx_last - link.length;
|
||||||
|
|
||||||
|
// Not a link if preceded by certain characters.
|
||||||
|
if ( /[\/:]/.test( txt.charAt( idx - 1 ) ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim trailing punctuation.
|
||||||
|
do {
|
||||||
|
// If no changes are made, we don't want to loop forever!
|
||||||
|
link_last = link;
|
||||||
|
|
||||||
|
quote_end = link.substr( -1 )
|
||||||
|
quote_begin = quotes[ quote_end ];
|
||||||
|
|
||||||
|
// Ending quote character?
|
||||||
|
if ( quote_begin ) {
|
||||||
|
matches_begin = link.match( new RegExp( '\\' + quote_begin + '(?!$)', 'g' ) );
|
||||||
|
matches_end = link.match( new RegExp( '\\' + quote_end, 'g' ) );
|
||||||
|
|
||||||
|
// If quotes are unbalanced, remove trailing quote character.
|
||||||
|
if ( ( matches_begin ? matches_begin.length : 0 ) < ( matches_end ? matches_end.length : 0 ) ) {
|
||||||
|
link = link.substr( 0, link.length - 1 );
|
||||||
|
idx_last--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ending non-quote punctuation character?
|
||||||
|
if ( options.punct_regexp ) {
|
||||||
|
link = link.replace( options.punct_regexp, function(a){
|
||||||
|
idx_last -= a.length;
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} while ( link.length && link !== link_last );
|
||||||
|
|
||||||
|
href = link;
|
||||||
|
|
||||||
|
// Add appropriate protocol to naked links.
|
||||||
|
if ( !SCHEME_RE.test( href ) ) {
|
||||||
|
href = ( href.indexOf( '@' ) !== -1 ? ( !href.indexOf( MAILTO ) ? '' : MAILTO )
|
||||||
|
: !href.indexOf( 'irc.' ) ? 'irc://'
|
||||||
|
: !href.indexOf( 'ftp.' ) ? 'ftp://'
|
||||||
|
: 'http://' )
|
||||||
|
+ href;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push preceding non-link text onto the array.
|
||||||
|
if ( idx_prev != idx ) {
|
||||||
|
parts.push([ txt.slice( idx_prev, idx ) ]);
|
||||||
|
idx_prev = idx_last;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push massaged link onto the array
|
||||||
|
parts.push([ link, href ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Push remaining non-link text onto the array.
|
||||||
|
parts.push([ txt.substr( idx_prev ) ]);
|
||||||
|
|
||||||
|
// Process the array items.
|
||||||
|
for ( i = 0; i < parts.length; i++ ) {
|
||||||
|
html += options.callback.apply( window, parts[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case of catastrophic failure, return the original text;
|
||||||
|
return html || txt;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
1251
app/assets/javascripts/app/lib/base/fileuploader.js
Normal file
1251
app/assets/javascripts/app/lib/base/fileuploader.js
Normal file
File diff suppressed because it is too large
Load diff
162
app/assets/javascripts/app/lib/base/jquery.elastic.source.js
Normal file
162
app/assets/javascripts/app/lib/base/jquery.elastic.source.js
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/**
|
||||||
|
* @name Elastic
|
||||||
|
* @descripton Elastic is jQuery plugin that grow and shrink your textareas automatically
|
||||||
|
* @version 1.6.11
|
||||||
|
* @requires jQuery 1.2.6+
|
||||||
|
*
|
||||||
|
* @author Jan Jarfalk
|
||||||
|
* @author-email jan.jarfalk@unwrongest.com
|
||||||
|
* @author-website http://www.unwrongest.com
|
||||||
|
*
|
||||||
|
* @licence MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($){
|
||||||
|
jQuery.fn.extend({
|
||||||
|
elastic: function() {
|
||||||
|
|
||||||
|
// We will create a div clone of the textarea
|
||||||
|
// by copying these attributes from the textarea to the div.
|
||||||
|
var mimics = [
|
||||||
|
'paddingTop',
|
||||||
|
'paddingRight',
|
||||||
|
'paddingBottom',
|
||||||
|
'paddingLeft',
|
||||||
|
'fontSize',
|
||||||
|
'lineHeight',
|
||||||
|
'fontFamily',
|
||||||
|
'width',
|
||||||
|
'fontWeight',
|
||||||
|
'border-top-width',
|
||||||
|
'border-right-width',
|
||||||
|
'border-bottom-width',
|
||||||
|
'border-left-width',
|
||||||
|
'borderTopStyle',
|
||||||
|
'borderTopColor',
|
||||||
|
'borderRightStyle',
|
||||||
|
'borderRightColor',
|
||||||
|
'borderBottomStyle',
|
||||||
|
'borderBottomColor',
|
||||||
|
'borderLeftStyle',
|
||||||
|
'borderLeftColor'
|
||||||
|
];
|
||||||
|
|
||||||
|
return this.each( function() {
|
||||||
|
|
||||||
|
// Elastic only works on textareas
|
||||||
|
if ( this.type !== 'textarea' ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $textarea = jQuery(this),
|
||||||
|
$twin = jQuery('<div />').css({
|
||||||
|
'position' : 'absolute',
|
||||||
|
'display' : 'none',
|
||||||
|
'word-wrap' : 'break-word',
|
||||||
|
'white-space' :'pre-wrap'
|
||||||
|
}),
|
||||||
|
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
|
||||||
|
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
|
||||||
|
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
|
||||||
|
goalheight = 0;
|
||||||
|
|
||||||
|
// Opera returns max-height of -1 if not set
|
||||||
|
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
|
||||||
|
|
||||||
|
// Append the twin to the DOM
|
||||||
|
// We are going to meassure the height of this, not the textarea.
|
||||||
|
$twin.appendTo($textarea.parent());
|
||||||
|
|
||||||
|
// Copy the essential styles (mimics) from the textarea to the twin
|
||||||
|
var i = mimics.length;
|
||||||
|
while(i--){
|
||||||
|
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the width of the twin. (solution for textareas with widths in percent)
|
||||||
|
function setTwinWidth(){
|
||||||
|
var curatedWidth = Math.floor(parseInt($textarea.width(),10));
|
||||||
|
if($twin.width() !== curatedWidth){
|
||||||
|
$twin.css({'width': curatedWidth + 'px'});
|
||||||
|
|
||||||
|
// Update height of textarea
|
||||||
|
update(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets a given height and overflow state on the textarea
|
||||||
|
function setHeightAndOverflow(height, overflow){
|
||||||
|
|
||||||
|
var curratedHeight = Math.floor(parseInt(height,10));
|
||||||
|
if($textarea.height() !== curratedHeight){
|
||||||
|
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will update the height of the textarea if necessary
|
||||||
|
function update(forced) {
|
||||||
|
|
||||||
|
// Get curated content from the textarea.
|
||||||
|
var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ {2}/g, ' ').replace(/<|>/g, '>').replace(/\n/g, '<br />');
|
||||||
|
|
||||||
|
// Compare curated content with curated twin.
|
||||||
|
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
|
||||||
|
|
||||||
|
if(forced || textareaContent+' ' !== twinContent){
|
||||||
|
|
||||||
|
// Add an extra white space so new rows are added when you are at the end of a row.
|
||||||
|
$twin.html(textareaContent+' ');
|
||||||
|
|
||||||
|
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
|
||||||
|
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
|
||||||
|
|
||||||
|
var goalheight = $twin.height()+lineHeight;
|
||||||
|
if(goalheight >= maxheight) {
|
||||||
|
setHeightAndOverflow(maxheight,'auto');
|
||||||
|
} else if(goalheight <= minheight) {
|
||||||
|
setHeightAndOverflow(minheight,'hidden');
|
||||||
|
} else {
|
||||||
|
setHeightAndOverflow(goalheight,'hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide scrollbars
|
||||||
|
$textarea.css({'overflow':'hidden'});
|
||||||
|
|
||||||
|
// Update textarea size on keyup, change, cut and paste
|
||||||
|
$textarea.bind('keyup change cut paste', function(){
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
|
||||||
|
$(window).bind('resize', setTwinWidth);
|
||||||
|
$textarea.bind('resize', setTwinWidth);
|
||||||
|
$textarea.bind('update', update);
|
||||||
|
|
||||||
|
// Compact textarea on blur
|
||||||
|
$textarea.bind('blur',function(){
|
||||||
|
if($twin.height() < maxheight){
|
||||||
|
if($twin.height() > minheight) {
|
||||||
|
$textarea.height($twin.height());
|
||||||
|
} else {
|
||||||
|
$textarea.height(minheight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// And this line is to catch the browser paste event
|
||||||
|
$textarea.bind('input paste',function(e){ setTimeout( update, 250); });
|
||||||
|
|
||||||
|
// Run update once when elastic is initialized
|
||||||
|
update();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(jQuery);
|
220
app/assets/javascripts/app/lib/base/jquery.noty.js
Normal file
220
app/assets/javascripts/app/lib/base/jquery.noty.js
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
/**
|
||||||
|
* jQuery Noty Plugin v1.1.1
|
||||||
|
* Authors: Nedim Arabacı (http://ned.im), Muhittin Özer (http://muhittinozer.com)
|
||||||
|
*
|
||||||
|
* Examples and Documentation - http://needim.github.com/noty/
|
||||||
|
*
|
||||||
|
* Licensed under the MIT licenses:
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
(function($) {
|
||||||
|
$.noty = function(options, customContainer) {
|
||||||
|
|
||||||
|
var base = this;
|
||||||
|
var $noty = null;
|
||||||
|
var isCustom = false;
|
||||||
|
|
||||||
|
base.init = function(options) {
|
||||||
|
base.options = $.extend({}, $.noty.defaultOptions, options);
|
||||||
|
base.options.type = base.options.cssPrefix+base.options.type;
|
||||||
|
base.options.id = base.options.type+'_'+new Date().getTime();
|
||||||
|
base.options.layout = base.options.cssPrefix+'layout_'+base.options.layout;
|
||||||
|
|
||||||
|
if (base.options.custom.container) customContainer = base.options.custom.container;
|
||||||
|
isCustom = ($.type(customContainer) === 'object') ? true : false;
|
||||||
|
|
||||||
|
return base.addQueue();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Push notification to queue
|
||||||
|
base.addQueue = function() {
|
||||||
|
var isGrowl = ($.inArray(base.options.layout, $.noty.growls) == -1) ? false : true;
|
||||||
|
if (!isGrowl) (base.options.force) ? $.noty.queue.unshift({options: base.options}) : $.noty.queue.push({options: base.options});
|
||||||
|
return base.render(isGrowl);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render the noty
|
||||||
|
base.render = function(isGrowl) {
|
||||||
|
|
||||||
|
// Layout spesific container settings
|
||||||
|
var container = (isCustom) ? customContainer.addClass(base.options.theme+' '+base.options.layout+' noty_custom_container') : $('body');
|
||||||
|
if (isGrowl) {
|
||||||
|
if ($('ul.noty_cont.' + base.options.layout).length == 0)
|
||||||
|
container.prepend($('<ul/>').addClass('noty_cont ' + base.options.layout));
|
||||||
|
container = $('ul.noty_cont.' + base.options.layout);
|
||||||
|
} else {
|
||||||
|
if ($.noty.available) {
|
||||||
|
var fromQueue = $.noty.queue.shift(); // Get noty from queue
|
||||||
|
if ($.type(fromQueue) === 'object') {
|
||||||
|
$.noty.available = false;
|
||||||
|
base.options = fromQueue.options;
|
||||||
|
} else {
|
||||||
|
$.noty.available = true; // Queue is over
|
||||||
|
return base.options.id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return base.options.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base.container = container;
|
||||||
|
|
||||||
|
// Generating noty bar
|
||||||
|
base.bar = $('<div class="noty_bar"/>').attr('id', base.options.id).addClass(base.options.theme+' '+base.options.layout+' '+base.options.type);
|
||||||
|
$noty = base.bar;
|
||||||
|
$noty.append(base.options.template).find('.noty_text').html(base.options.text);
|
||||||
|
$noty.data('noty_options', base.options);
|
||||||
|
|
||||||
|
// Close button display
|
||||||
|
(base.options.closeButton) ? $noty.addClass('noty_closable').find('.noty_close').show() : $noty.find('.noty_close').remove();
|
||||||
|
|
||||||
|
// Bind close event to button
|
||||||
|
$noty.find('.noty_close').bind('click', function() { $noty.trigger('noty.close'); });
|
||||||
|
|
||||||
|
// If we have a button we must disable closeOnSelfClick and closeOnSelfOver option
|
||||||
|
if (base.options.buttons) base.options.closeOnSelfClick = base.options.closeOnSelfOver = false;
|
||||||
|
// Close on self click
|
||||||
|
if (base.options.closeOnSelfClick) $noty.bind('click', function() { $noty.trigger('noty.close'); }).css('cursor', 'pointer');
|
||||||
|
// Close on self mouseover
|
||||||
|
if (base.options.closeOnSelfOver) $noty.bind('mouseover', function() { $noty.trigger('noty.close'); }).css('cursor', 'pointer');
|
||||||
|
|
||||||
|
// Set buttons if available
|
||||||
|
if (base.options.buttons) {
|
||||||
|
$buttons = $('<div/>').addClass('noty_buttons');
|
||||||
|
$noty.find('.noty_message').append($buttons);
|
||||||
|
$.each(base.options.buttons, function(i, button) {
|
||||||
|
bclass = (button.type) ? button.type : 'gray';
|
||||||
|
$button = $('<button/>').addClass(bclass).html(button.text).appendTo($noty.find('.noty_buttons'))
|
||||||
|
.bind('click', function() {
|
||||||
|
if ($.isFunction(button.click)) {
|
||||||
|
button.click.call($button, $noty);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.show(isGrowl);
|
||||||
|
};
|
||||||
|
|
||||||
|
base.show = function(isGrowl) {
|
||||||
|
|
||||||
|
// is Modal?
|
||||||
|
if (base.options.modal) $('<div/>').addClass('noty_modal').addClass(base.options.theme).prependTo($('body')).fadeIn('fast');
|
||||||
|
|
||||||
|
$noty.close = function() { return this.trigger('noty.close'); };
|
||||||
|
|
||||||
|
// Prepend noty to container
|
||||||
|
(isGrowl) ? base.container.prepend($('<li/>').append($noty)) : base.container.prepend($noty);
|
||||||
|
|
||||||
|
// topCenter and center specific options
|
||||||
|
if (base.options.layout == 'noty_layout_topCenter' || base.options.layout == 'noty_layout_center') {
|
||||||
|
$.noty.reCenter($noty);
|
||||||
|
}
|
||||||
|
|
||||||
|
$noty.bind('noty.setText', function(event, text) {
|
||||||
|
$noty.find('.noty_text').html(text); $.noty.reCenter($noty);
|
||||||
|
});
|
||||||
|
|
||||||
|
$noty.bind('noty.getId', function(event) {
|
||||||
|
return $noty.data('noty_options').id;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind close event
|
||||||
|
$noty.one('noty.close', function(event) {
|
||||||
|
var options = $noty.data('noty_options');
|
||||||
|
|
||||||
|
// Modal Cleaning
|
||||||
|
if (options.modal) $('.noty_modal').fadeOut('fast', function() { $(this).remove(); });
|
||||||
|
|
||||||
|
$noty.clearQueue().stop().animate(
|
||||||
|
$noty.data('noty_options').animateClose,
|
||||||
|
$noty.data('noty_options').speed,
|
||||||
|
$noty.data('noty_options').easing,
|
||||||
|
$noty.data('noty_options').onClose)
|
||||||
|
.promise().done(function() {
|
||||||
|
|
||||||
|
// Layout spesific cleaning
|
||||||
|
if ($.inArray($noty.data('noty_options').layout, $.noty.growls) > -1) {
|
||||||
|
$noty.parent().remove();
|
||||||
|
} else {
|
||||||
|
$noty.remove();
|
||||||
|
|
||||||
|
// queue render
|
||||||
|
$.noty.available = true;
|
||||||
|
base.render(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the show
|
||||||
|
$noty.animate(base.options.animateOpen, base.options.speed, base.options.easing, base.options.onShow);
|
||||||
|
|
||||||
|
// If noty is have a timeout option
|
||||||
|
if (base.options.timeout) $noty.delay(base.options.timeout).promise().done(function() { $noty.trigger('noty.close'); });
|
||||||
|
return base.options.id;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run initializer
|
||||||
|
return base.init(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
// API
|
||||||
|
$.noty.get = function(id) { return $('#'+id); };
|
||||||
|
$.noty.close = function(id) {
|
||||||
|
$.noty.get(id).trigger('noty.close');
|
||||||
|
};
|
||||||
|
$.noty.setText = function(id, text) {
|
||||||
|
$.noty.get(id).trigger('noty.setText', text);
|
||||||
|
};
|
||||||
|
$.noty.closeAll = function() {
|
||||||
|
$.noty.clearQueue();
|
||||||
|
$('.noty_bar').trigger('noty.close');
|
||||||
|
};
|
||||||
|
$.noty.reCenter = function(noty) {
|
||||||
|
noty.css({'left': ($(window).width() - noty.outerWidth()) / 2 + 'px'});
|
||||||
|
};
|
||||||
|
$.noty.clearQueue = function() {
|
||||||
|
$.noty.queue = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
$.noty.queue = [];
|
||||||
|
$.noty.growls = ['noty_layout_topLeft', 'noty_layout_topRight', 'noty_layout_bottomLeft', 'noty_layout_bottomRight'];
|
||||||
|
$.noty.available = true;
|
||||||
|
$.noty.defaultOptions = {
|
||||||
|
layout: 'top',
|
||||||
|
theme: 'noty_theme_default',
|
||||||
|
animateOpen: {height: 'toggle'},
|
||||||
|
animateClose: {height: 'toggle'},
|
||||||
|
easing: 'swing',
|
||||||
|
text: '',
|
||||||
|
type: 'alert',
|
||||||
|
speed: 500,
|
||||||
|
timeout: 5000,
|
||||||
|
closeButton: false,
|
||||||
|
closeOnSelfClick: true,
|
||||||
|
closeOnSelfOver: false,
|
||||||
|
force: false,
|
||||||
|
onShow: false,
|
||||||
|
onClose: false,
|
||||||
|
buttons: false,
|
||||||
|
modal: false,
|
||||||
|
template: '<div class="noty_message"><span class="noty_text"></span><div class="noty_close"></div></div>',
|
||||||
|
cssPrefix: 'noty_',
|
||||||
|
custom: {
|
||||||
|
container: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.noty = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
(new $.noty(options, $(this)));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
//Helper
|
||||||
|
function noty(options) {
|
||||||
|
return jQuery.noty(options); // returns an id
|
||||||
|
}
|
353
app/assets/javascripts/app/lib/base/jquery.tagsinput.js
Normal file
353
app/assets/javascripts/app/lib/base/jquery.tagsinput.js
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
jQuery Tags Input Plugin 1.3.3
|
||||||
|
|
||||||
|
Copyright (c) 2011 XOXCO, Inc
|
||||||
|
|
||||||
|
Documentation for this plugin lives here:
|
||||||
|
http://xoxco.com/clickable/jquery-tags-input
|
||||||
|
|
||||||
|
Licensed under the MIT license:
|
||||||
|
http://www.opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
ben@xoxco.com
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
var delimiter = new Array();
|
||||||
|
var tags_callbacks = new Array();
|
||||||
|
$.fn.doAutosize = function(o){
|
||||||
|
var minWidth = $(this).data('minwidth'),
|
||||||
|
maxWidth = $(this).data('maxwidth'),
|
||||||
|
val = '',
|
||||||
|
input = $(this),
|
||||||
|
testSubject = $('#'+$(this).data('tester_id'));
|
||||||
|
|
||||||
|
if (val === (val = input.val())) {return;}
|
||||||
|
|
||||||
|
// Enter new content into testSubject
|
||||||
|
var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
testSubject.html(escaped);
|
||||||
|
// Calculate new width + whether to change
|
||||||
|
var testerWidth = testSubject.width(),
|
||||||
|
newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
|
||||||
|
currentWidth = input.width(),
|
||||||
|
isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
|
||||||
|
|| (newWidth > minWidth && newWidth < maxWidth);
|
||||||
|
|
||||||
|
// Animate width
|
||||||
|
if (isValidWidthChange) {
|
||||||
|
input.width(newWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
$.fn.resetAutosize = function(options){
|
||||||
|
// alert(JSON.stringify(options));
|
||||||
|
var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(),
|
||||||
|
maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding),
|
||||||
|
val = '',
|
||||||
|
input = $(this),
|
||||||
|
testSubject = $('<tester/>').css({
|
||||||
|
position: 'absolute',
|
||||||
|
top: -9999,
|
||||||
|
left: -9999,
|
||||||
|
width: 'auto',
|
||||||
|
fontSize: input.css('fontSize'),
|
||||||
|
fontFamily: input.css('fontFamily'),
|
||||||
|
fontWeight: input.css('fontWeight'),
|
||||||
|
letterSpacing: input.css('letterSpacing'),
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
}),
|
||||||
|
testerId = $(this).attr('id')+'_autosize_tester';
|
||||||
|
if(! $('#'+testerId).length > 0){
|
||||||
|
testSubject.attr('id', testerId);
|
||||||
|
testSubject.appendTo('body');
|
||||||
|
}
|
||||||
|
|
||||||
|
input.data('minwidth', minWidth);
|
||||||
|
input.data('maxwidth', maxWidth);
|
||||||
|
input.data('tester_id', testerId);
|
||||||
|
input.css('width', minWidth);
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.addTag = function(value,options) {
|
||||||
|
options = jQuery.extend({focus:false,callback:true},options);
|
||||||
|
this.each(function() {
|
||||||
|
var id = $(this).attr('id');
|
||||||
|
|
||||||
|
var tagslist = $(this).val().split(delimiter[id]);
|
||||||
|
if (tagslist[0] == '') {
|
||||||
|
tagslist = new Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
value = jQuery.trim(value);
|
||||||
|
|
||||||
|
if (options.unique) {
|
||||||
|
var skipTag = $(tagslist).tagExist(value);
|
||||||
|
if(skipTag == true) {
|
||||||
|
//Marks fake input as not_valid to let styling it
|
||||||
|
$('#'+id+'_tag').addClass('not_valid');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var skipTag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value !='' && skipTag != true) {
|
||||||
|
$('<span>').addClass('tag').append(
|
||||||
|
$('<span>').text(value).append(' '),
|
||||||
|
$('<a>', {
|
||||||
|
href : '#',
|
||||||
|
title : 'Removing tag',
|
||||||
|
text : 'x'
|
||||||
|
}).click(function () {
|
||||||
|
return $('#' + id).removeTag(escape(value));
|
||||||
|
})
|
||||||
|
).insertBefore('#' + id + '_addTag');
|
||||||
|
|
||||||
|
tagslist.push(value);
|
||||||
|
|
||||||
|
$('#'+id+'_tag').val('');
|
||||||
|
if (options.focus) {
|
||||||
|
$('#'+id+'_tag').focus();
|
||||||
|
} else {
|
||||||
|
$('#'+id+'_tag').blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.tagsInput.updateTagsField(this,tagslist);
|
||||||
|
|
||||||
|
if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) {
|
||||||
|
var f = tags_callbacks[id]['onAddTag'];
|
||||||
|
f.call(this, value);
|
||||||
|
}
|
||||||
|
if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
|
||||||
|
{
|
||||||
|
var i = tagslist.length;
|
||||||
|
var f = tags_callbacks[id]['onChange'];
|
||||||
|
f.call(this, $(this), tagslist[i-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.removeTag = function(value) {
|
||||||
|
value = unescape(value);
|
||||||
|
this.each(function() {
|
||||||
|
var id = $(this).attr('id');
|
||||||
|
|
||||||
|
var old = $(this).val().split(delimiter[id]);
|
||||||
|
|
||||||
|
$('#'+id+'_tagsinput .tag').remove();
|
||||||
|
str = '';
|
||||||
|
for (i=0; i< old.length; i++) {
|
||||||
|
if (old[i]!=value) {
|
||||||
|
str = str + delimiter[id] +old[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.tagsInput.importTags(this,str);
|
||||||
|
|
||||||
|
if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) {
|
||||||
|
var f = tags_callbacks[id]['onRemoveTag'];
|
||||||
|
f.call(this, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.tagExist = function(val) {
|
||||||
|
return (jQuery.inArray(val, $(this)) >= 0); //true when tag exists, false when not
|
||||||
|
};
|
||||||
|
|
||||||
|
// clear all existing tags and import new ones from a string
|
||||||
|
$.fn.importTags = function(str) {
|
||||||
|
id = $(this).attr('id');
|
||||||
|
$('#'+id+'_tagsinput .tag').remove();
|
||||||
|
$.fn.tagsInput.importTags(this,str);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.tagsInput = function(options) {
|
||||||
|
var settings = jQuery.extend({
|
||||||
|
interactive:true,
|
||||||
|
defaultText:'add a tag',
|
||||||
|
minChars:0,
|
||||||
|
width:'300px',
|
||||||
|
height:'100px',
|
||||||
|
autocomplete: {selectFirst: false },
|
||||||
|
'hide':true,
|
||||||
|
'delimiter':',',
|
||||||
|
'unique':true,
|
||||||
|
removeWithBackspace:true,
|
||||||
|
placeholderColor:'#666666',
|
||||||
|
autosize: true,
|
||||||
|
comfortZone: 20,
|
||||||
|
inputPadding: 6*2
|
||||||
|
},options);
|
||||||
|
|
||||||
|
this.each(function() {
|
||||||
|
if (settings.hide) {
|
||||||
|
$(this).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = $(this).attr('id')
|
||||||
|
|
||||||
|
var data = jQuery.extend({
|
||||||
|
pid:id,
|
||||||
|
real_input: '#'+id,
|
||||||
|
holder: '#'+id+'_tagsinput',
|
||||||
|
input_wrapper: '#'+id+'_addTag',
|
||||||
|
fake_input: '#'+id+'_tag'
|
||||||
|
},settings);
|
||||||
|
|
||||||
|
delimiter[id] = data.delimiter;
|
||||||
|
|
||||||
|
if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
|
||||||
|
tags_callbacks[id] = new Array();
|
||||||
|
tags_callbacks[id]['onAddTag'] = settings.onAddTag;
|
||||||
|
tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
|
||||||
|
tags_callbacks[id]['onChange'] = settings.onChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
var markup = '<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag">';
|
||||||
|
|
||||||
|
if (settings.interactive) {
|
||||||
|
markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
markup = markup + '</div><div class="tags_clear"></div></div>';
|
||||||
|
|
||||||
|
$(markup).insertAfter(this);
|
||||||
|
|
||||||
|
$(data.holder).css('width',settings.width);
|
||||||
|
$(data.holder).css('height',settings.height);
|
||||||
|
|
||||||
|
if ($(data.real_input).val()!='') {
|
||||||
|
$.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());
|
||||||
|
}
|
||||||
|
if (settings.interactive) {
|
||||||
|
$(data.fake_input).val($(data.fake_input).attr('data-default'));
|
||||||
|
$(data.fake_input).css('color',settings.placeholderColor);
|
||||||
|
$(data.fake_input).resetAutosize(settings);
|
||||||
|
|
||||||
|
$(data.holder).bind('click',data,function(event) {
|
||||||
|
$(event.data.fake_input).focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(data.fake_input).bind('focus',data,function(event) {
|
||||||
|
if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) {
|
||||||
|
$(event.data.fake_input).val('');
|
||||||
|
}
|
||||||
|
$(event.data.fake_input).css('color','#000000');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (settings.autocomplete_url != undefined) {
|
||||||
|
// 2012-02-23 me
|
||||||
|
// autocomplete_options = {source: settings.autocomplete_url};
|
||||||
|
autocomplete_options = settings.auto;
|
||||||
|
// 2012-02-23 me
|
||||||
|
for (attrname in settings.autocomplete) {
|
||||||
|
autocomplete_options[attrname] = settings.autocomplete[attrname];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jQuery.Autocompleter !== undefined) {
|
||||||
|
$(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete);
|
||||||
|
$(data.fake_input).bind('result',data,function(event,data,formatted) {
|
||||||
|
if (data) {
|
||||||
|
$('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (jQuery.ui.autocomplete !== undefined) {
|
||||||
|
$(data.fake_input).autocomplete(autocomplete_options);
|
||||||
|
$(data.fake_input).bind('autocompleteselect',data,function(event,ui) {
|
||||||
|
$(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// if a user tabs out of the field, create a new tag
|
||||||
|
// this is only available if autocomplete is not used.
|
||||||
|
$(data.fake_input).bind('blur',data,function(event) {
|
||||||
|
var d = $(this).attr('data-default');
|
||||||
|
if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {
|
||||||
|
if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
|
||||||
|
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
|
||||||
|
} else {
|
||||||
|
$(event.data.fake_input).val($(event.data.fake_input).attr('data-default'));
|
||||||
|
$(event.data.fake_input).css('color',settings.placeholderColor);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
// if user types a comma, create a new tag
|
||||||
|
$(data.fake_input).bind('keypress',data,function(event) {
|
||||||
|
if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13 ) {
|
||||||
|
event.preventDefault();
|
||||||
|
if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
|
||||||
|
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
|
||||||
|
$(event.data.fake_input).resetAutosize(settings);
|
||||||
|
return false;
|
||||||
|
} else if (event.data.autosize) {
|
||||||
|
$(event.data.fake_input).doAutosize(settings);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//Delete last tag on backspace
|
||||||
|
data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event)
|
||||||
|
{
|
||||||
|
if(event.keyCode == 8 && $(this).val() == '')
|
||||||
|
{
|
||||||
|
event.preventDefault();
|
||||||
|
var last_tag = $(this).closest('.tagsinput').find('.tag:last').text();
|
||||||
|
var id = $(this).attr('id').replace(/_tag$/, '');
|
||||||
|
last_tag = last_tag.replace(/[\s]+x$/, '');
|
||||||
|
$('#' + id).removeTag(escape(last_tag));
|
||||||
|
$(this).trigger('focus');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(data.fake_input).blur();
|
||||||
|
|
||||||
|
//Removes the not_valid class when user changes the value of the fake input
|
||||||
|
if(data.unique) {
|
||||||
|
$(data.fake_input).keydown(function(event){
|
||||||
|
if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/)) {
|
||||||
|
$(this).removeClass('not_valid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} // if settings.interactive
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.tagsInput.updateTagsField = function(obj,tagslist) {
|
||||||
|
var id = $(obj).attr('id');
|
||||||
|
$(obj).val(tagslist.join(delimiter[id]));
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.tagsInput.importTags = function(obj,val) {
|
||||||
|
$(obj).val('');
|
||||||
|
var id = $(obj).attr('id');
|
||||||
|
var tags = val.split(delimiter[id]);
|
||||||
|
for (i=0; i<tags.length; i++) {
|
||||||
|
$(obj).addTag(tags[i],{focus:false,callback:false});
|
||||||
|
}
|
||||||
|
if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
|
||||||
|
{
|
||||||
|
var f = tags_callbacks[id]['onChange'];
|
||||||
|
f.call(obj, obj, tags[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
674
app/assets/javascripts/app/lib/base/waypoints.js
Normal file
674
app/assets/javascripts/app/lib/base/waypoints.js
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
/*!
|
||||||
|
jQuery Waypoints - v1.1.6
|
||||||
|
Copyright (c) 2011-2012 Caleb Troughton
|
||||||
|
Dual licensed under the MIT license and GPL license.
|
||||||
|
https://github.com/imakewebthings/jquery-waypoints/blob/master/MIT-license.txt
|
||||||
|
https://github.com/imakewebthings/jquery-waypoints/blob/master/GPL-license.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Waypoints is a small jQuery plugin that makes it easy to execute a function
|
||||||
|
whenever you scroll to an element.
|
||||||
|
|
||||||
|
GitHub Repository: https://github.com/imakewebthings/jquery-waypoints
|
||||||
|
Documentation and Examples: http://imakewebthings.github.com/jquery-waypoints
|
||||||
|
|
||||||
|
Changelog:
|
||||||
|
v1.1.6
|
||||||
|
- Fix potential memory leak by unbinding events on empty context elements.
|
||||||
|
v1.1.5
|
||||||
|
- Make plugin compatible with Browserify/RequireJS. (Thanks @cjroebuck)
|
||||||
|
v1.1.4
|
||||||
|
- Add handler option to give alternate binding method. (Issue #34)
|
||||||
|
v1.1.3
|
||||||
|
- Fix cases where waypoints are added post-load and should be triggered
|
||||||
|
immediately. (Issue #28)
|
||||||
|
v1.1.2
|
||||||
|
- Fixed error thrown by waypoints with triggerOnce option that were
|
||||||
|
triggered via resize refresh.
|
||||||
|
v1.1.1
|
||||||
|
- Fixed bug in initialization where all offsets were being calculated
|
||||||
|
as if set to 0 initially, causing unwarranted triggers during the
|
||||||
|
subsequent refresh.
|
||||||
|
- Added onlyOnScroll, an option for individual waypoints that disables
|
||||||
|
triggers due to an offset refresh that crosses the current scroll
|
||||||
|
point. (All credit to @knuton on this one.)
|
||||||
|
v1.1
|
||||||
|
- Moved the continuous option out of global settings and into the options
|
||||||
|
object for individual waypoints.
|
||||||
|
- Added the context option, which allows for using waypoints within any
|
||||||
|
scrollable element, not just the window.
|
||||||
|
v1.0.2
|
||||||
|
- Moved scroll and resize handler bindings out of load. Should play nicer
|
||||||
|
with async loaders like Head JS and LABjs.
|
||||||
|
- Fixed a 1px off error when using certain % offsets.
|
||||||
|
- Added unit tests.
|
||||||
|
v1.0.1
|
||||||
|
- Added $.waypoints('viewportHeight').
|
||||||
|
- Fixed iOS bug (using the new viewportHeight method).
|
||||||
|
- Added offset function alias: 'bottom-in-view'.
|
||||||
|
v1.0
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
Support:
|
||||||
|
- jQuery versions 1.4.3+
|
||||||
|
- IE6+, FF3+, Chrome 6+, Safari 4+, Opera 11
|
||||||
|
- Other versions and browsers may work, these are just the ones I've looked at.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($, wp, wps, window, undefined){
|
||||||
|
'$:nomunge';
|
||||||
|
|
||||||
|
var $w = $(window),
|
||||||
|
|
||||||
|
// Keeping common strings as variables = better minification
|
||||||
|
eventName = 'waypoint.reached',
|
||||||
|
|
||||||
|
/*
|
||||||
|
For the waypoint and direction passed in, trigger the waypoint.reached
|
||||||
|
event and deal with the triggerOnce option.
|
||||||
|
*/
|
||||||
|
triggerWaypoint = function(way, dir) {
|
||||||
|
way.element.trigger(eventName, dir);
|
||||||
|
if (way.options.triggerOnce) {
|
||||||
|
way.element[wp]('destroy');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Given a jQuery element and Context, returns the index of that element in the waypoints
|
||||||
|
array. Returns the index, or -1 if the element is not a waypoint.
|
||||||
|
*/
|
||||||
|
waypointIndex = function(el, context) {
|
||||||
|
if (!context) return -1;
|
||||||
|
var i = context.waypoints.length - 1;
|
||||||
|
while (i >= 0 && context.waypoints[i].element[0] !== el[0]) {
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Private list of all elements used as scrolling contexts for waypoints.
|
||||||
|
contexts = [],
|
||||||
|
|
||||||
|
/*
|
||||||
|
Context Class - represents a scrolling context. Properties include:
|
||||||
|
element: jQuery object containing a single HTML element.
|
||||||
|
waypoints: Array of waypoints operating under this scroll context.
|
||||||
|
oldScroll: Keeps the previous scroll position to determine scroll direction.
|
||||||
|
didScroll: Flag used in scrolling the context's scroll event.
|
||||||
|
didResize: Flag used in scrolling the context's resize event.
|
||||||
|
doScroll: Function that checks for crossed waypoints. Called from throttler.
|
||||||
|
*/
|
||||||
|
Context = function(context) {
|
||||||
|
$.extend(this, {
|
||||||
|
element: $(context),
|
||||||
|
oldScroll: 0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
List of all elements that have been registered as waypoints.
|
||||||
|
Each object in the array contains:
|
||||||
|
element: jQuery object containing a single HTML element.
|
||||||
|
offset: The window scroll offset, in px, that triggers the waypoint event.
|
||||||
|
options: Options object that was passed to the waypoint fn function.
|
||||||
|
*/
|
||||||
|
'waypoints': [],
|
||||||
|
|
||||||
|
didScroll: false,
|
||||||
|
didResize: false,
|
||||||
|
|
||||||
|
doScroll: $.proxy(function() {
|
||||||
|
var newScroll = this.element.scrollTop(),
|
||||||
|
|
||||||
|
// Are we scrolling up or down? Used for direction argument in callback.
|
||||||
|
isDown = newScroll > this.oldScroll,
|
||||||
|
that = this,
|
||||||
|
|
||||||
|
// Get a list of all waypoints that were crossed since last scroll move.
|
||||||
|
pointsHit = $.grep(this.waypoints, function(el, i) {
|
||||||
|
return isDown ?
|
||||||
|
(el.offset > that.oldScroll && el.offset <= newScroll) :
|
||||||
|
(el.offset <= that.oldScroll && el.offset > newScroll);
|
||||||
|
}),
|
||||||
|
len = pointsHit.length;
|
||||||
|
|
||||||
|
// iOS adjustment
|
||||||
|
if (!this.oldScroll || !newScroll) {
|
||||||
|
$[wps]('refresh');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done with scroll comparisons, store new scroll before ejection
|
||||||
|
this.oldScroll = newScroll;
|
||||||
|
|
||||||
|
// No waypoints crossed? Eject.
|
||||||
|
if (!len) return;
|
||||||
|
|
||||||
|
// If several waypoints triggered, need to do so in reverse order going up
|
||||||
|
if (!isDown) pointsHit.reverse();
|
||||||
|
|
||||||
|
/*
|
||||||
|
One scroll move may cross several waypoints. If the waypoint's continuous
|
||||||
|
option is true it should fire even if it isn't the last waypoint. If false,
|
||||||
|
it will only fire if it's the last one.
|
||||||
|
*/
|
||||||
|
$.each(pointsHit, function(i, point) {
|
||||||
|
if (point.options.continuous || i === len - 1) {
|
||||||
|
triggerWaypoint(point, [isDown ? 'down' : 'up']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, this)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup scroll and resize handlers. Throttled at the settings-defined rate limits.
|
||||||
|
$(context).bind('scroll.waypoints', $.proxy(function() {
|
||||||
|
if (!this.didScroll) {
|
||||||
|
this.didScroll = true;
|
||||||
|
window.setTimeout($.proxy(function() {
|
||||||
|
this.doScroll();
|
||||||
|
this.didScroll = false;
|
||||||
|
}, this), $[wps].settings.scrollThrottle);
|
||||||
|
}
|
||||||
|
}, this)).bind('resize.waypoints', $.proxy(function() {
|
||||||
|
if (!this.didResize) {
|
||||||
|
this.didResize = true;
|
||||||
|
window.setTimeout($.proxy(function() {
|
||||||
|
$[wps]('refresh');
|
||||||
|
this.didResize = false;
|
||||||
|
}, this), $[wps].settings.resizeThrottle);
|
||||||
|
}
|
||||||
|
}, this));
|
||||||
|
|
||||||
|
$w.load($.proxy(function() {
|
||||||
|
/*
|
||||||
|
Fire a scroll check, should the page be loaded at a non-zero scroll value,
|
||||||
|
as with a fragment id link or a page refresh.
|
||||||
|
*/
|
||||||
|
this.doScroll();
|
||||||
|
}, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Returns a Context object from the contexts array, given the raw HTML element
|
||||||
|
for that context. */
|
||||||
|
getContextByElement = function(element) {
|
||||||
|
var found = null;
|
||||||
|
|
||||||
|
$.each(contexts, function(i, c) {
|
||||||
|
if (c.element[0] === element) {
|
||||||
|
found = c;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return found;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Methods exposed to the effin' object
|
||||||
|
methods = {
|
||||||
|
/*
|
||||||
|
jQuery.fn.waypoint([handler], [options])
|
||||||
|
|
||||||
|
handler
|
||||||
|
function, optional
|
||||||
|
A callback function called when the user scrolls past the element.
|
||||||
|
The function signature is function(event, direction) where event is
|
||||||
|
a standard jQuery Event Object and direction is a string, either 'down'
|
||||||
|
or 'up' indicating which direction the user is scrolling.
|
||||||
|
|
||||||
|
options
|
||||||
|
object, optional
|
||||||
|
A map of options to apply to this set of waypoints, including where on
|
||||||
|
the browser window the waypoint is triggered. For a full list of
|
||||||
|
options and their defaults, see $.fn.waypoint.defaults.
|
||||||
|
|
||||||
|
This is how you register an element as a waypoint. When the user scrolls past
|
||||||
|
that element it triggers waypoint.reached, a custom event. Since the
|
||||||
|
parameters for creating a waypoint are optional, we have a few different
|
||||||
|
possible signatures. Let’s look at each of them.
|
||||||
|
|
||||||
|
someElements.waypoint();
|
||||||
|
|
||||||
|
Calling .waypoint with no parameters will register the elements as waypoints
|
||||||
|
using the default options. The elements will fire the waypoint.reached event,
|
||||||
|
but calling it in this way does not bind any handler to the event. You can
|
||||||
|
bind to the event yourself, as with any other event, like so:
|
||||||
|
|
||||||
|
someElements.bind('waypoint.reached', function(event, direction) {
|
||||||
|
// make it rain
|
||||||
|
});
|
||||||
|
|
||||||
|
You will usually want to create a waypoint and immediately bind a function to
|
||||||
|
waypoint.reached, and can do so by passing a handler as the first argument to
|
||||||
|
.waypoint:
|
||||||
|
|
||||||
|
someElements.waypoint(function(event, direction) {
|
||||||
|
if (direction === 'down') {
|
||||||
|
// do this on the way down
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// do this on the way back up through the waypoint
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
This will still use the default options, which will trigger the waypoint when
|
||||||
|
the top of the element hits the top of the window. We can pass .waypoint an
|
||||||
|
options object to customize things:
|
||||||
|
|
||||||
|
someElements.waypoint(function(event, direction) {
|
||||||
|
// do something amazing
|
||||||
|
}, {
|
||||||
|
offset: '50%' // middle of the page
|
||||||
|
});
|
||||||
|
|
||||||
|
You can also pass just an options object.
|
||||||
|
|
||||||
|
someElements.waypoint({
|
||||||
|
offset: 100 // 100px from the top
|
||||||
|
});
|
||||||
|
|
||||||
|
This behaves like .waypoint(), in that it registers the elements as waypoints
|
||||||
|
but binds no event handlers.
|
||||||
|
|
||||||
|
Calling .waypoint on an existing waypoint will extend the previous options.
|
||||||
|
If the call includes a handler, it will be bound to waypoint.reached without
|
||||||
|
unbinding any other handlers.
|
||||||
|
*/
|
||||||
|
init: function(f, options) {
|
||||||
|
// Register each element as a waypoint, add to array.
|
||||||
|
this.each(function() {
|
||||||
|
var cElement = $.fn[wp].defaults.context,
|
||||||
|
context,
|
||||||
|
$this = $(this);
|
||||||
|
|
||||||
|
// Default window context or a specific element?
|
||||||
|
if (options && options.context) {
|
||||||
|
cElement = options.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the closest element that matches the context
|
||||||
|
if (!$.isWindow(cElement)) {
|
||||||
|
cElement = $this.closest(cElement)[0];
|
||||||
|
}
|
||||||
|
context = getContextByElement(cElement);
|
||||||
|
|
||||||
|
// Not a context yet? Create and push.
|
||||||
|
if (!context) {
|
||||||
|
context = new Context(cElement);
|
||||||
|
contexts.push(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend default and preexisting options
|
||||||
|
var ndx = waypointIndex($this, context),
|
||||||
|
base = ndx < 0 ? $.fn[wp].defaults : context.waypoints[ndx].options,
|
||||||
|
opts = $.extend({}, base, options);
|
||||||
|
|
||||||
|
// Offset aliases
|
||||||
|
opts.offset = opts.offset === "bottom-in-view" ?
|
||||||
|
function() {
|
||||||
|
var cHeight = $.isWindow(cElement) ? $[wps]('viewportHeight')
|
||||||
|
: $(cElement).height();
|
||||||
|
return cHeight - $(this).outerHeight();
|
||||||
|
} : opts.offset;
|
||||||
|
|
||||||
|
// Update, or create new waypoint
|
||||||
|
if (ndx < 0) {
|
||||||
|
context.waypoints.push({
|
||||||
|
'element': $this,
|
||||||
|
'offset': null,
|
||||||
|
'options': opts
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
context.waypoints[ndx].options = opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind the function if it was passed in.
|
||||||
|
if (f) {
|
||||||
|
$this.bind(eventName, f);
|
||||||
|
}
|
||||||
|
// Bind the function in the handler option if it exists.
|
||||||
|
if (options && options.handler) {
|
||||||
|
$this.bind(eventName, options.handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Need to re-sort+refresh the waypoints array after new elements are added.
|
||||||
|
$[wps]('refresh');
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
jQuery.fn.waypoint('remove')
|
||||||
|
|
||||||
|
Passing the string 'remove' to .waypoint unregisters the elements as waypoints
|
||||||
|
and wipes any custom options, but leaves the waypoint.reached events bound.
|
||||||
|
Calling .waypoint again in the future would reregister the waypoint and the old
|
||||||
|
handlers would continue to work.
|
||||||
|
*/
|
||||||
|
remove: function() {
|
||||||
|
return this.each(function(i, el) {
|
||||||
|
var $el = $(el);
|
||||||
|
|
||||||
|
$.each(contexts, function(i, c) {
|
||||||
|
var ndx = waypointIndex($el, c);
|
||||||
|
|
||||||
|
if (ndx >= 0) {
|
||||||
|
c.waypoints.splice(ndx, 1);
|
||||||
|
|
||||||
|
if (!c.waypoints.length) {
|
||||||
|
c.element.unbind('scroll.waypoints resize.waypoints');
|
||||||
|
contexts.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
jQuery.fn.waypoint('destroy')
|
||||||
|
|
||||||
|
Passing the string 'destroy' to .waypoint will unbind all waypoint.reached
|
||||||
|
event handlers on those elements and unregisters them as waypoints.
|
||||||
|
*/
|
||||||
|
destroy: function() {
|
||||||
|
return this.unbind(eventName)[wp]('remove');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Methods used by the jQuery object extension.
|
||||||
|
*/
|
||||||
|
jQMethods = {
|
||||||
|
|
||||||
|
/*
|
||||||
|
jQuery.waypoints('refresh')
|
||||||
|
|
||||||
|
This will force a recalculation of each waypoint’s trigger point based on
|
||||||
|
its offset option and context. This is called automatically whenever the window
|
||||||
|
(or other defined context) is resized, new waypoints are added, or a waypoint’s
|
||||||
|
options are modified. If your project is changing the DOM or page layout without
|
||||||
|
doing one of these things, you may want to manually call this refresh.
|
||||||
|
*/
|
||||||
|
refresh: function() {
|
||||||
|
$.each(contexts, function(i, c) {
|
||||||
|
var isWin = $.isWindow(c.element[0]),
|
||||||
|
contextOffset = isWin ? 0 : c.element.offset().top,
|
||||||
|
contextHeight = isWin ? $[wps]('viewportHeight') : c.element.height(),
|
||||||
|
contextScroll = isWin ? 0 : c.element.scrollTop();
|
||||||
|
|
||||||
|
$.each(c.waypoints, function(j, o) {
|
||||||
|
/* $.each isn't safe from element removal due to triggerOnce.
|
||||||
|
Should rewrite the loop but this is way easier. */
|
||||||
|
if (!o) return;
|
||||||
|
|
||||||
|
// Adjustment is just the offset if it's a px value
|
||||||
|
var adjustment = o.options.offset,
|
||||||
|
oldOffset = o.offset;
|
||||||
|
|
||||||
|
// Set adjustment to the return value if offset is a function.
|
||||||
|
if (typeof o.options.offset === "function") {
|
||||||
|
adjustment = o.options.offset.apply(o.element);
|
||||||
|
}
|
||||||
|
// Calculate the adjustment if offset is a percentage.
|
||||||
|
else if (typeof o.options.offset === "string") {
|
||||||
|
var amount = parseFloat(o.options.offset);
|
||||||
|
adjustment = o.options.offset.indexOf("%") ?
|
||||||
|
Math.ceil(contextHeight * (amount / 100)) : amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the element offset to the window scroll offset, less
|
||||||
|
all our adjustments.
|
||||||
|
*/
|
||||||
|
o.offset = o.element.offset().top - contextOffset
|
||||||
|
+ contextScroll - adjustment;
|
||||||
|
|
||||||
|
/*
|
||||||
|
An element offset change across the current scroll point triggers
|
||||||
|
the event, just as if we scrolled past it unless prevented by an
|
||||||
|
optional flag.
|
||||||
|
*/
|
||||||
|
if (o.options.onlyOnScroll) return;
|
||||||
|
|
||||||
|
if (oldOffset !== null && c.oldScroll > oldOffset && c.oldScroll <= o.offset) {
|
||||||
|
triggerWaypoint(o, ['up']);
|
||||||
|
}
|
||||||
|
else if (oldOffset !== null && c.oldScroll < oldOffset && c.oldScroll >= o.offset) {
|
||||||
|
triggerWaypoint(o, ['down']);
|
||||||
|
}
|
||||||
|
/* For new waypoints added after load, check that down should have
|
||||||
|
already been triggered */
|
||||||
|
else if (!oldOffset && c.element.scrollTop() > o.offset) {
|
||||||
|
triggerWaypoint(o, ['down']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keep waypoints sorted by offset value.
|
||||||
|
c.waypoints.sort(function(a, b) {
|
||||||
|
return a.offset - b.offset;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
jQuery.waypoints('viewportHeight')
|
||||||
|
|
||||||
|
This will return the height of the viewport, adjusting for inconsistencies
|
||||||
|
that come with calling $(window).height() in iOS. Recommended for use
|
||||||
|
within any offset functions.
|
||||||
|
*/
|
||||||
|
viewportHeight: function() {
|
||||||
|
return (window.innerHeight ? window.innerHeight : $w.height());
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
jQuery.waypoints()
|
||||||
|
|
||||||
|
This will return a jQuery object with a collection of all registered waypoint
|
||||||
|
elements.
|
||||||
|
|
||||||
|
$('.post').waypoint();
|
||||||
|
$('.ad-unit').waypoint(function(event, direction) {
|
||||||
|
// Passed an ad unit
|
||||||
|
});
|
||||||
|
console.log($.waypoints());
|
||||||
|
|
||||||
|
The example above would log a jQuery object containing all .post and .ad-unit
|
||||||
|
elements.
|
||||||
|
*/
|
||||||
|
aggregate: function() {
|
||||||
|
var points = $();
|
||||||
|
$.each(contexts, function(i, c) {
|
||||||
|
$.each(c.waypoints, function(i, e) {
|
||||||
|
points = points.add(e.element);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn extension. Delegates to appropriate method.
|
||||||
|
*/
|
||||||
|
$.fn[wp] = function(method) {
|
||||||
|
|
||||||
|
if (methods[method]) {
|
||||||
|
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||||
|
}
|
||||||
|
else if (typeof method === "function" || !method) {
|
||||||
|
return methods.init.apply(this, arguments);
|
||||||
|
}
|
||||||
|
else if (typeof method === "object") {
|
||||||
|
return methods.init.apply(this, [null, method]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$.error( 'Method ' + method + ' does not exist on jQuery ' + wp );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The default options object that is extended when calling .waypoint. It has the
|
||||||
|
following properties:
|
||||||
|
|
||||||
|
context
|
||||||
|
string | element | jQuery*
|
||||||
|
default: window
|
||||||
|
The context defines which scrollable element the waypoint belongs to and acts
|
||||||
|
within. The default, window, means the waypoint offset is calculated with relation
|
||||||
|
to the whole viewport. You can set this to another element to use the waypoints
|
||||||
|
within that element. Accepts a selector string, *but if you use jQuery 1.6+ it
|
||||||
|
also accepts a raw HTML element or jQuery object.
|
||||||
|
|
||||||
|
continuous
|
||||||
|
boolean
|
||||||
|
default: true
|
||||||
|
If true, and multiple waypoints are triggered in one scroll, this waypoint will
|
||||||
|
trigger even if it is not the last waypoint reached. If false, it will only
|
||||||
|
trigger if it is the last waypoint.
|
||||||
|
|
||||||
|
handler
|
||||||
|
function
|
||||||
|
default: undefined
|
||||||
|
An alternative way to bind functions to the waypoint, without using the function
|
||||||
|
as the first argument to the waypoint function.
|
||||||
|
|
||||||
|
offset
|
||||||
|
number | string | function
|
||||||
|
default: 0
|
||||||
|
Determines how far the top of the element must be from the top of the browser
|
||||||
|
window to trigger a waypoint. It can be a number, which is taken as a number
|
||||||
|
of pixels, a string representing a percentage of the viewport height, or a
|
||||||
|
function that will return a number of pixels.
|
||||||
|
|
||||||
|
onlyOnScroll
|
||||||
|
boolean
|
||||||
|
default: false
|
||||||
|
If true, this waypoint will not trigger if an offset change during a refresh
|
||||||
|
causes it to pass the current scroll point.
|
||||||
|
|
||||||
|
triggerOnce
|
||||||
|
boolean
|
||||||
|
default: false
|
||||||
|
If true, the waypoint will be destroyed when triggered.
|
||||||
|
|
||||||
|
An offset of 250 would trigger the waypoint when the top of the element is 250px
|
||||||
|
from the top of the viewport. Negative values for any offset work as you might
|
||||||
|
expect. A value of -100 would trigger the waypoint when the element is 100px above
|
||||||
|
the top of the window.
|
||||||
|
|
||||||
|
offset: '100%'
|
||||||
|
|
||||||
|
A string percentage will determine the pixel offset based on the height of the
|
||||||
|
window. When resizing the window, this offset will automatically be recalculated
|
||||||
|
without needing to call $.waypoints('refresh').
|
||||||
|
|
||||||
|
// The bottom of the element is in view
|
||||||
|
offset: function() {
|
||||||
|
return $.waypoints('viewportHeight') - $(this).outerHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
Offset can take a function, which must return a number of pixels from the top of
|
||||||
|
the window. The this value will always refer to the raw HTML element of the
|
||||||
|
waypoint. As with % values, functions are recalculated automatically when the
|
||||||
|
window resizes. For more on recalculating offsets, see $.waypoints('refresh').
|
||||||
|
|
||||||
|
An offset value of 'bottom-in-view' will act as an alias for the function in the
|
||||||
|
example above, as this is a common usage.
|
||||||
|
|
||||||
|
offset: 'bottom-in-view'
|
||||||
|
|
||||||
|
You can see this alias in use on the Scroll Analytics example page.
|
||||||
|
|
||||||
|
The triggerOnce flag, if true, will destroy the waypoint after the first trigger.
|
||||||
|
This is just a shortcut for calling .waypoint('destroy') within the waypoint
|
||||||
|
handler. This is useful in situations such as scroll analytics, where you only
|
||||||
|
want to record an event once for each page visit.
|
||||||
|
|
||||||
|
The context option lets you use Waypoints within an element other than the window.
|
||||||
|
You can define the context with a selector string and the waypoint will act within
|
||||||
|
the nearest ancestor that matches this selector.
|
||||||
|
|
||||||
|
$('.something-scrollable .waypoint').waypoint({
|
||||||
|
context: '.something-scrollable'
|
||||||
|
});
|
||||||
|
|
||||||
|
You can see this in action on the Dial Controls example.
|
||||||
|
|
||||||
|
The handler option gives authors an alternative way to bind functions when
|
||||||
|
creating a waypoint. In place of:
|
||||||
|
|
||||||
|
$('.item').waypoint(function(event, direction) {
|
||||||
|
// make things happen
|
||||||
|
});
|
||||||
|
|
||||||
|
You may instead write:
|
||||||
|
|
||||||
|
$('.item').waypoint({
|
||||||
|
handler: function(event, direction) {
|
||||||
|
// make things happen
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
$.fn[wp].defaults = {
|
||||||
|
continuous: true,
|
||||||
|
offset: 0,
|
||||||
|
triggerOnce: false,
|
||||||
|
context: window
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
jQuery object extension. Delegates to appropriate methods above.
|
||||||
|
*/
|
||||||
|
$[wps] = function(method) {
|
||||||
|
if (jQMethods[method]) {
|
||||||
|
return jQMethods[method].apply(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return jQMethods['aggregate']();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
$.waypoints.settings
|
||||||
|
|
||||||
|
Settings object that determines some of the plugin’s behavior.
|
||||||
|
|
||||||
|
resizeThrottle
|
||||||
|
number
|
||||||
|
default: 200
|
||||||
|
For performance reasons, the refresh performed during resizes is
|
||||||
|
throttled. This value is the rate-limit in milliseconds between resize
|
||||||
|
refreshes. For more information on throttling, check out Ben Alman’s
|
||||||
|
throttle / debounce plugin.
|
||||||
|
http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||||
|
|
||||||
|
scrollThrottle
|
||||||
|
number
|
||||||
|
default: 100
|
||||||
|
For performance reasons, checking for any crossed waypoints during a
|
||||||
|
scroll event is throttled. This value is the rate-limit in milliseconds
|
||||||
|
between scroll checks. For more information on throttling, check out Ben
|
||||||
|
Alman’s throttle / debounce plugin.
|
||||||
|
http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||||
|
*/
|
||||||
|
$[wps].settings = {
|
||||||
|
resizeThrottle: 200,
|
||||||
|
scrollThrottle: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
$w.load(function() {
|
||||||
|
// Calculate everything once on load.
|
||||||
|
$[wps]('refresh');
|
||||||
|
});
|
||||||
|
})(jQuery, 'waypoint', 'waypoints', window);
|
90
app/assets/javascripts/app/lib/bootstrap/bootstrap-alert.js
vendored
Executable file
90
app/assets/javascripts/app/lib/bootstrap/bootstrap-alert.js
vendored
Executable file
|
@ -0,0 +1,90 @@
|
||||||
|
/* ==========================================================
|
||||||
|
* bootstrap-alert.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#alerts
|
||||||
|
* ==========================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* ALERT CLASS DEFINITION
|
||||||
|
* ====================== */
|
||||||
|
|
||||||
|
var dismiss = '[data-dismiss="alert"]'
|
||||||
|
, Alert = function (el) {
|
||||||
|
$(el).on('click', dismiss, this.close)
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert.prototype.close = function (e) {
|
||||||
|
var $this = $(this)
|
||||||
|
, selector = $this.attr('data-target')
|
||||||
|
, $parent
|
||||||
|
|
||||||
|
if (!selector) {
|
||||||
|
selector = $this.attr('href')
|
||||||
|
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent = $(selector)
|
||||||
|
|
||||||
|
e && e.preventDefault()
|
||||||
|
|
||||||
|
$parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
|
||||||
|
|
||||||
|
$parent.trigger(e = $.Event('close'))
|
||||||
|
|
||||||
|
if (e.isDefaultPrevented()) return
|
||||||
|
|
||||||
|
$parent.removeClass('in')
|
||||||
|
|
||||||
|
function removeElement() {
|
||||||
|
$parent
|
||||||
|
.trigger('closed')
|
||||||
|
.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
$.support.transition && $parent.hasClass('fade') ?
|
||||||
|
$parent.on($.support.transition.end, removeElement) :
|
||||||
|
removeElement()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ALERT PLUGIN DEFINITION
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
$.fn.alert = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('alert')
|
||||||
|
if (!data) $this.data('alert', (data = new Alert(this)))
|
||||||
|
if (typeof option == 'string') data[option].call($this)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.alert.Constructor = Alert
|
||||||
|
|
||||||
|
|
||||||
|
/* ALERT DATA-API
|
||||||
|
* ============== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
96
app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js
vendored
Executable file
96
app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js
vendored
Executable file
|
@ -0,0 +1,96 @@
|
||||||
|
/* ============================================================
|
||||||
|
* bootstrap-button.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#buttons
|
||||||
|
* ============================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* BUTTON PUBLIC CLASS DEFINITION
|
||||||
|
* ============================== */
|
||||||
|
|
||||||
|
var Button = function (element, options) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = $.extend({}, $.fn.button.defaults, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button.prototype.setState = function (state) {
|
||||||
|
var d = 'disabled'
|
||||||
|
, $el = this.$element
|
||||||
|
, data = $el.data()
|
||||||
|
, val = $el.is('input') ? 'val' : 'html'
|
||||||
|
|
||||||
|
state = state + 'Text'
|
||||||
|
data.resetText || $el.data('resetText', $el[val]())
|
||||||
|
|
||||||
|
$el[val](data[state] || this.options[state])
|
||||||
|
|
||||||
|
// push to event loop to allow forms to submit
|
||||||
|
setTimeout(function () {
|
||||||
|
state == 'loadingText' ?
|
||||||
|
$el.addClass(d).attr(d, d) :
|
||||||
|
$el.removeClass(d).removeAttr(d)
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button.prototype.toggle = function () {
|
||||||
|
var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
|
||||||
|
|
||||||
|
$parent && $parent
|
||||||
|
.find('.active')
|
||||||
|
.removeClass('active')
|
||||||
|
|
||||||
|
this.$element.toggleClass('active')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* BUTTON PLUGIN DEFINITION
|
||||||
|
* ======================== */
|
||||||
|
|
||||||
|
$.fn.button = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('button')
|
||||||
|
, options = typeof option == 'object' && option
|
||||||
|
if (!data) $this.data('button', (data = new Button(this, options)))
|
||||||
|
if (option == 'toggle') data.toggle()
|
||||||
|
else if (option) data.setState(option)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.button.defaults = {
|
||||||
|
loadingText: 'loading...'
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.button.Constructor = Button
|
||||||
|
|
||||||
|
|
||||||
|
/* BUTTON DATA-API
|
||||||
|
* =============== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
|
||||||
|
var $btn = $(e.target)
|
||||||
|
if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
|
||||||
|
$btn.button('toggle')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
169
app/assets/javascripts/app/lib/bootstrap/bootstrap-carousel.js
vendored
Executable file
169
app/assets/javascripts/app/lib/bootstrap/bootstrap-carousel.js
vendored
Executable file
|
@ -0,0 +1,169 @@
|
||||||
|
/* ==========================================================
|
||||||
|
* bootstrap-carousel.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#carousel
|
||||||
|
* ==========================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* CAROUSEL CLASS DEFINITION
|
||||||
|
* ========================= */
|
||||||
|
|
||||||
|
var Carousel = function (element, options) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = options
|
||||||
|
this.options.slide && this.slide(this.options.slide)
|
||||||
|
this.options.pause == 'hover' && this.$element
|
||||||
|
.on('mouseenter', $.proxy(this.pause, this))
|
||||||
|
.on('mouseleave', $.proxy(this.cycle, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
Carousel.prototype = {
|
||||||
|
|
||||||
|
cycle: function (e) {
|
||||||
|
if (!e) this.paused = false
|
||||||
|
this.options.interval
|
||||||
|
&& !this.paused
|
||||||
|
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, to: function (pos) {
|
||||||
|
var $active = this.$element.find('.active')
|
||||||
|
, children = $active.parent().children()
|
||||||
|
, activePos = children.index($active)
|
||||||
|
, that = this
|
||||||
|
|
||||||
|
if (pos > (children.length - 1) || pos < 0) return
|
||||||
|
|
||||||
|
if (this.sliding) {
|
||||||
|
return this.$element.one('slid', function () {
|
||||||
|
that.to(pos)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activePos == pos) {
|
||||||
|
return this.pause().cycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
|
||||||
|
}
|
||||||
|
|
||||||
|
, pause: function (e) {
|
||||||
|
if (!e) this.paused = true
|
||||||
|
clearInterval(this.interval)
|
||||||
|
this.interval = null
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, next: function () {
|
||||||
|
if (this.sliding) return
|
||||||
|
return this.slide('next')
|
||||||
|
}
|
||||||
|
|
||||||
|
, prev: function () {
|
||||||
|
if (this.sliding) return
|
||||||
|
return this.slide('prev')
|
||||||
|
}
|
||||||
|
|
||||||
|
, slide: function (type, next) {
|
||||||
|
var $active = this.$element.find('.active')
|
||||||
|
, $next = next || $active[type]()
|
||||||
|
, isCycling = this.interval
|
||||||
|
, direction = type == 'next' ? 'left' : 'right'
|
||||||
|
, fallback = type == 'next' ? 'first' : 'last'
|
||||||
|
, that = this
|
||||||
|
, e = $.Event('slide')
|
||||||
|
|
||||||
|
this.sliding = true
|
||||||
|
|
||||||
|
isCycling && this.pause()
|
||||||
|
|
||||||
|
$next = $next.length ? $next : this.$element.find('.item')[fallback]()
|
||||||
|
|
||||||
|
if ($next.hasClass('active')) return
|
||||||
|
|
||||||
|
if ($.support.transition && this.$element.hasClass('slide')) {
|
||||||
|
this.$element.trigger(e)
|
||||||
|
if (e.isDefaultPrevented()) return
|
||||||
|
$next.addClass(type)
|
||||||
|
$next[0].offsetWidth // force reflow
|
||||||
|
$active.addClass(direction)
|
||||||
|
$next.addClass(direction)
|
||||||
|
this.$element.one($.support.transition.end, function () {
|
||||||
|
$next.removeClass([type, direction].join(' ')).addClass('active')
|
||||||
|
$active.removeClass(['active', direction].join(' '))
|
||||||
|
that.sliding = false
|
||||||
|
setTimeout(function () { that.$element.trigger('slid') }, 0)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.$element.trigger(e)
|
||||||
|
if (e.isDefaultPrevented()) return
|
||||||
|
$active.removeClass('active')
|
||||||
|
$next.addClass('active')
|
||||||
|
this.sliding = false
|
||||||
|
this.$element.trigger('slid')
|
||||||
|
}
|
||||||
|
|
||||||
|
isCycling && this.cycle()
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* CAROUSEL PLUGIN DEFINITION
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
$.fn.carousel = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('carousel')
|
||||||
|
, options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
|
||||||
|
if (!data) $this.data('carousel', (data = new Carousel(this, options)))
|
||||||
|
if (typeof option == 'number') data.to(option)
|
||||||
|
else if (typeof option == 'string' || (option = options.slide)) data[option]()
|
||||||
|
else if (options.interval) data.cycle()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.carousel.defaults = {
|
||||||
|
interval: 5000
|
||||||
|
, pause: 'hover'
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.carousel.Constructor = Carousel
|
||||||
|
|
||||||
|
|
||||||
|
/* CAROUSEL DATA-API
|
||||||
|
* ================= */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
|
||||||
|
var $this = $(this), href
|
||||||
|
, $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|
||||||
|
, options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
|
||||||
|
$target.carousel(options)
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
157
app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js
vendored
Executable file
157
app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js
vendored
Executable file
|
@ -0,0 +1,157 @@
|
||||||
|
/* =============================================================
|
||||||
|
* bootstrap-collapse.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#collapse
|
||||||
|
* =============================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* COLLAPSE PUBLIC CLASS DEFINITION
|
||||||
|
* ================================ */
|
||||||
|
|
||||||
|
var Collapse = function (element, options) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = $.extend({}, $.fn.collapse.defaults, options)
|
||||||
|
|
||||||
|
if (this.options.parent) {
|
||||||
|
this.$parent = $(this.options.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options.toggle && this.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
Collapse.prototype = {
|
||||||
|
|
||||||
|
constructor: Collapse
|
||||||
|
|
||||||
|
, dimension: function () {
|
||||||
|
var hasWidth = this.$element.hasClass('width')
|
||||||
|
return hasWidth ? 'width' : 'height'
|
||||||
|
}
|
||||||
|
|
||||||
|
, show: function () {
|
||||||
|
var dimension
|
||||||
|
, scroll
|
||||||
|
, actives
|
||||||
|
, hasData
|
||||||
|
|
||||||
|
if (this.transitioning) return
|
||||||
|
|
||||||
|
dimension = this.dimension()
|
||||||
|
scroll = $.camelCase(['scroll', dimension].join('-'))
|
||||||
|
actives = this.$parent && this.$parent.find('> .accordion-group > .in')
|
||||||
|
|
||||||
|
if (actives && actives.length) {
|
||||||
|
hasData = actives.data('collapse')
|
||||||
|
if (hasData && hasData.transitioning) return
|
||||||
|
actives.collapse('hide')
|
||||||
|
hasData || actives.data('collapse', null)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$element[dimension](0)
|
||||||
|
this.transition('addClass', $.Event('show'), 'shown')
|
||||||
|
this.$element[dimension](this.$element[0][scroll])
|
||||||
|
}
|
||||||
|
|
||||||
|
, hide: function () {
|
||||||
|
var dimension
|
||||||
|
if (this.transitioning) return
|
||||||
|
dimension = this.dimension()
|
||||||
|
this.reset(this.$element[dimension]())
|
||||||
|
this.transition('removeClass', $.Event('hide'), 'hidden')
|
||||||
|
this.$element[dimension](0)
|
||||||
|
}
|
||||||
|
|
||||||
|
, reset: function (size) {
|
||||||
|
var dimension = this.dimension()
|
||||||
|
|
||||||
|
this.$element
|
||||||
|
.removeClass('collapse')
|
||||||
|
[dimension](size || 'auto')
|
||||||
|
[0].offsetWidth
|
||||||
|
|
||||||
|
this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, transition: function (method, startEvent, completeEvent) {
|
||||||
|
var that = this
|
||||||
|
, complete = function () {
|
||||||
|
if (startEvent.type == 'show') that.reset()
|
||||||
|
that.transitioning = 0
|
||||||
|
that.$element.trigger(completeEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$element.trigger(startEvent)
|
||||||
|
|
||||||
|
if (startEvent.isDefaultPrevented()) return
|
||||||
|
|
||||||
|
this.transitioning = 1
|
||||||
|
|
||||||
|
this.$element[method]('in')
|
||||||
|
|
||||||
|
$.support.transition && this.$element.hasClass('collapse') ?
|
||||||
|
this.$element.one($.support.transition.end, complete) :
|
||||||
|
complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
, toggle: function () {
|
||||||
|
this[this.$element.hasClass('in') ? 'hide' : 'show']()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* COLLAPSIBLE PLUGIN DEFINITION
|
||||||
|
* ============================== */
|
||||||
|
|
||||||
|
$.fn.collapse = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('collapse')
|
||||||
|
, options = typeof option == 'object' && option
|
||||||
|
if (!data) $this.data('collapse', (data = new Collapse(this, options)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.collapse.defaults = {
|
||||||
|
toggle: true
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.collapse.Constructor = Collapse
|
||||||
|
|
||||||
|
|
||||||
|
/* COLLAPSIBLE DATA-API
|
||||||
|
* ==================== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
|
||||||
|
var $this = $(this), href
|
||||||
|
, target = $this.attr('data-target')
|
||||||
|
|| e.preventDefault()
|
||||||
|
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
|
||||||
|
, option = $(target).data('collapse') ? 'toggle' : $this.data()
|
||||||
|
$(target).collapse(option)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
100
app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js
vendored
Normal file
100
app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/* ============================================================
|
||||||
|
* bootstrap-dropdown.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#dropdowns
|
||||||
|
* ============================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* DROPDOWN CLASS DEFINITION
|
||||||
|
* ========================= */
|
||||||
|
|
||||||
|
var toggle = '[data-toggle="dropdown"]'
|
||||||
|
, Dropdown = function (element) {
|
||||||
|
var $el = $(element).on('click.dropdown.data-api', this.toggle)
|
||||||
|
$('html').on('click.dropdown.data-api', function () {
|
||||||
|
$el.parent().removeClass('open')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Dropdown.prototype = {
|
||||||
|
|
||||||
|
constructor: Dropdown
|
||||||
|
|
||||||
|
, toggle: function (e) {
|
||||||
|
var $this = $(this)
|
||||||
|
, $parent
|
||||||
|
, selector
|
||||||
|
, isActive
|
||||||
|
|
||||||
|
if ($this.is('.disabled, :disabled')) return
|
||||||
|
|
||||||
|
selector = $this.attr('data-target')
|
||||||
|
|
||||||
|
if (!selector) {
|
||||||
|
selector = $this.attr('href')
|
||||||
|
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent = $(selector)
|
||||||
|
$parent.length || ($parent = $this.parent())
|
||||||
|
|
||||||
|
isActive = $parent.hasClass('open')
|
||||||
|
|
||||||
|
clearMenus()
|
||||||
|
|
||||||
|
if (!isActive) $parent.toggleClass('open')
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearMenus() {
|
||||||
|
$(toggle).parent().removeClass('open')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* DROPDOWN PLUGIN DEFINITION
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
$.fn.dropdown = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('dropdown')
|
||||||
|
if (!data) $this.data('dropdown', (data = new Dropdown(this)))
|
||||||
|
if (typeof option == 'string') data[option].call($this)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.dropdown.Constructor = Dropdown
|
||||||
|
|
||||||
|
|
||||||
|
/* APPLY TO STANDARD DROPDOWN ELEMENTS
|
||||||
|
* =================================== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('html').on('click.dropdown.data-api', clearMenus)
|
||||||
|
$('body')
|
||||||
|
.on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
|
||||||
|
.on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
218
app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js
vendored
Normal file
218
app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js
vendored
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
/* =========================================================
|
||||||
|
* bootstrap-modal.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#modals
|
||||||
|
* =========================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================= */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL CLASS DEFINITION
|
||||||
|
* ====================== */
|
||||||
|
|
||||||
|
var Modal = function (content, options) {
|
||||||
|
this.options = options
|
||||||
|
this.$element = $(content)
|
||||||
|
.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
Modal.prototype = {
|
||||||
|
|
||||||
|
constructor: Modal
|
||||||
|
|
||||||
|
, toggle: function () {
|
||||||
|
return this[!this.isShown ? 'show' : 'hide']()
|
||||||
|
}
|
||||||
|
|
||||||
|
, show: function () {
|
||||||
|
var that = this
|
||||||
|
, e = $.Event('show')
|
||||||
|
|
||||||
|
this.$element.trigger(e)
|
||||||
|
|
||||||
|
if (this.isShown || e.isDefaultPrevented()) return
|
||||||
|
|
||||||
|
$('body').addClass('modal-open')
|
||||||
|
|
||||||
|
this.isShown = true
|
||||||
|
|
||||||
|
escape.call(this)
|
||||||
|
backdrop.call(this, function () {
|
||||||
|
var transition = $.support.transition && that.$element.hasClass('fade')
|
||||||
|
|
||||||
|
if (!that.$element.parent().length) {
|
||||||
|
that.$element.appendTo(document.body) //don't move modals dom position
|
||||||
|
}
|
||||||
|
|
||||||
|
that.$element
|
||||||
|
.show()
|
||||||
|
|
||||||
|
if (transition) {
|
||||||
|
that.$element[0].offsetWidth // force reflow
|
||||||
|
}
|
||||||
|
|
||||||
|
that.$element.addClass('in')
|
||||||
|
|
||||||
|
transition ?
|
||||||
|
that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
|
||||||
|
that.$element.trigger('shown')
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
, hide: function (e) {
|
||||||
|
e && e.preventDefault()
|
||||||
|
|
||||||
|
var that = this
|
||||||
|
|
||||||
|
e = $.Event('hide')
|
||||||
|
|
||||||
|
this.$element.trigger(e)
|
||||||
|
|
||||||
|
if (!this.isShown || e.isDefaultPrevented()) return
|
||||||
|
|
||||||
|
this.isShown = false
|
||||||
|
|
||||||
|
$('body').removeClass('modal-open')
|
||||||
|
|
||||||
|
escape.call(this)
|
||||||
|
|
||||||
|
this.$element.removeClass('in')
|
||||||
|
|
||||||
|
$.support.transition && this.$element.hasClass('fade') ?
|
||||||
|
hideWithTransition.call(this) :
|
||||||
|
hideModal.call(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL PRIVATE METHODS
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
function hideWithTransition() {
|
||||||
|
var that = this
|
||||||
|
, timeout = setTimeout(function () {
|
||||||
|
that.$element.off($.support.transition.end)
|
||||||
|
hideModal.call(that)
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
this.$element.one($.support.transition.end, function () {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
hideModal.call(that)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideModal(that) {
|
||||||
|
this.$element
|
||||||
|
.hide()
|
||||||
|
.trigger('hidden')
|
||||||
|
|
||||||
|
backdrop.call(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
function backdrop(callback) {
|
||||||
|
var that = this
|
||||||
|
, animate = this.$element.hasClass('fade') ? 'fade' : ''
|
||||||
|
|
||||||
|
if (this.isShown && this.options.backdrop) {
|
||||||
|
var doAnimate = $.support.transition && animate
|
||||||
|
|
||||||
|
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
|
||||||
|
.appendTo(document.body)
|
||||||
|
|
||||||
|
if (this.options.backdrop != 'static') {
|
||||||
|
this.$backdrop.click($.proxy(this.hide, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
|
||||||
|
|
||||||
|
this.$backdrop.addClass('in')
|
||||||
|
|
||||||
|
doAnimate ?
|
||||||
|
this.$backdrop.one($.support.transition.end, callback) :
|
||||||
|
callback()
|
||||||
|
|
||||||
|
} else if (!this.isShown && this.$backdrop) {
|
||||||
|
this.$backdrop.removeClass('in')
|
||||||
|
|
||||||
|
$.support.transition && this.$element.hasClass('fade')?
|
||||||
|
this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
|
||||||
|
removeBackdrop.call(this)
|
||||||
|
|
||||||
|
} else if (callback) {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeBackdrop() {
|
||||||
|
this.$backdrop.remove()
|
||||||
|
this.$backdrop = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape() {
|
||||||
|
var that = this
|
||||||
|
if (this.isShown && this.options.keyboard) {
|
||||||
|
$(document).on('keyup.dismiss.modal', function ( e ) {
|
||||||
|
e.which == 27 && that.hide()
|
||||||
|
})
|
||||||
|
} else if (!this.isShown) {
|
||||||
|
$(document).off('keyup.dismiss.modal')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL PLUGIN DEFINITION
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
$.fn.modal = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('modal')
|
||||||
|
, options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
|
||||||
|
if (!data) $this.data('modal', (data = new Modal(this, options)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
else if (options.show) data.show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.modal.defaults = {
|
||||||
|
backdrop: true
|
||||||
|
, keyboard: true
|
||||||
|
, show: true
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.modal.Constructor = Modal
|
||||||
|
|
||||||
|
|
||||||
|
/* MODAL DATA-API
|
||||||
|
* ============== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
|
||||||
|
var $this = $(this), href
|
||||||
|
, $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|
||||||
|
, option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
|
||||||
|
|
||||||
|
e.preventDefault()
|
||||||
|
$target.modal(option)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
98
app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js
vendored
Normal file
98
app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* ===========================================================
|
||||||
|
* bootstrap-popover.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#popovers
|
||||||
|
* ===========================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* =========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* POPOVER PUBLIC CLASS DEFINITION
|
||||||
|
* =============================== */
|
||||||
|
|
||||||
|
var Popover = function ( element, options ) {
|
||||||
|
this.init('popover', element, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
|
||||||
|
========================================== */
|
||||||
|
|
||||||
|
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
|
||||||
|
|
||||||
|
constructor: Popover
|
||||||
|
|
||||||
|
, setContent: function () {
|
||||||
|
var $tip = this.tip()
|
||||||
|
, title = this.getTitle()
|
||||||
|
, content = this.getContent()
|
||||||
|
|
||||||
|
$tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
|
||||||
|
$tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
|
||||||
|
|
||||||
|
$tip.removeClass('fade top bottom left right in')
|
||||||
|
}
|
||||||
|
|
||||||
|
, hasContent: function () {
|
||||||
|
return this.getTitle() || this.getContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
, getContent: function () {
|
||||||
|
var content
|
||||||
|
, $e = this.$element
|
||||||
|
, o = this.options
|
||||||
|
|
||||||
|
content = $e.attr('data-content')
|
||||||
|
|| (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
|
||||||
|
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
, tip: function () {
|
||||||
|
if (!this.$tip) {
|
||||||
|
this.$tip = $(this.options.template)
|
||||||
|
}
|
||||||
|
return this.$tip
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
/* POPOVER PLUGIN DEFINITION
|
||||||
|
* ======================= */
|
||||||
|
|
||||||
|
$.fn.popover = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('popover')
|
||||||
|
, options = typeof option == 'object' && option
|
||||||
|
if (!data) $this.data('popover', (data = new Popover(this, options)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.popover.Constructor = Popover
|
||||||
|
|
||||||
|
$.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
|
||||||
|
placement: 'right'
|
||||||
|
, content: ''
|
||||||
|
, template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
151
app/assets/javascripts/app/lib/bootstrap/bootstrap-scrollspy.js
vendored
Executable file
151
app/assets/javascripts/app/lib/bootstrap/bootstrap-scrollspy.js
vendored
Executable file
|
@ -0,0 +1,151 @@
|
||||||
|
/* =============================================================
|
||||||
|
* bootstrap-scrollspy.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#scrollspy
|
||||||
|
* =============================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ============================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* SCROLLSPY CLASS DEFINITION
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
function ScrollSpy( element, options) {
|
||||||
|
var process = $.proxy(this.process, this)
|
||||||
|
, $element = $(element).is('body') ? $(window) : $(element)
|
||||||
|
, href
|
||||||
|
this.options = $.extend({}, $.fn.scrollspy.defaults, options)
|
||||||
|
this.$scrollElement = $element.on('scroll.scroll.data-api', process)
|
||||||
|
this.selector = (this.options.target
|
||||||
|
|| ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|
||||||
|
|| '') + ' .nav li > a'
|
||||||
|
this.$body = $('body')
|
||||||
|
this.refresh()
|
||||||
|
this.process()
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollSpy.prototype = {
|
||||||
|
|
||||||
|
constructor: ScrollSpy
|
||||||
|
|
||||||
|
, refresh: function () {
|
||||||
|
var self = this
|
||||||
|
, $targets
|
||||||
|
|
||||||
|
this.offsets = $([])
|
||||||
|
this.targets = $([])
|
||||||
|
|
||||||
|
$targets = this.$body
|
||||||
|
.find(this.selector)
|
||||||
|
.map(function () {
|
||||||
|
var $el = $(this)
|
||||||
|
, href = $el.data('target') || $el.attr('href')
|
||||||
|
, $href = /^#\w/.test(href) && $(href)
|
||||||
|
return ( $href
|
||||||
|
&& href.length
|
||||||
|
&& [[ $href.position().top, href ]] ) || null
|
||||||
|
})
|
||||||
|
.sort(function (a, b) { return a[0] - b[0] })
|
||||||
|
.each(function () {
|
||||||
|
self.offsets.push(this[0])
|
||||||
|
self.targets.push(this[1])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
, process: function () {
|
||||||
|
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
|
||||||
|
, scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
|
||||||
|
, maxScroll = scrollHeight - this.$scrollElement.height()
|
||||||
|
, offsets = this.offsets
|
||||||
|
, targets = this.targets
|
||||||
|
, activeTarget = this.activeTarget
|
||||||
|
, i
|
||||||
|
|
||||||
|
if (scrollTop >= maxScroll) {
|
||||||
|
return activeTarget != (i = targets.last()[0])
|
||||||
|
&& this.activate ( i )
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = offsets.length; i--;) {
|
||||||
|
activeTarget != targets[i]
|
||||||
|
&& scrollTop >= offsets[i]
|
||||||
|
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
|
||||||
|
&& this.activate( targets[i] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, activate: function (target) {
|
||||||
|
var active
|
||||||
|
, selector
|
||||||
|
|
||||||
|
this.activeTarget = target
|
||||||
|
|
||||||
|
$(this.selector)
|
||||||
|
.parent('.active')
|
||||||
|
.removeClass('active')
|
||||||
|
|
||||||
|
selector = this.selector
|
||||||
|
+ '[data-target="' + target + '"],'
|
||||||
|
+ this.selector + '[href="' + target + '"]'
|
||||||
|
|
||||||
|
active = $(selector)
|
||||||
|
.parent('li')
|
||||||
|
.addClass('active')
|
||||||
|
|
||||||
|
if (active.parent('.dropdown-menu')) {
|
||||||
|
active = active.closest('li.dropdown').addClass('active')
|
||||||
|
}
|
||||||
|
|
||||||
|
active.trigger('activate')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SCROLLSPY PLUGIN DEFINITION
|
||||||
|
* =========================== */
|
||||||
|
|
||||||
|
$.fn.scrollspy = function ( option ) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('scrollspy')
|
||||||
|
, options = typeof option == 'object' && option
|
||||||
|
if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.scrollspy.Constructor = ScrollSpy
|
||||||
|
|
||||||
|
$.fn.scrollspy.defaults = {
|
||||||
|
offset: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SCROLLSPY DATA-API
|
||||||
|
* ================== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('[data-spy="scroll"]').each(function () {
|
||||||
|
var $spy = $(this)
|
||||||
|
$spy.scrollspy($spy.data())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
135
app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js
vendored
Normal file
135
app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js
vendored
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/* ========================================================
|
||||||
|
* bootstrap-tab.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#tabs
|
||||||
|
* ========================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ======================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* TAB CLASS DEFINITION
|
||||||
|
* ==================== */
|
||||||
|
|
||||||
|
var Tab = function ( element ) {
|
||||||
|
this.element = $(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
Tab.prototype = {
|
||||||
|
|
||||||
|
constructor: Tab
|
||||||
|
|
||||||
|
, show: function () {
|
||||||
|
var $this = this.element
|
||||||
|
, $ul = $this.closest('ul:not(.dropdown-menu)')
|
||||||
|
, selector = $this.attr('data-target')
|
||||||
|
, previous
|
||||||
|
, $target
|
||||||
|
, e
|
||||||
|
|
||||||
|
if (!selector) {
|
||||||
|
selector = $this.attr('href')
|
||||||
|
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $this.parent('li').hasClass('active') ) return
|
||||||
|
|
||||||
|
previous = $ul.find('.active a').last()[0]
|
||||||
|
|
||||||
|
e = $.Event('show', {
|
||||||
|
relatedTarget: previous
|
||||||
|
})
|
||||||
|
|
||||||
|
$this.trigger(e)
|
||||||
|
|
||||||
|
if (e.isDefaultPrevented()) return
|
||||||
|
|
||||||
|
$target = $(selector)
|
||||||
|
|
||||||
|
this.activate($this.parent('li'), $ul)
|
||||||
|
this.activate($target, $target.parent(), function () {
|
||||||
|
$this.trigger({
|
||||||
|
type: 'shown'
|
||||||
|
, relatedTarget: previous
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
, activate: function ( element, container, callback) {
|
||||||
|
var $active = container.find('> .active')
|
||||||
|
, transition = callback
|
||||||
|
&& $.support.transition
|
||||||
|
&& $active.hasClass('fade')
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
$active
|
||||||
|
.removeClass('active')
|
||||||
|
.find('> .dropdown-menu > .active')
|
||||||
|
.removeClass('active')
|
||||||
|
|
||||||
|
element.addClass('active')
|
||||||
|
|
||||||
|
if (transition) {
|
||||||
|
element[0].offsetWidth // reflow for transition
|
||||||
|
element.addClass('in')
|
||||||
|
} else {
|
||||||
|
element.removeClass('fade')
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( element.parent('.dropdown-menu') ) {
|
||||||
|
element.closest('li.dropdown').addClass('active')
|
||||||
|
}
|
||||||
|
|
||||||
|
callback && callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
transition ?
|
||||||
|
$active.one($.support.transition.end, next) :
|
||||||
|
next()
|
||||||
|
|
||||||
|
$active.removeClass('in')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TAB PLUGIN DEFINITION
|
||||||
|
* ===================== */
|
||||||
|
|
||||||
|
$.fn.tab = function ( option ) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('tab')
|
||||||
|
if (!data) $this.data('tab', (data = new Tab(this)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.tab.Constructor = Tab
|
||||||
|
|
||||||
|
|
||||||
|
/* TAB DATA-API
|
||||||
|
* ============ */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
$(this).tab('show')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
275
app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js
vendored
Normal file
275
app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js
vendored
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/* ===========================================================
|
||||||
|
* bootstrap-tooltip.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#tooltips
|
||||||
|
* Inspired by the original jQuery.tipsy by Jason Frame
|
||||||
|
* ===========================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* TOOLTIP PUBLIC CLASS DEFINITION
|
||||||
|
* =============================== */
|
||||||
|
|
||||||
|
var Tooltip = function (element, options) {
|
||||||
|
this.init('tooltip', element, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip.prototype = {
|
||||||
|
|
||||||
|
constructor: Tooltip
|
||||||
|
|
||||||
|
, init: function (type, element, options) {
|
||||||
|
var eventIn
|
||||||
|
, eventOut
|
||||||
|
|
||||||
|
this.type = type
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = this.getOptions(options)
|
||||||
|
this.enabled = true
|
||||||
|
|
||||||
|
if (this.options.trigger != 'manual') {
|
||||||
|
eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
|
||||||
|
eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
|
||||||
|
this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
|
||||||
|
this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.options.selector ?
|
||||||
|
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
|
||||||
|
this.fixTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
, getOptions: function (options) {
|
||||||
|
options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
|
||||||
|
|
||||||
|
if (options.delay && typeof options.delay == 'number') {
|
||||||
|
options.delay = {
|
||||||
|
show: options.delay
|
||||||
|
, hide: options.delay
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
, enter: function (e) {
|
||||||
|
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
|
||||||
|
|
||||||
|
if (!self.options.delay || !self.options.delay.show) return self.show()
|
||||||
|
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
self.hoverState = 'in'
|
||||||
|
this.timeout = setTimeout(function() {
|
||||||
|
if (self.hoverState == 'in') self.show()
|
||||||
|
}, self.options.delay.show)
|
||||||
|
}
|
||||||
|
|
||||||
|
, leave: function (e) {
|
||||||
|
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
|
||||||
|
|
||||||
|
if (this.timeout) clearTimeout(this.timeout)
|
||||||
|
if (!self.options.delay || !self.options.delay.hide) return self.hide()
|
||||||
|
|
||||||
|
self.hoverState = 'out'
|
||||||
|
this.timeout = setTimeout(function() {
|
||||||
|
if (self.hoverState == 'out') self.hide()
|
||||||
|
}, self.options.delay.hide)
|
||||||
|
}
|
||||||
|
|
||||||
|
, show: function () {
|
||||||
|
var $tip
|
||||||
|
, inside
|
||||||
|
, pos
|
||||||
|
, actualWidth
|
||||||
|
, actualHeight
|
||||||
|
, placement
|
||||||
|
, tp
|
||||||
|
|
||||||
|
if (this.hasContent() && this.enabled) {
|
||||||
|
$tip = this.tip()
|
||||||
|
this.setContent()
|
||||||
|
|
||||||
|
if (this.options.animation) {
|
||||||
|
$tip.addClass('fade')
|
||||||
|
}
|
||||||
|
|
||||||
|
placement = typeof this.options.placement == 'function' ?
|
||||||
|
this.options.placement.call(this, $tip[0], this.$element[0]) :
|
||||||
|
this.options.placement
|
||||||
|
|
||||||
|
inside = /in/.test(placement)
|
||||||
|
|
||||||
|
$tip
|
||||||
|
.remove()
|
||||||
|
.css({ top: 0, left: 0, display: 'block' })
|
||||||
|
.appendTo(inside ? this.$element : document.body)
|
||||||
|
|
||||||
|
pos = this.getPosition(inside)
|
||||||
|
|
||||||
|
actualWidth = $tip[0].offsetWidth
|
||||||
|
actualHeight = $tip[0].offsetHeight
|
||||||
|
|
||||||
|
switch (inside ? placement.split(' ')[1] : placement) {
|
||||||
|
case 'bottom':
|
||||||
|
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||||
|
break
|
||||||
|
case 'top':
|
||||||
|
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||||
|
break
|
||||||
|
case 'left':
|
||||||
|
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
|
||||||
|
break
|
||||||
|
case 'right':
|
||||||
|
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
$tip
|
||||||
|
.css(tp)
|
||||||
|
.addClass(placement)
|
||||||
|
.addClass('in')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, isHTML: function(text) {
|
||||||
|
// html string detection logic adapted from jQuery
|
||||||
|
return typeof text != 'string'
|
||||||
|
|| ( text.charAt(0) === "<"
|
||||||
|
&& text.charAt( text.length - 1 ) === ">"
|
||||||
|
&& text.length >= 3
|
||||||
|
) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
, setContent: function () {
|
||||||
|
var $tip = this.tip()
|
||||||
|
, title = this.getTitle()
|
||||||
|
|
||||||
|
$tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
|
||||||
|
$tip.removeClass('fade in top bottom left right')
|
||||||
|
}
|
||||||
|
|
||||||
|
, hide: function () {
|
||||||
|
var that = this
|
||||||
|
, $tip = this.tip()
|
||||||
|
|
||||||
|
$tip.removeClass('in')
|
||||||
|
|
||||||
|
function removeWithAnimation() {
|
||||||
|
var timeout = setTimeout(function () {
|
||||||
|
$tip.off($.support.transition.end).remove()
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
$tip.one($.support.transition.end, function () {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
$tip.remove()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.support.transition && this.$tip.hasClass('fade') ?
|
||||||
|
removeWithAnimation() :
|
||||||
|
$tip.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
, fixTitle: function () {
|
||||||
|
var $e = this.$element
|
||||||
|
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
|
||||||
|
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, hasContent: function () {
|
||||||
|
return this.getTitle()
|
||||||
|
}
|
||||||
|
|
||||||
|
, getPosition: function (inside) {
|
||||||
|
return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
|
||||||
|
width: this.$element[0].offsetWidth
|
||||||
|
, height: this.$element[0].offsetHeight
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
, getTitle: function () {
|
||||||
|
var title
|
||||||
|
, $e = this.$element
|
||||||
|
, o = this.options
|
||||||
|
|
||||||
|
title = $e.attr('data-original-title')
|
||||||
|
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
|
||||||
|
|
||||||
|
return title
|
||||||
|
}
|
||||||
|
|
||||||
|
, tip: function () {
|
||||||
|
return this.$tip = this.$tip || $(this.options.template)
|
||||||
|
}
|
||||||
|
|
||||||
|
, validate: function () {
|
||||||
|
if (!this.$element[0].parentNode) {
|
||||||
|
this.hide()
|
||||||
|
this.$element = null
|
||||||
|
this.options = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
, enable: function () {
|
||||||
|
this.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
, disable: function () {
|
||||||
|
this.enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
, toggleEnabled: function () {
|
||||||
|
this.enabled = !this.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
, toggle: function () {
|
||||||
|
this[this.tip().hasClass('in') ? 'hide' : 'show']()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TOOLTIP PLUGIN DEFINITION
|
||||||
|
* ========================= */
|
||||||
|
|
||||||
|
$.fn.tooltip = function ( option ) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('tooltip')
|
||||||
|
, options = typeof option == 'object' && option
|
||||||
|
if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.tooltip.Constructor = Tooltip
|
||||||
|
|
||||||
|
$.fn.tooltip.defaults = {
|
||||||
|
animation: true
|
||||||
|
, placement: 'top'
|
||||||
|
, selector: false
|
||||||
|
, template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
|
||||||
|
, trigger: 'hover'
|
||||||
|
, title: ''
|
||||||
|
, delay: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}(window.jQuery);
|
61
app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js
vendored
Normal file
61
app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/* ===================================================
|
||||||
|
* bootstrap-transition.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#transitions
|
||||||
|
* ===================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
!function ($) {
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
|
||||||
|
* ======================================================= */
|
||||||
|
|
||||||
|
$.support.transition = (function () {
|
||||||
|
|
||||||
|
var transitionEnd = (function () {
|
||||||
|
|
||||||
|
var el = document.createElement('bootstrap')
|
||||||
|
, transEndEventNames = {
|
||||||
|
'WebkitTransition' : 'webkitTransitionEnd'
|
||||||
|
, 'MozTransition' : 'transitionend'
|
||||||
|
, 'OTransition' : 'oTransitionEnd'
|
||||||
|
, 'msTransition' : 'MSTransitionEnd'
|
||||||
|
, 'transition' : 'transitionend'
|
||||||
|
}
|
||||||
|
, name
|
||||||
|
|
||||||
|
for (name in transEndEventNames){
|
||||||
|
if (el.style[name] !== undefined) {
|
||||||
|
return transEndEventNames[name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}())
|
||||||
|
|
||||||
|
return transitionEnd && {
|
||||||
|
end: transitionEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
})()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
285
app/assets/javascripts/app/lib/bootstrap/bootstrap-typeahead.js
vendored
Executable file
285
app/assets/javascripts/app/lib/bootstrap/bootstrap-typeahead.js
vendored
Executable file
|
@ -0,0 +1,285 @@
|
||||||
|
/* =============================================================
|
||||||
|
* bootstrap-typeahead.js v2.0.4
|
||||||
|
* http://twitter.github.com/bootstrap/javascript.html#typeahead
|
||||||
|
* =============================================================
|
||||||
|
* Copyright 2012 Twitter, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
|
||||||
|
!function($){
|
||||||
|
|
||||||
|
"use strict"; // jshint ;_;
|
||||||
|
|
||||||
|
|
||||||
|
/* TYPEAHEAD PUBLIC CLASS DEFINITION
|
||||||
|
* ================================= */
|
||||||
|
|
||||||
|
var Typeahead = function (element, options) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = $.extend({}, $.fn.typeahead.defaults, options)
|
||||||
|
this.matcher = this.options.matcher || this.matcher
|
||||||
|
this.sorter = this.options.sorter || this.sorter
|
||||||
|
this.highlighter = this.options.highlighter || this.highlighter
|
||||||
|
this.updater = this.options.updater || this.updater
|
||||||
|
this.$menu = $(this.options.menu).appendTo('body')
|
||||||
|
this.source = this.options.source
|
||||||
|
this.shown = false
|
||||||
|
this.listen()
|
||||||
|
}
|
||||||
|
|
||||||
|
Typeahead.prototype = {
|
||||||
|
|
||||||
|
constructor: Typeahead
|
||||||
|
|
||||||
|
, select: function () {
|
||||||
|
var val = this.$menu.find('.active').attr('data-value')
|
||||||
|
this.$element
|
||||||
|
.val(this.updater(val))
|
||||||
|
.change()
|
||||||
|
return this.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
, updater: function (item) {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
, show: function () {
|
||||||
|
var pos = $.extend({}, this.$element.offset(), {
|
||||||
|
height: this.$element[0].offsetHeight
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$menu.css({
|
||||||
|
top: pos.top + pos.height
|
||||||
|
, left: pos.left
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$menu.show()
|
||||||
|
this.shown = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, hide: function () {
|
||||||
|
this.$menu.hide()
|
||||||
|
this.shown = false
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, lookup: function (event) {
|
||||||
|
var that = this
|
||||||
|
, items
|
||||||
|
, q
|
||||||
|
|
||||||
|
this.query = this.$element.val()
|
||||||
|
|
||||||
|
if (!this.query) {
|
||||||
|
return this.shown ? this.hide() : this
|
||||||
|
}
|
||||||
|
|
||||||
|
items = $.grep(this.source, function (item) {
|
||||||
|
return that.matcher(item)
|
||||||
|
})
|
||||||
|
|
||||||
|
items = this.sorter(items)
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
return this.shown ? this.hide() : this
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.render(items.slice(0, this.options.items)).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
, matcher: function (item) {
|
||||||
|
return ~item.toLowerCase().indexOf(this.query.toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
, sorter: function (items) {
|
||||||
|
var beginswith = []
|
||||||
|
, caseSensitive = []
|
||||||
|
, caseInsensitive = []
|
||||||
|
, item
|
||||||
|
|
||||||
|
while (item = items.shift()) {
|
||||||
|
if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
|
||||||
|
else if (~item.indexOf(this.query)) caseSensitive.push(item)
|
||||||
|
else caseInsensitive.push(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return beginswith.concat(caseSensitive, caseInsensitive)
|
||||||
|
}
|
||||||
|
|
||||||
|
, highlighter: function (item) {
|
||||||
|
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
|
||||||
|
return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
|
||||||
|
return '<strong>' + match + '</strong>'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
, render: function (items) {
|
||||||
|
var that = this
|
||||||
|
|
||||||
|
items = $(items).map(function (i, item) {
|
||||||
|
i = $(that.options.item).attr('data-value', item)
|
||||||
|
i.find('a').html(that.highlighter(item))
|
||||||
|
return i[0]
|
||||||
|
})
|
||||||
|
|
||||||
|
items.first().addClass('active')
|
||||||
|
this.$menu.html(items)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
, next: function (event) {
|
||||||
|
var active = this.$menu.find('.active').removeClass('active')
|
||||||
|
, next = active.next()
|
||||||
|
|
||||||
|
if (!next.length) {
|
||||||
|
next = $(this.$menu.find('li')[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
next.addClass('active')
|
||||||
|
}
|
||||||
|
|
||||||
|
, prev: function (event) {
|
||||||
|
var active = this.$menu.find('.active').removeClass('active')
|
||||||
|
, prev = active.prev()
|
||||||
|
|
||||||
|
if (!prev.length) {
|
||||||
|
prev = this.$menu.find('li').last()
|
||||||
|
}
|
||||||
|
|
||||||
|
prev.addClass('active')
|
||||||
|
}
|
||||||
|
|
||||||
|
, listen: function () {
|
||||||
|
this.$element
|
||||||
|
.on('blur', $.proxy(this.blur, this))
|
||||||
|
.on('keypress', $.proxy(this.keypress, this))
|
||||||
|
.on('keyup', $.proxy(this.keyup, this))
|
||||||
|
|
||||||
|
if ($.browser.webkit || $.browser.msie) {
|
||||||
|
this.$element.on('keydown', $.proxy(this.keypress, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$menu
|
||||||
|
.on('click', $.proxy(this.click, this))
|
||||||
|
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
, keyup: function (e) {
|
||||||
|
switch(e.keyCode) {
|
||||||
|
case 40: // down arrow
|
||||||
|
case 38: // up arrow
|
||||||
|
break
|
||||||
|
|
||||||
|
case 9: // tab
|
||||||
|
case 13: // enter
|
||||||
|
if (!this.shown) return
|
||||||
|
this.select()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 27: // escape
|
||||||
|
if (!this.shown) return
|
||||||
|
this.hide()
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.lookup()
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
, keypress: function (e) {
|
||||||
|
if (!this.shown) return
|
||||||
|
|
||||||
|
switch(e.keyCode) {
|
||||||
|
case 9: // tab
|
||||||
|
case 13: // enter
|
||||||
|
case 27: // escape
|
||||||
|
e.preventDefault()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 38: // up arrow
|
||||||
|
if (e.type != 'keydown') break
|
||||||
|
e.preventDefault()
|
||||||
|
this.prev()
|
||||||
|
break
|
||||||
|
|
||||||
|
case 40: // down arrow
|
||||||
|
if (e.type != 'keydown') break
|
||||||
|
e.preventDefault()
|
||||||
|
this.next()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
, blur: function (e) {
|
||||||
|
var that = this
|
||||||
|
setTimeout(function () { that.hide() }, 150)
|
||||||
|
}
|
||||||
|
|
||||||
|
, click: function (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
this.select()
|
||||||
|
}
|
||||||
|
|
||||||
|
, mouseenter: function (e) {
|
||||||
|
this.$menu.find('.active').removeClass('active')
|
||||||
|
$(e.currentTarget).addClass('active')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TYPEAHEAD PLUGIN DEFINITION
|
||||||
|
* =========================== */
|
||||||
|
|
||||||
|
$.fn.typeahead = function (option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
, data = $this.data('typeahead')
|
||||||
|
, options = typeof option == 'object' && option
|
||||||
|
if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
|
||||||
|
if (typeof option == 'string') data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.typeahead.defaults = {
|
||||||
|
source: []
|
||||||
|
, items: 8
|
||||||
|
, menu: '<ul class="typeahead dropdown-menu"></ul>'
|
||||||
|
, item: '<li><a href="#"></a></li>'
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.typeahead.Constructor = Typeahead
|
||||||
|
|
||||||
|
|
||||||
|
/* TYPEAHEAD DATA-API
|
||||||
|
* ================== */
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
$('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
|
||||||
|
var $this = $(this)
|
||||||
|
if ($this.data('typeahead')) return
|
||||||
|
e.preventDefault()
|
||||||
|
$this.typeahead($this.data())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}(window.jQuery);
|
4
app/assets/javascripts/app/lib/core/jquery-1.7.2.min.js
vendored
Normal file
4
app/assets/javascripts/app/lib/core/jquery-1.7.2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9301
app/assets/javascripts/app/lib/core/jquery-1.8.1.js
vendored
Normal file
9301
app/assets/javascripts/app/lib/core/jquery-1.8.1.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
2
app/assets/javascripts/app/lib/core/jquery-1.8.1.min.js
vendored
Normal file
2
app/assets/javascripts/app/lib/core/jquery-1.8.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1059
app/assets/javascripts/app/lib/core/underscore-1.3.3.js
Normal file
1059
app/assets/javascripts/app/lib/core/underscore-1.3.3.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue