sidekiq_monitor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +180 -0
  3. data/Rakefile +12 -0
  4. data/app/assets/javascripts/sidekiq/monitor/abstract_jobs_table.js.coffee +165 -0
  5. data/app/assets/javascripts/sidekiq/monitor/application.js.coffee +11 -0
  6. data/app/assets/javascripts/sidekiq/monitor/bootstrap-select.min.js +1 -0
  7. data/app/assets/javascripts/sidekiq/monitor/bootstrap.min.js +6 -0
  8. data/app/assets/javascripts/sidekiq/monitor/datatables.bootstrap.js +96 -0
  9. data/app/assets/javascripts/sidekiq/monitor/datatables.js +256 -0
  10. data/app/assets/javascripts/sidekiq/monitor/datatables.standing_redraw.js.coffee +5 -0
  11. data/app/assets/javascripts/sidekiq/monitor/initialize.js.coffee.erb +5 -0
  12. data/app/assets/javascripts/sidekiq/monitor/jobs_table.js.coffee +59 -0
  13. data/app/assets/javascripts/sidekiq/monitor/jquery.timeago.js +27 -0
  14. data/app/assets/javascripts/sidekiq/monitor/queue_jobs_table.js.coffee +92 -0
  15. data/app/assets/stylesheets/sidekiq/monitor/application.css.sass +5 -0
  16. data/app/assets/stylesheets/sidekiq/monitor/bootstrap-select.min.css +1 -0
  17. data/app/assets/stylesheets/sidekiq/monitor/bootstrap.min.css +9 -0
  18. data/app/assets/stylesheets/sidekiq/monitor/jobs_table.css.sass +51 -0
  19. data/app/assets/stylesheets/sidekiq/monitor/layout.css.sass +15 -0
  20. data/app/controllers/sidekiq/monitor/api/jobs_controller.rb +32 -0
  21. data/app/controllers/sidekiq/monitor/api/queues_controller.rb +24 -0
  22. data/app/controllers/sidekiq/monitor/jobs_controller.rb +14 -0
  23. data/app/controllers/sidekiq/monitor/queues_controller.rb +15 -0
  24. data/app/datatables/sidekiq/monitor/jobs_datatable.rb +74 -0
  25. data/app/helpers/sidekiq/monitor/sidekiq_helper.rb +13 -0
  26. data/app/models/sidekiq/monitor/job.rb +37 -0
  27. data/app/views/sidekiq/monitor/jobs/_jobs.slim +13 -0
  28. data/app/views/sidekiq/monitor/jobs/index.slim +1 -0
  29. data/app/views/sidekiq/monitor/layouts/application.slim +28 -0
  30. data/app/views/sidekiq/monitor/queues/_jobs.slim +13 -0
  31. data/app/views/sidekiq/monitor/queues/index.slim +6 -0
  32. data/config/routes.rb +10 -0
  33. data/lib/generators/sidekiq/monitor/install/install_generator.rb +27 -0
  34. data/lib/generators/sidekiq/monitor/install/templates/create_sidekiq_jobs.rb +26 -0
  35. data/lib/sidekiq/monitor/cleaner.rb +58 -0
  36. data/lib/sidekiq/monitor/client/middleware.rb +16 -0
  37. data/lib/sidekiq/monitor/engine.rb +11 -0
  38. data/lib/sidekiq/monitor/processor.rb +73 -0
  39. data/lib/sidekiq/monitor/server/middleware.rb +22 -0
  40. data/lib/sidekiq/monitor/version.rb +5 -0
  41. data/lib/sidekiq/monitor.rb +26 -0
  42. data/lib/sidekiq_monitor.rb +1 -0
  43. metadata +135 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 SocialPandas
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,180 @@
1
+ Sidekiq Monitor
2
+ ===============
3
+ Advanced monitoring for Sidekiq
4
+
5
+ Description
6
+ -----------
7
+ Sidekiq Monitor offers a detailed, malleable UI for monitoring Sidekiq jobs.
8
+
9
+ It lets you:
10
+
11
+ * Sort jobs by:
12
+ * Queue
13
+ * Class
14
+ * Queued at time
15
+ * Started at time
16
+ * Duration
17
+ * Status (e.g. queued, running, complete, failed)
18
+ * Filter jobs by:
19
+ * Queue
20
+ * Class
21
+ * Status
22
+ * Set and view metadata for each job:
23
+ * Name - A customizable, human-readable name (e.g. 'Data Import for John Doe')
24
+ * Result - A customizable value describing the job's result (e.g. '{imported\_documents\_count: 241, imported\_contacts_count: 183}')
25
+ * View errors for failed jobs, including a backtrace
26
+ * Easily isolate long-running jobs and failed jobs
27
+ * Retry failed jobs via a button-click
28
+
29
+ And it looks like this:
30
+
31
+ [<img src="https://raw.github.com/socialpandas/sidekiq_monitor/master/examples/screenshot.png" />](https://raw.github.com/socialpandas/sidekiq_monitor/master/examples/screenshot.png)
32
+
33
+ Installation
34
+ ------------
35
+
36
+ Add sidekiq_monitor to your Gemfile:
37
+
38
+ gem 'sidekiq_monitor'
39
+
40
+ Install and run the migration:
41
+
42
+ rails g sidekiq:monitor:install
43
+ rake db:migrate
44
+
45
+ Mount it at a customizable path in `routes.rb`:
46
+
47
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
48
+
49
+ Usage
50
+ -----
51
+
52
+ ### Setting a Job Name
53
+
54
+ To set a job's name (which makes the job's representation in the UI more human-readable), define a `self.job_name` method on your worker that takes the same arguments as its `perform` method:
55
+
56
+ ```ruby
57
+ class HardWorker
58
+ include Sidekiq::Worker
59
+
60
+ def perform(user_id)
61
+ puts 'Doing hard work'
62
+ end
63
+
64
+ def self.job_name(user_id)
65
+ User.find(user_id).username
66
+ end
67
+ end
68
+ ```
69
+
70
+ ### Setting a Job Result
71
+
72
+ To set a job's result (which can show what the job accomplished, for example), return a hash from the worker's `perform` method:
73
+
74
+ ```ruby
75
+ class HardWorker
76
+ include Sidekiq::Worker
77
+
78
+ def perform(user_ids)
79
+ puts 'Doing hard work'
80
+ { processed_users_count: user_ids.length }
81
+ end
82
+ end
83
+ ```
84
+
85
+ ### Authentication
86
+
87
+ You'll likely want to restrict access to this interface in a production setting. To do this, you can use routing constraints:
88
+
89
+ #### Devise
90
+
91
+ Checks a `User` model instance that responds to `admin?`
92
+
93
+ ```ruby
94
+ constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? }
95
+ constraints constraint do
96
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
97
+ end
98
+ ```
99
+
100
+ Allow any authenticated `User`
101
+
102
+ ```ruby
103
+ constraint = lambda { |request| request.env['warden'].authenticate!({ scope: :user }) }
104
+ constraints constraint do
105
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
106
+ end
107
+ ```
108
+
109
+ Short version
110
+
111
+ ```ruby
112
+ authenticate :user do
113
+ mount Sidekiq::Monitor::Engine => '/sidekiq'
114
+ end
115
+ ```
116
+
117
+ #### Authlogic
118
+
119
+ ```ruby
120
+ # lib/admin_constraint.rb
121
+ class AdminConstraint
122
+ def matches?(request)
123
+ return false unless request.cookies['user_credentials'].present?
124
+ user = User.find_by_persistence_token(request.cookies['user_credentials'].split(':')[0])
125
+ user && user.admin?
126
+ end
127
+ end
128
+
129
+ # config/routes.rb
130
+ require "admin_constraint"
131
+ mount Sidekiq::Monitor::Engine => '/sidekiq', :constraints => AdminConstraint.new
132
+ ```
133
+
134
+ #### Restful Authentication
135
+
136
+ Checks a `User` model instance that responds to `admin?`
137
+
138
+ ```
139
+ # lib/admin_constraint.rb
140
+ class AdminConstraint
141
+ def matches?(request)
142
+ return false unless request.session[:user_id]
143
+ user = User.find request.session[:user_id]
144
+ user && user.admin?
145
+ end
146
+ end
147
+
148
+ # config/routes.rb
149
+ require "admin_constraint"
150
+ mount Sidekiq::Monitor::Engine => '/sidekiq', :constraints => AdminConstraint.new
151
+ ```
152
+
153
+ #### Custom External Authentication
154
+
155
+ ```ruby
156
+ class AuthConstraint
157
+ def self.admin?(request)
158
+ return false unless (cookie = request.cookies['auth'])
159
+
160
+ Rails.cache.fetch(cookie['user'], :expires_in => 1.minute) do
161
+ auth_data = JSON.parse(Base64.decode64(cookie['data']))
162
+ response = HTTParty.post(Auth.validate_url, :query => auth_data)
163
+
164
+ response.code == 200 && JSON.parse(response.body)['roles'].to_a.include?('Admin')
165
+ end
166
+ end
167
+ end
168
+
169
+ # config/routes.rb
170
+ constraints lambda {|request| AuthConstraint.admin?(request) } do
171
+ mount Sidekiq::Monitor::Engine => '/admin/sidekiq'
172
+ end
173
+ ```
174
+
175
+ _(This authentication documentation was borrowed from the [Sidekiq wiki](https://github.com/mperham/sidekiq/wiki/Monitoring).)_
176
+
177
+ License
178
+ -------
179
+
180
+ Sidekiq Monitor is released under the MIT License. Please see the MIT-LICENSE file for details.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << "lib"
9
+ t.libs << "test"
10
+ t.test_files = FileList["test/**/*_test.rb"]
11
+ t.verbose = true
12
+ end
@@ -0,0 +1,165 @@
1
+ class SidekiqMonitor.AbstractJobsTable
2
+
3
+ constructor: ->
4
+ @api_params = {}
5
+ @initialize()
6
+
7
+ initialize_with_options: (options) =>
8
+ @options = options
9
+ @table = $(@options.table_selector)
10
+
11
+ @columns = @options.columns
12
+ @status_filter = null
13
+
14
+ $.getJSON SidekiqMonitor.settings.api_url('jobs/clean')
15
+
16
+ @table.dataTable
17
+ bProcessing: true
18
+ bServerSide: true
19
+ sAjaxSource: @table.data('source')
20
+ iDisplayLength: 10
21
+ aaSorting: [[@columns.enqueued_at, 'desc']]
22
+ sPaginationType: 'bootstrap'
23
+ aoColumns: @options.column_options
24
+ oLanguage:
25
+ sInfo: '_TOTAL_ jobs'
26
+ sInfoFiltered: ' (filtered from _MAX_)'
27
+ sLengthMenu: 'Per page: _MENU_'
28
+ sSearch: ''
29
+ fnRowCallback: (nRow, aData, iDisplayIndex) =>
30
+ $('.timeago', nRow).timeago()
31
+ fnInitComplete: () =>
32
+ filter_container = @table.siblings('.dataTables_filter')
33
+ filter_container.find('input').attr('placeholder', 'Search...')
34
+ filter_container.prepend '
35
+ <div class="btn-group status-filter" data-toggle="buttons-radio">
36
+ <button type="button" class="btn btn-small" data-value="queued">Queued</button>
37
+ <button type="button" class="btn btn-small" data-value="running">Running</button>
38
+ <button type="button" class="btn btn-small" data-value="complete">Complete</button>
39
+ <button type="button" class="btn btn-small" data-value="failed">Failed</button>
40
+ </div>'
41
+ @status_filter = filter_container.find('.status-filter')
42
+ fnServerData: (sSource, aoData, fnCallback) =>
43
+ $.each @api_params, (key, value) =>
44
+ aoData.push
45
+ name: key
46
+ value: @api_params[key]
47
+ $.getJSON sSource, aoData, (json) -> fnCallback(json)
48
+
49
+ @table.parents('.dataTables_wrapper').addClass('jobs-table-wrapper')
50
+
51
+ @initialize_ui()
52
+
53
+ initialize_ui: =>
54
+
55
+ @table.on 'click', '.status-value', (e) =>
56
+ tr = $(e.target).parents('tr:first')[0]
57
+ job = @table.fnGetData(tr)
58
+ @show_job(job)
59
+ false
60
+ @table.on 'click', '.retry-job', (e) =>
61
+ jid = $(e.target).attr('data-job-jid')
62
+ $.getJSON SidekiqMonitor.settings.api_url('jobs/retry?jid='+jid), =>
63
+ @reload_table()
64
+ false
65
+
66
+ $('body').on 'click', '.status-filter .btn', (e) =>
67
+ e.stopPropagation()
68
+ btn = $(e.target)
69
+ btn.siblings('.btn').removeClass('active')
70
+ btn.toggleClass('active')
71
+ value = @status_filter.find('.active:first').attr('data-value')
72
+ value = '' if !value?
73
+ @table.fnFilter(value, @columns.status - 1)
74
+
75
+ @start_polling()
76
+
77
+ show_job: (job) =>
78
+ return false if !job?
79
+
80
+ jid = job[@columns.jid]
81
+ class_name = job[@columns.class_name]
82
+ started_at = job[@columns.started_at]
83
+ duration = job[@columns.duration]
84
+ status = job[@columns.status]
85
+ result = job[@columns.result]
86
+ args = job[@columns.args]
87
+
88
+ # TODO: Make this cleaner; is there a way to grab the original value returned by the server?
89
+ status = $("<div>#{status}</div>").find('.status-value').text()
90
+
91
+ result_html = ''
92
+ if status == 'failed'
93
+ result_html = """
94
+ <h4>Error</h4>
95
+ #{result.message}
96
+ <h5>Backtrace</h5>
97
+ <pre>
98
+ #{result.backtrace.join("\n")}
99
+ </pre>
100
+ """
101
+ else if result?
102
+ rows_html = "<tr><td>#{key}</td><td>#{value}</td></tr>" for key, value in result
103
+ result_html = """
104
+ <table class="table table-striped">
105
+ #{rows_html}
106
+ </table>
107
+ """
108
+
109
+ modal_html = """
110
+ <div class="modal hide fade job-modal" role="dialog">
111
+ <div class="modal-header">
112
+ <button type="button" class="close" data-dismiss="modal">×</button>
113
+ <h3>Job</h3>
114
+ </div>
115
+ <div class="modal-body">
116
+ <table class="table table-striped">
117
+ <tr>
118
+ <th>JID</th>
119
+ <td>#{jid}</td>
120
+ </tr>
121
+ <tr>
122
+ <th>Class</th>
123
+ <td>#{class_name}</td>
124
+ </tr>
125
+ <tr>
126
+ <th>Args</th>
127
+ <td>#{args}</td>
128
+ </tr>
129
+ <tr>
130
+ <th>Started</th>
131
+ <td>#{started_at}</td>
132
+ </tr>
133
+ <tr>
134
+ <th>Duration</th>
135
+ <td>#{duration}</td>
136
+ </tr>
137
+ <tr>
138
+ <th>Status</th>
139
+ <td>#{status}</td>
140
+ </tr>
141
+ </table>
142
+ #{result_html}
143
+ </div>
144
+ </div>
145
+ """
146
+ $('.job-modal').modal('hide')
147
+ $('body').append(modal_html)
148
+ $('.job-modal:last').modal()
149
+
150
+ on_poll: =>
151
+ @reload_table()
152
+
153
+ reload_table: =>
154
+ @table.dataTable().fnStandingRedraw()
155
+
156
+ start_polling: =>
157
+ setInterval =>
158
+ @on_poll()
159
+ , 3000
160
+
161
+ format_time_ago: (time) =>
162
+ if time?
163
+ """<span class="timeago" title="#{time}">#{time}</span>"""
164
+ else
165
+ ""
@@ -0,0 +1,11 @@
1
+ #= require jquery
2
+ #= require sidekiq/monitor/bootstrap.min
3
+ #= require sidekiq/monitor/bootstrap-select.min
4
+ #= require sidekiq/monitor/jquery.timeago
5
+ #= require sidekiq/monitor/datatables
6
+ #= require sidekiq/monitor/datatables.bootstrap
7
+ #= require sidekiq/monitor/datatables.standing_redraw
8
+ #= require sidekiq/monitor/initialize
9
+ #= require sidekiq/monitor/abstract_jobs_table
10
+ #= require sidekiq/monitor/jobs_table
11
+ #= require sidekiq/monitor/queue_jobs_table
@@ -0,0 +1 @@
1
+ !function(b){var a=function(d,c,f){if(f){f.stopPropagation();f.preventDefault()}this.$element=b(d);this.$newElement=null;this.button=null;this.options=b.extend({},b.fn.selectpicker.defaults,this.$element.data(),typeof c=="object"&&c);this.style=this.options.style;this.size=this.options.size;this.init()};a.prototype={constructor:a,init:function(s){this.$element.hide();var v=this.$element.attr("class")!==undefined?this.$element.attr("class").split(/\s+/):"";var u=this.getTemplate();var o=this.$element.attr("id");u=this.createLi(u);this.$element.after(u);this.$newElement=this.$element.next(".bootstrap-select");var p=this.$newElement;var d=this.$newElement.find(".dropdown-menu");var m=d.find("li > a");var g=parseInt(m.css("line-height"))+m.outerHeight();var h=d.find("li .divider").outerHeight(true);var j=this.$newElement.offset().top;var l=0;var n=0;var t=this.$newElement.outerHeight();this.button=this.$newElement.find("> button");if(o!==undefined){this.button.attr("id",o);b('label[for="'+o+'"]').click(function(){p.find("button#"+o).focus()})}for(var r=0;r<v.length;r++){if(v[r]!="selectpicker"){this.$newElement.addClass(v[r])}}this.button.addClass(this.style);this.checkDisabled();this.checkTabIndex();this.clickListener();var q=parseInt(d.css("padding-top"))+parseInt(d.css("padding-bottom"))+parseInt(d.css("border-top-width"))+parseInt(d.css("border-bottom-width"));if(this.size=="auto"){function f(){var e=j-b(window).scrollTop();var x=window.innerHeight;var i=q+parseInt(d.css("margin-top"))+parseInt(d.css("margin-bottom"))+2;var w=x-e-t-i;n=w;if(p.hasClass("dropup")){n=e-i}d.css({"max-height":n+"px","overflow-y":"auto","min-height":g*3+"px"})}f();b(window).resize(f);b(window).scroll(f);this.$element.bind("DOMNodeInserted",f)}else{if(this.size&&this.size!="auto"&&d.find("li").length>this.size){var k=d.find("li > *").filter(":not(.div-contain)").slice(0,this.size).last().parent().index();var c=d.find("li").slice(0,k+1).find(".div-contain").length;n=g*this.size+c*h+q;d.css({"max-height":n+"px","overflow-y":"scroll"})}}this.$element.bind("DOMNodeInserted",b.proxy(this.reloadLi,this))},getTemplate:function(){var c="<div class='btn-group bootstrap-select'><button class='btn dropdown-toggle clearfix' data-toggle='dropdown'><span class='filter-option pull-left'>__SELECTED_OPTION</span>&nbsp;<span class='caret'></span></button><ul class='dropdown-menu' role='menu'>__ADD_LI</ul></div>";return c},reloadLi:function(){var f=[];var g=[];var c="";this.$newElement.find("li").remove();this.$element.find("option").each(function(){f.push(b(this).text())});this.$element.find("option").each(function(){var j=b(this).attr("class")!==undefined?b(this).attr("class"):"";var i=b(this).data("subtext")!==undefined?'<small class="muted">'+b(this).data("subtext")+"</small>":"";var h=b(this).parent().data("subtext")!==undefined?'<small class="muted">'+b(this).parent().data("subtext")+"</small>":"";if(b(this).parent().is("optgroup")&&b(this).data("divider")!=true){if(b(this).index()==0){if(b(this)[0].index!=0){g.push('<div class="div-contain"><div class="divider"></div></div><dt>'+b(this).parent().attr("label")+h+'</dt><a tabindex="-1" href="#" class="opt '+j+'">'+b(this).text()+i+"</a>")}else{g.push("<dt>"+b(this).parent().attr("label")+h+'</dt><a tabindex="-1" href="#" class="opt '+j+'">'+b(this).text()+i+"</a>")}}else{g.push('<a tabindex="-1" href="#" class="opt '+j+'">'+b(this).text()+i+"</a>")}}else{if(b(this).data("divider")==true){g.push('<div class="div-contain"><div class="divider"></div></div>')}else{g.push('<a tabindex="-1" href="#" class="'+j+'">'+b(this).text()+i+"</a>")}}});if(f.length>0){for(var d=0;d<f.length;d++){var e=this.$element.find("option").eq(d).is(":disabled")||this.$element.find("option").eq(d).parent().is(":disabled")?'class="disabled"':"";this.$newElement.find("ul").append("<li rel="+d+" "+e+">"+g[d]+"</li>")}}this.$newElement.find("li.disabled a, li dt, li .div-contain").on("click",function(h){h.preventDefault();h.stopPropagation();$select=b(this).parent().parents(".bootstrap-select");$select.find("button").focus()});if(this.$element.find("option:selected").attr("title")!=undefined){this.$newElement.find(".filter-option").html(this.$element.find("option:selected").attr("title"))}else{this.$newElement.find(".filter-option").html(this.$element.find("option:selected").text())}},createLi:function(g){var f=[];var k=[];var c="";var j=this;var h=this.$element[0].selectedIndex?this.$element[0].selectedIndex:0;this.$element.find("option").each(function(){f.push(b(this).text())});this.$element.find("option").each(function(){var m=b(this).attr("class")!==undefined?b(this).attr("class"):"";var l=b(this).data("subtext")!==undefined?'<small class="muted">'+b(this).data("subtext")+"</small>":"";var i=b(this).parent().data("subtext")!==undefined?'<small class="muted">'+b(this).parent().data("subtext")+"</small>":"";if(b(this).parent().is("optgroup")&&b(this).data("divider")!=true){if(b(this).index()==0){if(b(this)[0].index!=0){k.push('<div class="div-contain"><div class="divider"></div></div><dt>'+b(this).parent().attr("label")+i+'</dt><a tabindex="-1" href="#" class="opt '+m+'">'+b(this).text()+l+"</a>")}else{k.push("<dt>"+b(this).parent().attr("label")+i+'</dt><a tabindex="-1" href="#" class="opt '+m+'">'+b(this).text()+l+"</a>")}}else{k.push('<a tabindex="-1" href="#" class="opt '+m+'">'+b(this).text()+l+"</a>")}}else{if(b(this).data("divider")==true){k.push('<div class="div-contain"><div class="divider"></div></div>')}else{k.push('<a tabindex="-1" href="#" class="'+m+'">'+b(this).text()+l+"</a>")}}});if(f.length>0){g=g.replace("__SELECTED_OPTION",f[h]);for(var d=0;d<f.length;d++){var e=this.$element.find("option").eq(d).is(":disabled")||this.$element.find("option").eq(d).parent().is(":disabled")?'class="disabled"':"";c+="<li rel="+d+" "+e+">"+k[d]+"</li>"}}else{g=g.replace("__SELECTED_OPTION","")}this.$element.find("option").eq(h).prop("selected",true);g=g.replace("__ADD_LI",c);return g},checkDisabled:function(){if(this.$element.is(":disabled")){this.button.addClass("disabled");this.button.click(function(c){c.preventDefault()})}},checkTabIndex:function(){if(this.$element.is("[tabindex]")){var c=this.$element.attr("tabindex");this.button.attr("tabindex",c)}},clickListener:function(){b("body").on("touchstart.dropdown",".dropdown-menu",function(c){c.stopPropagation()});this.$newElement.find("li.disabled a, li dt, li .div-contain").on("click",function(c){c.preventDefault();c.stopPropagation();$select=b(this).parent().parents(".bootstrap-select");$select.find("button").focus()});this.$newElement.on("click","li a",function(g){g.preventDefault();var d=b(this).parent().index(),f=b(this).parent(),c=f.parents(".bootstrap-select");if(c.prev("select").not(":disabled")){c.prev("select").find("option").removeAttr("selected");c.prev("select").find("option").eq(d).prop("selected",true).attr("selected","selected");c.find(".filter-option").html(f.text());c.find("button").focus();c.prev("select").trigger("change")}});this.$element.on("change",function(c){if(b(this).find("option:selected").attr("title")!=undefined){b(this).next(".bootstrap-select").find(".filter-option").html(b(this).find("option:selected").attr("title"))}else{b(this).next(".bootstrap-select").find(".filter-option").html(b(this).find("option:selected").text())}})}};b.fn.selectpicker=function(c,d){return this.each(function(){var g=b(this),f=g.data("selectpicker"),e=typeof c=="object"&&c;if(!f){g.data("selectpicker",(f=new a(this,e,d)))}if(typeof c=="string"){f[c]()}})};b.fn.selectpicker.defaults={style:null,size:"auto"}}(window.jQuery);
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Bootstrap.js by @fat & @mdo
3
+ * Copyright 2012 Twitter, Inc.
4
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
5
+ */
6
+ !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||s.toggleClass("open"),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on(".dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(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 t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
@@ -0,0 +1,96 @@
1
+ /* Default class modification */
2
+
3
+ $.extend( $.fn.dataTableExt.oStdClasses, {
4
+ "sWrapper": "dataTables_wrapper form-inline"
5
+ } );
6
+
7
+ /* API method to get paging information */
8
+ $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
9
+ {
10
+ return {
11
+ "iStart": oSettings._iDisplayStart,
12
+ "iEnd": oSettings.fnDisplayEnd(),
13
+ "iLength": oSettings._iDisplayLength,
14
+ "iTotal": oSettings.fnRecordsTotal(),
15
+ "iFilteredTotal": oSettings.fnRecordsDisplay(),
16
+ "iPage": Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
17
+ "iTotalPages": Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
18
+ };
19
+ }
20
+
21
+ /* Bootstrap style pagination control */
22
+ $.extend( $.fn.dataTableExt.oPagination, {
23
+ "bootstrap": {
24
+ "fnInit": function( oSettings, nPaging, fnDraw ) {
25
+ var oLang = oSettings.oLanguage.oPaginate;
26
+ var fnClickHandler = function ( e ) {
27
+ e.preventDefault();
28
+ if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
29
+ fnDraw( oSettings );
30
+ }
31
+ };
32
+
33
+ $(nPaging).addClass('pagination').append(
34
+ '<ul>'+
35
+ '<li class="prev disabled"><a href="#">&larr; '+oLang.sPrevious+'</a></li>'+
36
+ '<li class="next disabled"><a href="#">'+oLang.sNext+' &rarr; </a></li>'+
37
+ '</ul>'
38
+ );
39
+ var els = $('a', nPaging);
40
+ $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
41
+ $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
42
+ },
43
+
44
+ "fnUpdate": function ( oSettings, fnDraw ) {
45
+ var iListLength = 5;
46
+ var oPaging = oSettings.oInstance.fnPagingInfo();
47
+ var an = oSettings.aanFeatures.p;
48
+ var i, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);
49
+
50
+ if ( oPaging.iTotalPages < iListLength) {
51
+ iStart = 1;
52
+ iEnd = oPaging.iTotalPages;
53
+ }
54
+ else if ( oPaging.iPage <= iHalf ) {
55
+ iStart = 1;
56
+ iEnd = iListLength;
57
+ } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
58
+ iStart = oPaging.iTotalPages - iListLength + 1;
59
+ iEnd = oPaging.iTotalPages;
60
+ } else {
61
+ iStart = oPaging.iPage - iHalf + 1;
62
+ iEnd = iStart + iListLength - 1;
63
+ }
64
+
65
+ for ( i=0, iLen=an.length ; i<iLen ; i++ ) {
66
+ // Remove the middle elements
67
+ $('li:gt(0)', an[i]).filter(':not(:last)').remove();
68
+
69
+ // Add the new list items and their event handlers
70
+ for ( j=iStart ; j<=iEnd ; j++ ) {
71
+ sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
72
+ $('<li '+sClass+'><a href="#">'+j+'</a></li>')
73
+ .insertBefore( $('li:last', an[i])[0] )
74
+ .bind('click', function (e) {
75
+ e.preventDefault();
76
+ oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
77
+ fnDraw( oSettings );
78
+ } );
79
+ }
80
+
81
+ // Add / remove disabled classes from the static elements
82
+ if ( oPaging.iPage === 0 ) {
83
+ $('li:first', an[i]).addClass('disabled');
84
+ } else {
85
+ $('li:first', an[i]).removeClass('disabled');
86
+ }
87
+
88
+ if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
89
+ $('li:last', an[i]).addClass('disabled');
90
+ } else {
91
+ $('li:last', an[i]).removeClass('disabled');
92
+ }
93
+ }
94
+ }
95
+ }
96
+ } );