'
@@ -724,11 +729,10 @@ class Article extends App.Controller
@article_changed = false
@article['html'] = @article['html'].replace /^\n{0,10}(--|__)/m, (match) =>
@article_changed = true
- notify + '
' + match
+ notify + '
' + match
if @article_changed
@article['html'] = @article['html'] + '
'
-
actionRow: ->
if @isRole('Customer')
@article.actions = []
@@ -786,7 +790,7 @@ class TicketActionRow extends App.Controller
@render()
render: ->
- @html App.view('ticket_action')()
+ @html App.view('ticket_zoom/actions')()
history_dialog: (e) ->
e.preventDefault()
@@ -794,11 +798,11 @@ class TicketActionRow extends App.Controller
merge_dialog: (e) ->
e.preventDefault()
- new App.TicketMerge( ticket_id: @ticket.id, task_key: @zoom.task_key )
+ new App.TicketMerge( ticket_id: @ticket.id, task_key: @ui.task_key )
customer_dialog: (e) ->
e.preventDefault()
- new App.TicketCustomer( ticket_id: @ticket.id, zoom: @zoom )
+ new App.TicketCustomer( ticket_id: @ticket.id, ui: @ui )
class TicketZoomRouter extends App.ControllerPermanent
constructor: (params) ->
diff --git a/app/assets/javascripts/app/controllers/trigger.js.coffee b/app/assets/javascripts/app/controllers/trigger.js.coffee
index a3266e683..7733907c8 100644
--- a/app/assets/javascripts/app/controllers/trigger.js.coffee
+++ b/app/assets/javascripts/app/controllers/trigger.js.coffee
@@ -13,11 +13,13 @@ class Index extends App.ControllerContent
@render()
render: ->
-
+
@html App.view('trigger')(
head: 'some header'
)
-App.Config.set( 'trigger', Index, 'Routes' )
+#App.Config.set( 'trigger', Index, 'Routes' )
+#App.Config.set( 'Trigger', { prio: 3000, parent: '#admin', name: 'Trigger', target: '#trigger', role: ['Admin'] }, 'NavBar' )
+
+App.Config.set( 'Trigger', { prio: 3000, name: 'Triggers', target: '#manage/triggers', controller: Index, role: ['Admin'] }, 'NavBarLevel2' )
-App.Config.set( 'Trigger', { prio: 3000, parent: '#admin', name: 'Trigger', target: '#trigger', role: ['Admin'] }, 'NavBar' )
\ No newline at end of file
diff --git a/app/assets/javascripts/app/controllers/users.js.coffee b/app/assets/javascripts/app/controllers/users.js.coffee
index b6754b747..aff0e623c 100644
--- a/app/assets/javascripts/app/controllers/users.js.coffee
+++ b/app/assets/javascripts/app/controllers/users.js.coffee
@@ -1,4 +1,4 @@
-class Index extends App.ControllerContent
+class Index extends App.Controller
constructor: ->
super
@@ -6,26 +6,24 @@ class Index extends App.ControllerContent
return if !@authenticate()
new App.ControllerGenericIndex(
- el: @el,
- id: @id,
- genericObject: 'User',
- defaultSortBy: 'login',
- ignoreObjectIDs: [1],
- pageData: {
- title: 'Users',
- home: 'users',
- object: 'User',
- objects: 'Users',
- navupdate: '#users',
+ el: @el
+ id: @id
+ genericObject: 'User'
+ defaultSortBy: 'login'
+ ignoreObjectIDs: [1]
+ pageData:
+ title: 'Users'
+ home: 'users'
+ object: 'User'
+ objects: 'Users'
+ navupdate: '#users'
notes: [
'Users are for any person in the system. Agents (Owners, Resposbiles, ...) and Customers.'
- ],
+ ]
buttons: [
# { name: 'List', 'data-type': '', class: 'active' },
- { name: 'New User', 'data-type': 'new', class: 'primary' },
- ],
- }
+ { name: 'New User', 'data-type': 'new', class: 'primary' }
+ ]
)
-App.Config.set( 'users', Index, 'Routes' )
-App.Config.set( 'User', { prio: 1000, parent: '#admin', name: 'Users', target: '#users', role: ['Admin'] }, 'NavBar' )
+App.Config.set( 'User', { prio: 1000, name: 'Users', parent: '#manage', target: '#manage/users', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
diff --git a/app/assets/javascripts/app/controllers/chat_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/chat.js.coffee
similarity index 95%
rename from app/assets/javascripts/app/controllers/chat_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/chat.js.coffee
index dcc3c02e5..802337153 100644
--- a/app/assets/javascripts/app/controllers/chat_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/chat.js.coffee
@@ -1,4 +1,4 @@
-class App.ChatWidget extends App.Controller
+class Widget extends App.Controller
events:
'submit #chat_form': 'submitMessage'
'focusin [name=chat_message]': 'focusIn'
@@ -130,6 +130,7 @@ class App.ChatWidget extends App.Controller
'chat-message-new'
)
@el.find('#chat_content').show(100)
+ @el.find('#chat_content').removeClass('hide')
@newMessage = false
# hide
@@ -142,6 +143,7 @@ class App.ChatWidget extends App.Controller
hide: =>
@isShown = false
@el.find('#chat_content').hide(100)
+ @el.find('#chat_content').addClass('hide')
@el.find('#chat_toogle').html('♦');
focusIn: =>
@@ -171,7 +173,7 @@ class App.ChatWidget extends App.Controller
shown = false
if @isShown
shown = true
- @html App.view('chat_widget')(
+ @html App.view('widget/chat')(
messages: @messageLog
isShown: shown
)
@@ -210,4 +212,4 @@ class App.ChatWidget extends App.Controller
)
@render()
-App.Config.set( 'chat', App.ChatWidget, 'Widgets' )
+App.Config.set( 'chat', Widget, 'Widgets' )
diff --git a/app/assets/javascripts/app/controllers/link_info_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/link.js.coffee
similarity index 83%
rename from app/assets/javascripts/app/controllers/link_info_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/link.js.coffee
index 1a07420b6..4231c9da1 100644
--- a/app/assets/javascripts/app/controllers/link_info_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/link.js.coffee
@@ -1,14 +1,14 @@
-class App.LinkInfo extends App.Controller
+class App.WidgetLink extends App.ControllerDrox
events:
'click [data-type=add]': 'add',
- 'click [data-type=edit]': 'edit',
+ 'click [data-type=edit]': 'toggle',
'click [data-type=remove]': 'remove',
constructor: ->
super
@fetch()
- fetch: () =>
+ fetch: =>
# fetch item on demand
# get data
@ajax(
@@ -27,9 +27,12 @@ class App.LinkInfo extends App.Controller
App.Event.trigger 'loadAssets', data.assets
@render()
+
+ if _.isEmpty(data.links)
+ @toggle()
)
- render: () =>
+ render: =>
list = {}
for item in @links
@@ -43,8 +46,12 @@ class App.LinkInfo extends App.Controller
list[ item['link_type'] ].push ticket
# insert data
- @html App.view('link/info')(
- links: list,
+ @html @template(
+ file: 'link/info'
+ header: 'Links'
+ edit: true
+ params:
+ links: list
)
# show edit mode once enabled
@@ -58,15 +65,16 @@ class App.LinkInfo extends App.Controller
# )
# enable/disable edit mode
- edit: (e) =>
- e.preventDefault()
+ toggle: (e) =>
+ if e
+ e.preventDefault()
@edit_mode = true
- if $(e.target).parent().parent().find('[data-type=add]').hasClass('hide')
- $(e.target).parent().parent().find('[data-type=remove]').removeClass('hide')
- $(e.target).parent().parent().find('[data-type=add]').removeClass('hide')
+ if @el.find('[data-type=add]').hasClass('hide')
+ @el.find('[data-type=remove]').removeClass('hide')
+ @el.find('[data-type=add]').removeClass('hide')
else
- $(e.target).parent().parent().find('[data-type=remove]').addClass('hide')
- $(e.target).parent().parent().find('[data-type=add]').addClass('hide')
+ @el.find('[data-type=remove]').addClass('hide')
+ @el.find('[data-type=add]').addClass('hide')
remove: (e) =>
e.preventDefault()
diff --git a/app/assets/javascripts/app/controllers/maintenance_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/maintenance.js.coffee
similarity index 84%
rename from app/assets/javascripts/app/controllers/maintenance_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/maintenance.js.coffee
index e28b5e8a2..125a5f127 100644
--- a/app/assets/javascripts/app/controllers/maintenance_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/maintenance.js.coffee
@@ -1,4 +1,4 @@
-class App.MaintenanceWidget extends App.Controller
+class Widget extends App.Controller
constructor: ->
super
@@ -31,4 +31,4 @@ class Message extends App.ControllerModal
forceReload: message.reload
)
-App.Config.set( 'maintenance', App.MaintenanceWidget, 'Widgets' )
+App.Config.set( 'maintenance', Widget, 'Widgets' )
diff --git a/app/assets/javascripts/app/controllers/widget/organization.js.coffee b/app/assets/javascripts/app/controllers/widget/organization.js.coffee
new file mode 100644
index 000000000..1809536c9
--- /dev/null
+++ b/app/assets/javascripts/app/controllers/widget/organization.js.coffee
@@ -0,0 +1,78 @@
+class App.WidgetOrganization extends App.Controller
+ events:
+ 'focusout [data-type=update-org]': 'update',
+ 'click [data-type=edit-org]': 'edit'
+
+ constructor: ->
+ super
+
+ # show organization
+ callback = (organization) =>
+ @render(organization)
+ if @callback
+ @callback(organization)
+
+ # subscribe and reload data / fetch new data if triggered
+ @subscribeId = organization.subscribe(@render)
+
+ App.Organization.retrieve( @organization_id, callback )
+
+ release: =>
+ App.Organization.unsubscribe(@subscribeId)
+
+ render: (organization) =>
+ if !organization
+ organization = @u
+
+ # get display data
+ organizationData = []
+ for item2 in App.Organization.configure_attributes
+ item = _.clone( item2 )
+
+ # check if value for _id exists
+ itemNameValue = item.name
+ itemNameValueNew = itemNameValue.substr( 0, itemNameValue.length - 3 )
+ if itemNameValueNew of organization
+ item.name = itemNameValueNew
+
+ # add to show if value exists
+ if organization[item.name] || item.tag is 'textarea'
+
+ # do not show name / already show via diplayName()
+ if item.name isnt 'name'
+ if item.info
+ organizationData.push item
+
+ # insert userData
+ @html App.view('widget/organization')(
+ organization: organization
+ organizationData: organizationData
+ )
+
+ ###
+ @userTicketPopups(
+ selector: '.user-tickets'
+ user_id: user.id
+ position: 'right'
+ )
+ ###
+
+ update: (e) =>
+ note = $(e.target).parent().find('[data-type=update]').val()
+ organization = App.Organization.find( @organization_id )
+ if organization.note isnt note
+ organization.updateAttributes( note: note )
+ @log 'notice', 'update', e, note, organization
+
+ edit: (e) =>
+ e.preventDefault()
+ new App.ControllerGenericEdit(
+ id: @organization_id,
+ genericObject: 'Organization',
+ pageData: {
+ title: 'Organizations',
+ object: 'Organization',
+ objects: 'Organizations',
+ },
+ callback: @render
+ )
diff --git a/app/assets/javascripts/app/controllers/tag_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/tag.js.coffee
similarity index 89%
rename from app/assets/javascripts/app/controllers/tag_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/tag.js.coffee
index f6b1a2075..e67b48a0b 100644
--- a/app/assets/javascripts/app/controllers/tag_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/tag.js.coffee
@@ -1,4 +1,4 @@
-class App.TagWidget extends App.Controller
+class App.WidgetTag extends App.Controller
constructor: ->
super
@load()
@@ -6,6 +6,8 @@ class App.TagWidget extends App.Controller
# update box size
@bind 'ui:rerender:content', =>
@siteUpdate()
+ @bind 'ui:rerender:task', =>
+ @siteUpdate()
load: =>
@attribute_id = 'tags_' + @object.id + '_' + @object_type
@@ -24,16 +26,16 @@ class App.TagWidget extends App.Controller
render: (tags) =>
# insert data
- @html App.view('tag_widget')(
+ @html App.view('widget/tag')(
tags: tags || [],
tag_id: @attribute_id
)
@el.find('#' + @attribute_id ).tagsInput(
- width: '150px'
+ width: '100%'
defaultText: App.i18n.translateContent('add a Tag')
onAddTag: @onAddTag
onRemoveTag: @onRemoveTag
-# height: '65px'
+ height: '45px'
)
@delay @siteUpdate, 250
diff --git a/app/assets/javascripts/app/controllers/template_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/template.js.coffee
similarity index 89%
rename from app/assets/javascripts/app/controllers/template_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/template.js.coffee
index c24661ba1..c2da4003e 100644
--- a/app/assets/javascripts/app/controllers/template_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/template.js.coffee
@@ -1,4 +1,4 @@
-class App.TemplateUI extends App.Controller
+class App.WidgetTemplate extends App.ControllerDrox
events:
'click [data-type=template_save]': 'create',
'click [data-type=template_select]': 'select',
@@ -21,8 +21,11 @@ class App.TemplateUI extends App.Controller
template = App.Template.find( @template_id )
# insert data
- @html App.view('template_widget')(
- template: template,
+ @html @template(
+ file: 'widget/template'
+ header: 'Templates'
+ params:
+ template: template
)
new App.ControllerForm(
el: @el.find('#form-template')
@@ -54,6 +57,7 @@ class App.TemplateUI extends App.Controller
e.preventDefault()
# get params
+ form = @formParam( $('.ticket-create') )
params = @formParam(e.target)
name = params['template_name']
# delete params['template_name']
@@ -62,10 +66,9 @@ class App.TemplateUI extends App.Controller
if !template
template = new App.Template
- options = params
template.load(
name: params['template_name']
- options: options
+ options: form
)
# validate form
diff --git a/app/assets/javascripts/app/controllers/text_module_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/text_module.js.coffee
similarity index 98%
rename from app/assets/javascripts/app/controllers/text_module_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/text_module.js.coffee
index fdd23daf0..eca0d8b79 100644
--- a/app/assets/javascripts/app/controllers/text_module_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/text_module.js.coffee
@@ -1,4 +1,4 @@
-class App.TextModuleUI extends App.Controller
+class App.WidgetTextModule extends App.Controller
constructor: ->
super
@@ -59,7 +59,7 @@ class App.TextModuleUI extends App.Controller
return values
-class App.TextModuleUIOld extends App.Controller
+class App.WidgetTextModuleOld extends App.Controller
events:
'click [data-type=save]': 'create',
'click [data-type=text_module_delete]': 'delete',
@@ -191,7 +191,7 @@ class App.TextModuleUIOld extends App.Controller
)
# insert data
- @html App.view('text_module_widget')(
+ @html App.view('widget/text_module')(
search: @search,
)
diff --git a/app/assets/javascripts/app/controllers/user_info_widget.js.coffee b/app/assets/javascripts/app/controllers/widget/user.js.coffee
similarity index 69%
rename from app/assets/javascripts/app/controllers/user_info_widget.js.coffee
rename to app/assets/javascripts/app/controllers/widget/user.js.coffee
index 326da3233..9016b5023 100644
--- a/app/assets/javascripts/app/controllers/user_info_widget.js.coffee
+++ b/app/assets/javascripts/app/controllers/widget/user.js.coffee
@@ -1,7 +1,7 @@
-class App.UserInfo extends App.Controller
+class App.WidgetUser extends App.ControllerDrox
events:
'focusout [data-type=update]': 'update',
- 'click [data-type=edit]': 'edit'
+ 'click [data-type=edit]': 'edit'
constructor: ->
super
@@ -25,7 +25,7 @@ class App.UserInfo extends App.Controller
user = @u
# get display data
- data = []
+ userData = []
for item2 in App.User.configure_attributes
item = _.clone( item2 )
@@ -36,25 +36,37 @@ class App.UserInfo extends App.Controller
item.name = itemNameValueNew
# add to show if value exists
- if user[item.name]
+ if user[item.name] || item.tag is 'textarea'
# do not show firstname and lastname / already show via diplayName()
- if item.name isnt 'firstname' && item.name isnt 'lastname' && item.name isnt 'organization'
+ if item.name isnt 'firstname' && item.name isnt 'lastname'
if item.info
- data.push item
+ userData.push item
- # insert data
- @html App.view('user_info')(
- user: user,
- data: data,
+ # insert userData
+ @html @template(
+ file: 'widget/user'
+ header: 'Customer'
+ edit: true
+ params:
+ user: user
+ userData: userData
)
@userTicketPopups(
- selector: '.user-tickets',
- user_id: user.id,
+ selector: '.user-tickets'
+ user_id: user.id
+ position: 'right'
)
- # update changes
+
+ if user.organization_id
+ @el.append('
')
+ new App.WidgetOrganization(
+ organization_id: user.organization_id
+ el: @el.find('.org-info')
+ )
+
update: (e) =>
note = $(e.target).parent().find('[data-type=update]').val()
user = App.User.find( @user_id )
diff --git a/app/assets/javascripts/app/index.js.coffee b/app/assets/javascripts/app/index.js.coffee
index ad4042f9f..b2874c142 100644
--- a/app/assets/javascripts/app/index.js.coffee
+++ b/app/assets/javascripts/app/index.js.coffee
@@ -42,7 +42,9 @@ class App extends Spine.Controller
# define linkify helper
params.L = ( item ) ->
- window.linkify( item )
+ if item && typeof item is 'string'
+ return window.linkify( item )
+ item
# define config helper
params.C = ( key ) ->
@@ -56,4 +58,4 @@ class App extends Spine.Controller
JST["app/views/#{name}"](params)
template
-window.App = App
\ No newline at end of file
+window.App = App
diff --git a/app/assets/javascripts/app/lib/app_post/collection.js.coffee b/app/assets/javascripts/app/lib/app_post/collection.js.coffee
index df2c55413..4c91a8ff1 100644
--- a/app/assets/javascripts/app/lib/app_post/collection.js.coffee
+++ b/app/assets/javascripts/app/lib/app_post/collection.js.coffee
@@ -25,18 +25,25 @@ class _collectionSingleton extends Spine.Module
for type, collections of data
if type is 'users'
type = 'User'
+ throw "BREAK, users"
if type is 'tickets'
type = 'Ticket'
+ throw "BREAK, tickets"
if type is 'ticket_article'
type = 'TicketArticle'
+ throw "BREAK, ticket_article"
if type is 'organization'
type = 'Organization'
+ throw "BREAK, organization"
if type is 'history_object'
type = 'HistoryObject'
+ throw "BREAK, history_object"
if type is 'history_type'
type = 'HistoryType'
+ throw "BREAK, history_type"
if type is 'history_attribute'
type = 'HistoryAttribute'
+ throw "BREAK, history_attribute"
@log 'debug', 'loadCollection:trigger', type, collections
@load( localStorage: data.localStorage, type: type, data: collections )
diff --git a/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee b/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee
index e46a890f0..49c372518 100644
--- a/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee
+++ b/app/assets/javascripts/app/lib/app_post/interface_handle.js.coffee
@@ -47,7 +47,7 @@ class App.Run extends App.Controller
App.Event.trigger( event + ':ready')
class App.Content extends App.Controller
- className: 'container'
+ className: 'content'
constructor: ->
super
diff --git a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee
index da9aa3a32..9aa54e6a5 100644
--- a/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee
+++ b/app/assets/javascripts/app/lib/app_post/task_manager.js.coffee
@@ -147,7 +147,7 @@ class _taskManagerSingleton extends App.Controller
# create div for permanent content
if !$("#content_permanent")[0]
- $('#app section').append('
')
+ $('#app section').append('
')
# empty static content if task is shown
if active
@@ -208,6 +208,7 @@ class _taskManagerSingleton extends App.Controller
worker = @worker( key )
if worker && worker.activate
worker.activate()
+ App.Event.trigger('ui:rerender:task')
# return if controller is already started
return if @workersStarted[key]
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js
deleted file mode 100644
index ce4599164..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/* ============================================================
- * bootstrap-button.js v2.3.2
- * 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.closest('[data-toggle="buttons-radio"]')
-
- $parent && $parent
- .find('.active')
- .removeClass('active')
-
- this.$element.toggleClass('active')
- }
-
-
- /* BUTTON PLUGIN DEFINITION
- * ======================== */
-
- var old = $.fn.button
-
- $.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 NO CONFLICT
- * ================== */
-
- $.fn.button.noConflict = function () {
- $.fn.button = old
- return this
- }
-
-
- /* BUTTON DATA-API
- * =============== */
-
- $(document).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);
\ No newline at end of file
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js
deleted file mode 100644
index 74a73a890..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js
+++ /dev/null
@@ -1,167 +0,0 @@
-/* =============================================================
- * bootstrap-collapse.js v2.3.2
- * 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 || this.$element.hasClass('in')) 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')
- $.support.transition && this.$element[dimension](this.$element[0][scroll])
- }
-
- , hide: function () {
- var dimension
- if (this.transitioning || !this.$element.hasClass('in')) 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']()
- }
-
- }
-
-
- /* COLLAPSE PLUGIN DEFINITION
- * ========================== */
-
- var old = $.fn.collapse
-
- $.fn.collapse = function (option) {
- return this.each(function () {
- var $this = $(this)
- , data = $this.data('collapse')
- , options = $.extend({}, $.fn.collapse.defaults, $this.data(), 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
-
-
- /* COLLAPSE NO CONFLICT
- * ==================== */
-
- $.fn.collapse.noConflict = function () {
- $.fn.collapse = old
- return this
- }
-
-
- /* COLLAPSE DATA-API
- * ================= */
-
- $(document).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()
- $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
- $(target).collapse(option)
- })
-
-}(window.jQuery);
\ No newline at end of file
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js
deleted file mode 100644
index 6cc122113..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js
+++ /dev/null
@@ -1,169 +0,0 @@
-/* ============================================================
- * bootstrap-dropdown.js v2.3.2
- * 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
- , isActive
-
- if ($this.is('.disabled, :disabled')) return
-
- $parent = getParent($this)
-
- isActive = $parent.hasClass('open')
-
- clearMenus()
-
- if (!isActive) {
- if ('ontouchstart' in document.documentElement) {
- // if mobile we we use a backdrop because click events don't delegate
- $('
').insertBefore($(this)).on('click', clearMenus)
- }
- $parent.toggleClass('open')
- }
-
- $this.focus()
-
- return false
- }
-
- , keydown: function (e) {
- var $this
- , $items
- , $active
- , $parent
- , isActive
- , index
-
- if (!/(38|40|27)/.test(e.keyCode)) return
-
- $this = $(this)
-
- e.preventDefault()
- e.stopPropagation()
-
- if ($this.is('.disabled, :disabled')) return
-
- $parent = getParent($this)
-
- isActive = $parent.hasClass('open')
-
- if (!isActive || (isActive && e.keyCode == 27)) {
- if (e.which == 27) $parent.find(toggle).focus()
- return $this.click()
- }
-
- $items = $('[role=menu] li:not(.divider):visible a', $parent)
-
- if (!$items.length) return
-
- index = $items.index($items.filter(':focus'))
-
- if (e.keyCode == 38 && index > 0) index-- // up
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
- if (!~index) index = 0
-
- $items
- .eq(index)
- .focus()
- }
-
- }
-
- function clearMenus() {
- $('.dropdown-backdrop').remove()
- $(toggle).each(function () {
- getParent($(this)).removeClass('open')
- })
- }
-
- function getParent($this) {
- var selector = $this.attr('data-target')
- , $parent
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
- }
-
- $parent = selector && $(selector)
-
- if (!$parent || !$parent.length) $parent = $this.parent()
-
- return $parent
- }
-
-
- /* DROPDOWN PLUGIN DEFINITION
- * ========================== */
-
- var old = $.fn.dropdown
-
- $.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
-
-
- /* DROPDOWN NO CONFLICT
- * ==================== */
-
- $.fn.dropdown.noConflict = function () {
- $.fn.dropdown = old
- return this
- }
-
-
- /* APPLY TO STANDARD DROPDOWN ELEMENTS
- * =================================== */
-
- $(document)
- .on('click.dropdown.data-api', clearMenus)
- .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
- .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
- .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
-
-}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js
deleted file mode 100644
index c3648d8b7..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js
+++ /dev/null
@@ -1,247 +0,0 @@
-/* =========================================================
- * bootstrap-modal.js v2.3.2
- * 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 (element, options) {
- this.options = options
- this.$element = $(element)
- .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
- this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
- }
-
- 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
-
- this.isShown = true
-
- this.escape()
-
- this.backdrop(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')
- .attr('aria-hidden', false)
-
- that.enforceFocus()
-
- transition ?
- that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
- that.$element.focus().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
-
- this.escape()
-
- $(document).off('focusin.modal')
-
- this.$element
- .removeClass('in')
- .attr('aria-hidden', true)
-
- $.support.transition && this.$element.hasClass('fade') ?
- this.hideWithTransition() :
- this.hideModal()
- }
-
- , enforceFocus: function () {
- var that = this
- $(document).on('focusin.modal', function (e) {
- if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
- that.$element.focus()
- }
- })
- }
-
- , escape: function () {
- var that = this
- if (this.isShown && this.options.keyboard) {
- this.$element.on('keyup.dismiss.modal', function ( e ) {
- e.which == 27 && that.hide()
- })
- } else if (!this.isShown) {
- this.$element.off('keyup.dismiss.modal')
- }
- }
-
- , hideWithTransition: function () {
- var that = this
- , timeout = setTimeout(function () {
- that.$element.off($.support.transition.end)
- that.hideModal()
- }, 500)
-
- this.$element.one($.support.transition.end, function () {
- clearTimeout(timeout)
- that.hideModal()
- })
- }
-
- , hideModal: function () {
- var that = this
- this.$element.hide()
- this.backdrop(function () {
- that.removeBackdrop()
- that.$element.trigger('hidden')
- })
- }
-
- , removeBackdrop: function () {
- this.$backdrop && this.$backdrop.remove()
- this.$backdrop = null
- }
-
- , backdrop: function (callback) {
- var that = this
- , animate = this.$element.hasClass('fade') ? 'fade' : ''
-
- if (this.isShown && this.options.backdrop) {
- var doAnimate = $.support.transition && animate
-
- this.$backdrop = $('
')
- .appendTo(document.body)
-
- this.$backdrop.click(
- this.options.backdrop == 'static' ?
- $.proxy(this.$element[0].focus, this.$element[0])
- : $.proxy(this.hide, this)
- )
-
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
-
- this.$backdrop.addClass('in')
-
- if (!callback) return
-
- 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, callback) :
- callback()
-
- } else if (callback) {
- callback()
- }
- }
- }
-
-
- /* MODAL PLUGIN DEFINITION
- * ======================= */
-
- var old = $.fn.modal
-
- $.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 NO CONFLICT
- * ================= */
-
- $.fn.modal.noConflict = function () {
- $.fn.modal = old
- return this
- }
-
-
- /* MODAL DATA-API
- * ============== */
-
- $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
- var $this = $(this)
- , href = $this.attr('href')
- , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
- , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
-
- e.preventDefault()
-
- $target
- .modal(option)
- .one('hide', function () {
- $this.focus()
- })
- })
-
-}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js
deleted file mode 100644
index e6a23d210..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/* ===========================================================
- * bootstrap-popover.js v2.3.2
- * 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.options.html ? 'html' : 'text'](title)
- $tip.find('.popover-content')[this.options.html ? '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 = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
- || $e.attr('data-content')
-
- return content
- }
-
- , tip: function () {
- if (!this.$tip) {
- this.$tip = $(this.options.template)
- }
- return this.$tip
- }
-
- , destroy: function () {
- this.hide().$element.off('.' + this.type).removeData(this.type)
- }
-
- })
-
-
- /* POPOVER PLUGIN DEFINITION
- * ======================= */
-
- var old = $.fn.popover
-
- $.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'
- , trigger: 'click'
- , content: ''
- , template: '
'
- })
-
-
- /* POPOVER NO CONFLICT
- * =================== */
-
- $.fn.popover.noConflict = function () {
- $.fn.popover = old
- return this
- }
-
-}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js
deleted file mode 100644
index a5161515a..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/* ========================================================
- * bootstrap-tab.js v2.3.2
- * 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:last a')[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
- * ===================== */
-
- var old = $.fn.tab
-
- $.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 NO CONFLICT
- * =============== */
-
- $.fn.tab.noConflict = function () {
- $.fn.tab = old
- return this
- }
-
-
- /* TAB DATA-API
- * ============ */
-
- $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
- e.preventDefault()
- $(this).tab('show')
- })
-
-}(window.jQuery);
\ No newline at end of file
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js
deleted file mode 100644
index a3bbd580b..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js
+++ /dev/null
@@ -1,361 +0,0 @@
-/* ===========================================================
- * bootstrap-tooltip.js v2.3.2
- * 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
- , triggers
- , trigger
- , i
-
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
- this.enabled = true
-
- triggers = this.options.trigger.split(' ')
-
- for (i = triggers.length; i--;) {
- trigger = triggers[i]
- if (trigger == 'click') {
- this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
- } else if (trigger != 'manual') {
- eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
- eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
- this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut + '.' + this.type, 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, this.$element.data(), options)
-
- if (options.delay && typeof options.delay == 'number') {
- options.delay = {
- show: options.delay
- , hide: options.delay
- }
- }
-
- return options
- }
-
- , enter: function (e) {
- var defaults = $.fn[this.type].defaults
- , options = {}
- , self
-
- this._options && $.each(this._options, function (key, value) {
- if (defaults[key] != value) options[key] = value
- }, this)
-
- self = $(e.currentTarget)[this.type](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
- , pos
- , actualWidth
- , actualHeight
- , placement
- , tp
- , e = $.Event('show')
-
- if (this.hasContent() && this.enabled) {
- this.$element.trigger(e)
- if (e.isDefaultPrevented()) return
- $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
-
- $tip
- .detach()
- .css({ top: 0, left: 0, display: 'block' })
-
- this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
-
- pos = this.getPosition()
-
- actualWidth = $tip[0].offsetWidth
- actualHeight = $tip[0].offsetHeight
-
- switch (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
- }
-
- this.applyPlacement(tp, placement)
- this.$element.trigger('shown')
- }
- }
-
- , applyPlacement: function(offset, placement){
- var $tip = this.tip()
- , width = $tip[0].offsetWidth
- , height = $tip[0].offsetHeight
- , actualWidth
- , actualHeight
- , delta
- , replace
-
- $tip
- .offset(offset)
- .addClass(placement)
- .addClass('in')
-
- actualWidth = $tip[0].offsetWidth
- actualHeight = $tip[0].offsetHeight
-
- if (placement == 'top' && actualHeight != height) {
- offset.top = offset.top + height - actualHeight
- replace = true
- }
-
- if (placement == 'bottom' || placement == 'top') {
- delta = 0
-
- if (offset.left < 0){
- delta = offset.left * -2
- offset.left = 0
- $tip.offset(offset)
- actualWidth = $tip[0].offsetWidth
- actualHeight = $tip[0].offsetHeight
- }
-
- this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
- } else {
- this.replaceArrow(actualHeight - height, actualHeight, 'top')
- }
-
- if (replace) $tip.offset(offset)
- }
-
- , replaceArrow: function(delta, dimension, position){
- this
- .arrow()
- .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
- }
-
- , setContent: function () {
- var $tip = this.tip()
- , title = this.getTitle()
-
- $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
- $tip.removeClass('fade in top bottom left right')
- }
-
- , hide: function () {
- var that = this
- , $tip = this.tip()
- , e = $.Event('hide')
-
- this.$element.trigger(e)
- if (e.isDefaultPrevented()) return
-
- $tip.removeClass('in')
-
- function removeWithAnimation() {
- var timeout = setTimeout(function () {
- $tip.off($.support.transition.end).detach()
- }, 500)
-
- $tip.one($.support.transition.end, function () {
- clearTimeout(timeout)
- $tip.detach()
- })
- }
-
- $.support.transition && this.$tip.hasClass('fade') ?
- removeWithAnimation() :
- $tip.detach()
-
- this.$element.trigger('hidden')
-
- return this
- }
-
- , 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') || '').attr('title', '')
- }
- }
-
- , hasContent: function () {
- return this.getTitle()
- }
-
- , getPosition: function () {
- var el = this.$element[0]
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
- width: el.offsetWidth
- , height: el.offsetHeight
- }, this.$element.offset())
- }
-
- , 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)
- }
-
- , arrow: function(){
- return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
- }
-
- , 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 (e) {
- var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
- self.tip().hasClass('in') ? self.hide() : self.show()
- }
-
- , destroy: function () {
- this.hide().$element.off('.' + this.type).removeData(this.type)
- }
-
- }
-
-
- /* TOOLTIP PLUGIN DEFINITION
- * ========================= */
-
- var old = $.fn.tooltip
-
- $.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: '
'
- , trigger: 'hover focus'
- , title: ''
- , delay: 0
- , html: false
- , container: false
- }
-
-
- /* TOOLTIP NO CONFLICT
- * =================== */
-
- $.fn.tooltip.noConflict = function () {
- $.fn.tooltip = old
- return this
- }
-
-}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js b/app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js
deleted file mode 100644
index e12cf6e5a..000000000
--- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/* ===================================================
- * bootstrap-transition.js v2.3.2
- * 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 ($) {
-
- "use strict"; // jshint ;_;
-
-
- /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
- * ======================================================= */
-
- $(function () {
-
- $.support.transition = (function () {
-
- var transitionEnd = (function () {
-
- var el = document.createElement('bootstrap')
- , transEndEventNames = {
- 'WebkitTransition' : 'webkitTransitionEnd'
- , 'MozTransition' : 'transitionend'
- , 'OTransition' : 'oTransitionEnd otransitionend'
- , 'transition' : 'transitionend'
- }
- , name
-
- for (name in transEndEventNames){
- if (el.style[name] !== undefined) {
- return transEndEventNames[name]
- }
- }
-
- }())
-
- return transitionEnd && {
- end: transitionEnd
- }
-
- })()
-
- })
-
-}(window.jQuery);
\ No newline at end of file
diff --git a/app/assets/javascripts/app/lib/bootstrap/button.js b/app/assets/javascripts/app/lib/bootstrap/button.js
new file mode 100644
index 000000000..fc73b555f
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/button.js
@@ -0,0 +1,109 @@
+/* ========================================================================
+ * Bootstrap: button.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#buttons
+ * ========================================================================
+ * Copyright 2013 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";
+
+ // BUTTON PUBLIC CLASS DEFINITION
+ // ==============================
+
+ var Button = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Button.DEFAULTS, options)
+ }
+
+ Button.DEFAULTS = {
+ loadingText: 'loading...'
+ }
+
+ Button.prototype.setState = function (state) {
+ var d = 'disabled'
+ var $el = this.$element
+ var val = $el.is('input') ? 'val' : 'html'
+ var data = $el.data()
+
+ state = state + 'Text'
+
+ if (!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.closest('[data-toggle="buttons"]')
+
+ if ($parent.length) {
+ var $input = this.$element.find('input')
+ .prop('checked', !this.$element.hasClass('active'))
+ .trigger('change')
+ if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active')
+ }
+
+ this.$element.toggleClass('active')
+ }
+
+
+ // BUTTON PLUGIN DEFINITION
+ // ========================
+
+ var old = $.fn.button
+
+ $.fn.button = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.button')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ $.fn.button.Constructor = Button
+
+
+ // BUTTON NO CONFLICT
+ // ==================
+
+ $.fn.button.noConflict = function () {
+ $.fn.button = old
+ return this
+ }
+
+
+ // BUTTON DATA-API
+ // ===============
+
+ $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
+ var $btn = $(e.target)
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+ $btn.button('toggle')
+ e.preventDefault()
+ })
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/collapse.js b/app/assets/javascripts/app/lib/bootstrap/collapse.js
new file mode 100644
index 000000000..92cc0bc76
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/collapse.js
@@ -0,0 +1,179 @@
+/* ========================================================================
+ * Bootstrap: collapse.js v3.0.0
+ * http://twbs.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";
+
+ // COLLAPSE PUBLIC CLASS DEFINITION
+ // ================================
+
+ var Collapse = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
+ this.transitioning = null
+
+ if (this.options.parent) this.$parent = $(this.options.parent)
+ if (this.options.toggle) this.toggle()
+ }
+
+ Collapse.DEFAULTS = {
+ toggle: true
+ }
+
+ Collapse.prototype.dimension = function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ Collapse.prototype.show = function () {
+ if (this.transitioning || this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('show.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var actives = this.$parent && this.$parent.find('> .panel > .in')
+
+ if (actives && actives.length) {
+ var hasData = actives.data('bs.collapse')
+ if (hasData && hasData.transitioning) return
+ actives.collapse('hide')
+ hasData || actives.data('bs.collapse', null)
+ }
+
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ .addClass('collapsing')
+ [dimension](0)
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.$element
+ .removeClass('collapsing')
+ .addClass('in')
+ [dimension]('auto')
+ this.transitioning = 0
+ this.$element.trigger('shown.bs.collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+ this.$element
+ .one($.support.transition.end, $.proxy(complete, this))
+ .emulateTransitionEnd(350)
+ [dimension](this.$element[0][scrollSize])
+ }
+
+ Collapse.prototype.hide = function () {
+ if (this.transitioning || !this.$element.hasClass('in')) return
+
+ var startEvent = $.Event('hide.bs.collapse')
+ this.$element.trigger(startEvent)
+ if (startEvent.isDefaultPrevented()) return
+
+ var dimension = this.dimension()
+
+ this.$element
+ [dimension](this.$element[dimension]())
+ [0].offsetHeight
+
+ this.$element
+ .addClass('collapsing')
+ .removeClass('collapse')
+ .removeClass('in')
+
+ this.transitioning = 1
+
+ var complete = function () {
+ this.transitioning = 0
+ this.$element
+ .trigger('hidden.bs.collapse')
+ .removeClass('collapsing')
+ .addClass('collapse')
+ }
+
+ if (!$.support.transition) return complete.call(this)
+
+ this.$element
+ [dimension](0)
+ .one($.support.transition.end, $.proxy(complete, this))
+ .emulateTransitionEnd(350)
+ }
+
+ Collapse.prototype.toggle = function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+
+ // COLLAPSE PLUGIN DEFINITION
+ // ==========================
+
+ var old = $.fn.collapse
+
+ $.fn.collapse = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.collapse')
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.collapse.Constructor = Collapse
+
+
+ // COLLAPSE NO CONFLICT
+ // ====================
+
+ $.fn.collapse.noConflict = function () {
+ $.fn.collapse = old
+ return this
+ }
+
+
+ // COLLAPSE DATA-API
+ // =================
+
+ $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
+ var $this = $(this), href
+ var target = $this.attr('data-target')
+ || e.preventDefault()
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+ var $target = $(target)
+ var data = $target.data('bs.collapse')
+ var option = data ? 'toggle' : $this.data()
+ var parent = $this.attr('data-parent')
+ var $parent = parent && $(parent)
+
+ if (!data || !data.transitioning) {
+ if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
+ $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
+ }
+
+ $target.collapse(option)
+ })
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/dropdown.js b/app/assets/javascripts/app/lib/bootstrap/dropdown.js
new file mode 100644
index 000000000..6093f11a8
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/dropdown.js
@@ -0,0 +1,154 @@
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.0.0
+ * http://twbs.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";
+
+ // DROPDOWN CLASS DEFINITION
+ // =========================
+
+ var backdrop = '.dropdown-backdrop'
+ var toggle = '[data-toggle=dropdown]'
+ var Dropdown = function (element) {
+ var $el = $(element).on('click.bs.dropdown', this.toggle)
+ }
+
+ Dropdown.prototype.toggle = function (e) {
+ var $this = $(this)
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ clearMenus()
+
+ if (!isActive) {
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+ // if mobile we we use a backdrop because click events don't delegate
+ $('
').insertAfter($(this)).on('click', clearMenus)
+ }
+
+ $parent.trigger(e = $.Event('show.bs.dropdown'))
+
+ if (e.isDefaultPrevented()) return
+
+ $parent
+ .toggleClass('open')
+ .trigger('shown.bs.dropdown')
+
+ $this.focus()
+ }
+
+ return false
+ }
+
+ Dropdown.prototype.keydown = function (e) {
+ if (!/(38|40|27)/.test(e.keyCode)) return
+
+ var $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ if (!isActive || (isActive && e.keyCode == 27)) {
+ if (e.which == 27) $parent.find(toggle).focus()
+ return $this.click()
+ }
+
+ var $items = $('[role=menu] li:not(.divider):visible a', $parent)
+
+ if (!$items.length) return
+
+ var index = $items.index($items.filter(':focus'))
+
+ if (e.keyCode == 38 && index > 0) index-- // up
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index=0
+
+ $items.eq(index).focus()
+ }
+
+ function clearMenus() {
+ $(backdrop).remove()
+ $(toggle).each(function (e) {
+ var $parent = getParent($(this))
+ if (!$parent.hasClass('open')) return
+ $parent.trigger(e = $.Event('hide.bs.dropdown'))
+ if (e.isDefaultPrevented()) return
+ $parent.removeClass('open').trigger('hidden.bs.dropdown')
+ })
+ }
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ var $parent = selector && $(selector)
+
+ return $parent && $parent.length ? $parent : $this.parent()
+ }
+
+
+ // DROPDOWN PLUGIN DEFINITION
+ // ==========================
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var 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
+
+
+ // DROPDOWN NO CONFLICT
+ // ====================
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
+ // ===================================
+
+ $(document)
+ .on('click.bs.dropdown.data-api', clearMenus)
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
+ .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/modal.js b/app/assets/javascripts/app/lib/bootstrap/modal.js
new file mode 100644
index 000000000..65eba481e
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/modal.js
@@ -0,0 +1,246 @@
+/* ========================================================================
+ * Bootstrap: modal.js v3.0.0
+ * http://twbs.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";
+
+ // MODAL CLASS DEFINITION
+ // ======================
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$element = $(element)
+ this.$backdrop =
+ this.isShown = null
+
+ if (this.options.remote) this.$element.load(this.options.remote)
+ }
+
+ Modal.DEFAULTS = {
+ backdrop: true
+ , keyboard: true
+ , show: true
+ }
+
+ Modal.prototype.toggle = function (_relatedTarget) {
+ return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
+ }
+
+ Modal.prototype.show = function (_relatedTarget) {
+ var that = this
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.escape()
+
+ this.$element.on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+ this.backdrop(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')
+ .attr('aria-hidden', false)
+
+ that.enforceFocus()
+
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+ transition ?
+ that.$element.find('.modal-dialog') // wait for modal to slide in
+ .one($.support.transition.end, function () {
+ that.$element.focus().trigger(e)
+ })
+ .emulateTransitionEnd(300) :
+ that.$element.focus().trigger(e)
+ })
+ }
+
+ Modal.prototype.hide = function (e) {
+ if (e) e.preventDefault()
+
+ e = $.Event('hide.bs.modal')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+
+ $(document).off('focusin.bs.modal')
+
+ this.$element
+ .removeClass('in')
+ .attr('aria-hidden', true)
+ .off('click.dismiss.modal')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$element
+ .one($.support.transition.end, $.proxy(this.hideModal, this))
+ .emulateTransitionEnd(300) :
+ this.hideModal()
+ }
+
+ Modal.prototype.enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', $.proxy(function (e) {
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+ this.$element.focus()
+ }
+ }, this))
+ }
+
+ Modal.prototype.escape = function () {
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
+ e.which == 27 && this.hide()
+ }, this))
+ } else if (!this.isShown) {
+ this.$element.off('keyup.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.hideModal = function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.removeBackdrop()
+ that.$element.trigger('hidden.bs.modal')
+ })
+ }
+
+ Modal.prototype.removeBackdrop = function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ Modal.prototype.backdrop = function (callback) {
+ var that = this
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $('
')
+ .appendTo(document.body)
+
+ this.$element.on('click.dismiss.modal', $.proxy(function (e) {
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus.call(this.$element[0])
+ : this.hide.call(this)
+ }, this))
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop
+ .one($.support.transition.end, callback)
+ .emulateTransitionEnd(150) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade')?
+ this.$backdrop
+ .one($.support.transition.end, callback)
+ .emulateTransitionEnd(150) :
+ callback()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+
+ // MODAL PLUGIN DEFINITION
+ // =======================
+
+ var old = $.fn.modal
+
+ $.fn.modal = function (option, _relatedTarget) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.modal')
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option](_relatedTarget)
+ else if (options.show) data.show(_relatedTarget)
+ })
+ }
+
+ $.fn.modal.Constructor = Modal
+
+
+ // MODAL NO CONFLICT
+ // =================
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ // MODAL DATA-API
+ // ==============
+
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ var href = $this.attr('href')
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+ var option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+ e.preventDefault()
+
+ $target
+ .modal(option, this)
+ .one('hide', function () {
+ $this.is(':visible') && $this.focus()
+ })
+ })
+
+ $(document)
+ .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
+ .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/popover.js b/app/assets/javascripts/app/lib/bootstrap/popover.js
new file mode 100644
index 000000000..ecd37ac23
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/popover.js
@@ -0,0 +1,117 @@
+/* ========================================================================
+ * Bootstrap: popover.js v3.0.0
+ * http://twbs.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";
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.DEFAULTS = $.extend({} , $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right'
+ , trigger: 'click'
+ , content: ''
+ , template: '
'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.arrow')
+ }
+
+ Popover.prototype.tip = function () {
+ if (!this.$tip) this.$tip = $(this.options.template)
+ return this.$tip
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.popover
+
+ $.fn.popover = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/tab.js b/app/assets/javascripts/app/lib/bootstrap/tab.js
new file mode 100644
index 000000000..e1c155920
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/tab.js
@@ -0,0 +1,135 @@
+/* ========================================================================
+ * Bootstrap: tab.js v3.0.0
+ * http://twbs.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";
+
+ // TAB CLASS DEFINITION
+ // ====================
+
+ var Tab = function (element) {
+ this.element = $(element)
+ }
+
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ if ($this.parent('li').hasClass('active')) return
+
+ var previous = $ul.find('.active:last a')[0]
+ var e = $.Event('show.bs.tab', {
+ relatedTarget: previous
+ })
+
+ $this.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ var $target = $(selector)
+
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown.bs.tab'
+ , relatedTarget: previous
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var 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)
+ .emulateTransitionEnd(150) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ var old = $.fn.tab
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
+ })
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/tooltip.js b/app/assets/javascripts/app/lib/bootstrap/tooltip.js
new file mode 100644
index 000000000..89802287a
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/tooltip.js
@@ -0,0 +1,386 @@
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tooltip
+ * 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";
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type =
+ this.options =
+ this.enabled =
+ this.timeout =
+ this.hoverState =
+ this.$element = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.DEFAULTS = {
+ animation: true
+ , placement: 'top'
+ , selector: false
+ , template: '
'
+ , trigger: 'hover focus'
+ , title: ''
+ , delay: 0
+ , html: false
+ , container: false
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay
+ , hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.'+ this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ var $tip = this.tip()
+
+ this.setContent()
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var $parent = this.$element.parent()
+
+ var orgPlacement = placement
+ var docScroll = document.documentElement.scrollTop || document.body.scrollTop
+ var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
+ var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+ var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
+
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
+ placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
+ placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+ this.$element.trigger('shown.bs.' + this.type)
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function(offset, placement) {
+ var replace
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
+
+ $tip
+ .offset(offset)
+ .addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ replace = true
+ offset.top = offset.top + height - actualHeight
+ }
+
+ if (/bottom|top/.test(placement)) {
+ var delta = 0
+
+ if (offset.left < 0) {
+ delta = offset.left * -2
+ offset.left = 0
+
+ $tip.offset(offset)
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+ }
+
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+ } else {
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
+ }
+
+ if (replace) $tip.offset(offset)
+ }
+
+ Tooltip.prototype.replaceArrow = function(delta, dimension, position) {
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function () {
+ var that = this
+ var $tip = this.tip()
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
+
+ this.$element.trigger('hidden.bs.' + this.type)
+
+ return this
+ }
+
+ Tooltip.prototype.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') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function () {
+ var el = this.$element[0]
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth
+ , height: el.offsetHeight
+ }, this.$element.offset())
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.tip = function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+ }
+
+ Tooltip.prototype.validate = function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+
+ Tooltip.prototype.destroy = function () {
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/lib/bootstrap/transition.js b/app/assets/javascripts/app/lib/bootstrap/transition.js
new file mode 100644
index 000000000..e8f318beb
--- /dev/null
+++ b/app/assets/javascripts/app/lib/bootstrap/transition.js
@@ -0,0 +1,56 @@
+/* ========================================================================
+ * Bootstrap: transition.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#transitions
+ * ========================================================================
+ * Copyright 2013 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";
+
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+ // ============================================================
+
+ function transitionEnd() {
+ var el = document.createElement('bootstrap')
+
+ var transEndEventNames = {
+ 'WebkitTransition' : 'webkitTransitionEnd'
+ , 'MozTransition' : 'transitionend'
+ , 'OTransition' : 'oTransitionEnd otransitionend'
+ , 'transition' : 'transitionend'
+ }
+
+ for (var name in transEndEventNames) {
+ if (el.style[name] !== undefined) {
+ return { end: transEndEventNames[name] }
+ }
+ }
+ }
+
+ // http://blog.alexmaccaw.com/css-transitions
+ $.fn.emulateTransitionEnd = function (duration) {
+ var called = false, $el = this
+ $(this).one($.support.transition.end, function () { called = true })
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+ setTimeout(callback, duration)
+ return this
+ }
+
+ $(function () {
+ $.support.transition = transitionEnd()
+ })
+
+}(window.jQuery);
diff --git a/app/assets/javascripts/app/models/_application_model.js.coffee b/app/assets/javascripts/app/models/_application_model.js.coffee
index 0bc429b4f..2e0340f5b 100644
--- a/app/assets/javascripts/app/models/_application_model.js.coffee
+++ b/app/assets/javascripts/app/models/_application_model.js.coffee
@@ -13,6 +13,9 @@ class App.Model extends Spine.Model
App.Store.delete(key)
)
+ uiUrl: ->
+ '#'
+
displayName: ->
return @name if @name
if @realname
@@ -26,6 +29,10 @@ class App.Model extends Spine.Model
return name
if @email
return @email
+ if @title
+ return @title
+ if @subject
+ return @subject
return '???'
displayNameLong: ->
diff --git a/app/assets/javascripts/app/models/group.js.coffee b/app/assets/javascripts/app/models/group.js.coffee
index 2336dd463..7ad3f1be6 100644
--- a/app/assets/javascripts/app/models/group.js.coffee
+++ b/app/assets/javascripts/app/models/group.js.coffee
@@ -17,3 +17,6 @@ class App.Group extends App.Model
@configure_overview = [
'name',
]
+
+ uiUrl: ->
+ '#group/zoom/' + @id
\ No newline at end of file
diff --git a/app/assets/javascripts/app/models/history.js.coffee b/app/assets/javascripts/app/models/history.js.coffee
deleted file mode 100644
index 9b82b5699..000000000
--- a/app/assets/javascripts/app/models/history.js.coffee
+++ /dev/null
@@ -1,20 +0,0 @@
-class App.History extends App.Model
- @configure 'History', 'name'
- @extend Spine.Model.Ajax
- @url: @apiPath + '/histories'
-
- @_fillUp: (data) ->
-
- # add user
- data.created_by = App.User.find( data.created_by_id )
-
- # add possible actions
- if data.history_attribute_id
- data.attribute = App.HistoryAttribute.find( data.history_attribute_id )
- if data.history_type_id
- data.type = App.HistoryType.find( data.history_type_id )
- if data.history_object_id
- data.object = App.HistoryObject.find( data.history_object_id )
-
- return data
-
diff --git a/app/assets/javascripts/app/models/history_attributes.js.coffee b/app/assets/javascripts/app/models/history_attributes.js.coffee
deleted file mode 100644
index 8c314c1dd..000000000
--- a/app/assets/javascripts/app/models/history_attributes.js.coffee
+++ /dev/null
@@ -1,4 +0,0 @@
-class App.HistoryAttribute extends App.Model
- @configure 'HistoryAttribute', 'name'
- @extend Spine.Model.Ajax
- @url: @apiPath + '/history_attributes'
diff --git a/app/assets/javascripts/app/models/history_object.js.coffee b/app/assets/javascripts/app/models/history_object.js.coffee
deleted file mode 100644
index 9d03058d0..000000000
--- a/app/assets/javascripts/app/models/history_object.js.coffee
+++ /dev/null
@@ -1,4 +0,0 @@
-class App.HistoryObject extends App.Model
- @configure 'HistoryObject', 'name'
- @extend Spine.Model.Ajax
- @url: @apiPath + '/history_objects'
diff --git a/app/assets/javascripts/app/models/history_type.js.coffee b/app/assets/javascripts/app/models/history_type.js.coffee
deleted file mode 100644
index 0865e9e23..000000000
--- a/app/assets/javascripts/app/models/history_type.js.coffee
+++ /dev/null
@@ -1,4 +0,0 @@
-class App.HistoryType extends App.Model
- @configure 'HistoryType', 'name'
- @extend Spine.Model.Ajax
- @url: @apiPath + '/history_types'
diff --git a/app/assets/javascripts/app/models/organization.js.coffee b/app/assets/javascripts/app/models/organization.js.coffee
index 0f4e15bd5..4de1a3b22 100644
--- a/app/assets/javascripts/app/models/organization.js.coffee
+++ b/app/assets/javascripts/app/models/organization.js.coffee
@@ -3,17 +3,20 @@ class App.Organization extends App.Model
@extend Spine.Model.Ajax
@url: @apiPath + '/organizations'
@configure_attributes = [
- { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, 'class': 'span4' },
- { name: 'shared', display: 'Shared organiztion', tag: 'boolean', note: 'Customers in the organiztion can view each other items.', type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
- { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' },
- { name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
- { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, 'class': 'span4' },
+ { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, 'null': false, info: true, 'class': 'span4' },
+ { name: 'shared', display: 'Shared organiztion', tag: 'boolean', note: 'Customers in the organiztion can view each other items.', type: 'boolean', 'default': true, 'null': false, info: false, 'class': 'span4' },
+ { name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, info: true, 'class': 'span4' },
+ { name: 'updated_at', display: 'Updated', type: 'time', readonly: 1, info: false },
+ { name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, 'null': false, info: false, 'class': 'span4' },
]
@configure_overview = [
'name',
'shared',
]
+ uiUrl: ->
+ '#organization/zoom/' + @id
+
@_fillUp: (data) ->
# addd users of organization
@@ -23,4 +26,4 @@ class App.Organization extends App.Model
if App.User.exists( user_id )
user = App.User.find( user_id )
data['user_ids'].push user
- data
\ No newline at end of file
+ data
diff --git a/app/assets/javascripts/app/models/overview.js.coffee b/app/assets/javascripts/app/models/overview.js.coffee
index 90da9c1af..626b0b5f4 100644
--- a/app/assets/javascripts/app/models/overview.js.coffee
+++ b/app/assets/javascripts/app/models/overview.js.coffee
@@ -11,7 +11,7 @@ class App.Overview extends App.Model
# { name: 'content', display: 'Content', tag: 'textarea', limit: 250, 'null': false, 'class': 'span4' },
{ name: 'condition', display: 'Conditions for shown Tickets', tag: 'ticket_attribute_selection', null: true, class: 'span4' },
{ name: 'prio', display: 'Prio', tag: 'input', type: 'text', limit: 10, 'null': false, 'class': 'span4' },
- {
+ {
name: 'view::s'
display: 'Attributes'
tag: 'checkbox'
@@ -60,7 +60,7 @@ class App.Overview extends App.Model
article_count: 'Article Count'
class: 'span4'
},
- {
+ {
name: 'order::direction'
display: 'Direction'
tag: 'select'
@@ -72,7 +72,7 @@ class App.Overview extends App.Model
DESC: 'down'
class: 'span4'
},
- {
+ {
name: 'group_by'
display: 'Group by'
tag: 'select'
diff --git a/app/assets/javascripts/app/models/ticket.js.coffee b/app/assets/javascripts/app/models/ticket.js.coffee
index 0dcea0da6..f7e585bac 100644
--- a/app/assets/javascripts/app/models/ticket.js.coffee
+++ b/app/assets/javascripts/app/models/ticket.js.coffee
@@ -20,6 +20,9 @@ class App.Ticket extends App.Model
{ name: 'article_count', display: 'Article#', style: 'width: 12%' },
]
+ uiUrl: ->
+ '#ticket/zoom/' + @id
+
@_fillUp: (data) ->
# priority
diff --git a/app/assets/javascripts/app/models/ticket_article.js.coffee b/app/assets/javascripts/app/models/ticket_article.js.coffee
index 2fa16dd27..4870f4d4d 100644
--- a/app/assets/javascripts/app/models/ticket_article.js.coffee
+++ b/app/assets/javascripts/app/models/ticket_article.js.coffee
@@ -14,6 +14,9 @@ class App.TicketArticle extends App.Model
{ name: 'internal', display: 'Visibility', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' }, class: 'medium' },
]
+ uiUrl: ->
+ '#ticket/zoom/' + @ticket_id + '/' + @id
+
@_fillUp: (data) ->
# add created & updated
diff --git a/app/assets/javascripts/app/models/user.js.coffee b/app/assets/javascripts/app/models/user.js.coffee
index e8551d42f..2868a32e7 100644
--- a/app/assets/javascripts/app/models/user.js.coffee
+++ b/app/assets/javascripts/app/models/user.js.coffee
@@ -30,6 +30,9 @@ class App.User extends App.Model
'login', 'firstname', 'lastname',
]
+ uiUrl: ->
+ '#user/zoom/' + @id
+
@_fillUp: (data) ->
# set socal media links
diff --git a/app/assets/javascripts/app/views/agent_ticket_create.jst.eco b/app/assets/javascripts/app/views/agent_ticket_create.jst.eco
index 9a237bc61..70cd905b2 100644
--- a/app/assets/javascripts/app/views/agent_ticket_create.jst.eco
+++ b/app/assets/javascripts/app/views/agent_ticket_create.jst.eco
@@ -1,21 +1,26 @@
-