apipie-rails 0.5.19 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +31 -0
  3. data/.github/workflows/rubocop-challenger.yml +28 -0
  4. data/.github/workflows/rubocop.yml +18 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +128 -0
  7. data/.rubocop_todo.yml +2056 -0
  8. data/.vscode/settings.json +3 -0
  9. data/CHANGELOG.md +161 -0
  10. data/Gemfile +20 -0
  11. data/README.rst +117 -23
  12. data/Rakefile +0 -5
  13. data/apipie-rails.gemspec +18 -9
  14. data/app/controllers/apipie/apipies_controller.rb +14 -29
  15. data/app/helpers/apipie_helper.rb +1 -1
  16. data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +70 -41
  17. data/app/public/apipie/javascripts/bundled/bootstrap.js +1033 -479
  18. data/app/public/apipie/javascripts/bundled/jquery.js +5 -5
  19. data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +9 -12
  20. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +9 -689
  21. data/app/views/apipie/apipies/_deprecation.html.erb +16 -0
  22. data/app/views/apipie/apipies/_params.html.erb +7 -1
  23. data/config/locales/en.yml +8 -0
  24. data/config/locales/ko.yml +31 -0
  25. data/gemfiles/Gemfile.tools +9 -0
  26. data/lib/apipie/apipie_module.rb +7 -7
  27. data/lib/apipie/application.rb +132 -97
  28. data/lib/apipie/configuration.rb +43 -33
  29. data/lib/apipie/dsl_definition.rb +44 -33
  30. data/lib/apipie/error_description.rb +3 -3
  31. data/lib/apipie/errors.rb +17 -17
  32. data/lib/apipie/extractor/collector.rb +5 -6
  33. data/lib/apipie/extractor/recorder.rb +35 -8
  34. data/lib/apipie/extractor/writer.rb +15 -15
  35. data/lib/apipie/extractor.rb +6 -9
  36. data/lib/apipie/generator/config.rb +12 -0
  37. data/lib/apipie/generator/generator.rb +2 -0
  38. data/lib/apipie/generator/swagger/computed_interface_id.rb +23 -0
  39. data/lib/apipie/generator/swagger/config.rb +80 -0
  40. data/lib/apipie/generator/swagger/context.rb +38 -0
  41. data/lib/apipie/generator/swagger/method_description/api_decorator.rb +20 -0
  42. data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +89 -0
  43. data/lib/apipie/generator/swagger/method_description/decorator.rb +22 -0
  44. data/lib/apipie/generator/swagger/method_description/parameters_service.rb +139 -0
  45. data/lib/apipie/generator/swagger/method_description/response_schema_service.rb +46 -0
  46. data/lib/apipie/generator/swagger/method_description/response_service.rb +58 -0
  47. data/lib/apipie/generator/swagger/method_description.rb +2 -0
  48. data/lib/apipie/generator/swagger/operation_id.rb +51 -0
  49. data/lib/apipie/generator/swagger/param_description/builder.rb +114 -0
  50. data/lib/apipie/generator/swagger/param_description/composite.rb +119 -0
  51. data/lib/apipie/generator/swagger/param_description/description.rb +15 -0
  52. data/lib/apipie/generator/swagger/param_description/in.rb +37 -0
  53. data/lib/apipie/generator/swagger/param_description/name.rb +18 -0
  54. data/lib/apipie/generator/swagger/param_description/path_params_composite.rb +61 -0
  55. data/lib/apipie/generator/swagger/param_description/referenced_composite.rb +36 -0
  56. data/lib/apipie/generator/swagger/param_description/type.rb +128 -0
  57. data/lib/apipie/generator/swagger/param_description.rb +18 -0
  58. data/lib/apipie/generator/swagger/path_decorator.rb +36 -0
  59. data/lib/apipie/generator/swagger/referenced_definitions.rb +17 -0
  60. data/lib/apipie/generator/swagger/resource_description_collection.rb +30 -0
  61. data/lib/apipie/generator/swagger/resource_description_composite.rb +56 -0
  62. data/lib/apipie/generator/swagger/schema.rb +63 -0
  63. data/lib/apipie/generator/swagger/swagger.rb +2 -0
  64. data/lib/apipie/generator/swagger/type.rb +16 -0
  65. data/lib/apipie/generator/swagger/type_extractor.rb +51 -0
  66. data/lib/apipie/generator/swagger/warning.rb +74 -0
  67. data/lib/apipie/generator/swagger/warning_writer.rb +54 -0
  68. data/lib/apipie/helpers.rb +3 -3
  69. data/lib/apipie/markup.rb +9 -8
  70. data/lib/apipie/method_description/api.rb +12 -0
  71. data/lib/apipie/method_description/apis_service.rb +82 -0
  72. data/lib/apipie/method_description.rb +12 -56
  73. data/lib/apipie/param_description/deprecation.rb +24 -0
  74. data/lib/apipie/param_description.rb +57 -24
  75. data/lib/apipie/resource_description.rb +42 -14
  76. data/lib/apipie/response_description.rb +3 -3
  77. data/lib/apipie/response_description_adapter.rb +12 -10
  78. data/lib/apipie/routing.rb +1 -1
  79. data/lib/apipie/rspec/response_validation_helper.rb +3 -3
  80. data/lib/apipie/static_dispatcher.rb +10 -2
  81. data/lib/apipie/swagger_generator.rb +28 -691
  82. data/lib/apipie/validator.rb +41 -11
  83. data/lib/apipie/version.rb +1 -1
  84. data/lib/apipie-rails.rb +36 -5
  85. data/lib/generators/apipie/install/install_generator.rb +1 -1
  86. data/lib/generators/apipie/views_generator.rb +1 -1
  87. data/lib/tasks/apipie.rake +37 -32
  88. data/rel-eng/gem_release.ipynb +41 -9
  89. data/spec/controllers/api/v2/architectures_controller_spec.rb +10 -3
  90. data/spec/controllers/api/v2/empty_middle_controller_spec.rb +23 -0
  91. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +18 -2
  92. data/spec/controllers/api/v2/sub/footguns_controller_spec.rb +19 -0
  93. data/spec/controllers/included_param_group_controller_spec.rb +13 -0
  94. data/spec/{lib/swagger/response_validation_spec.rb → controllers/pets_controller_spec.rb} +26 -32
  95. data/spec/controllers/users_controller_spec.rb +47 -6
  96. data/spec/dummy/Rakefile +1 -1
  97. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +2 -1
  98. data/spec/dummy/app/controllers/api/v2/base_controller.rb +6 -0
  99. data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +14 -0
  100. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +2 -2
  101. data/spec/dummy/app/controllers/api/v2/sub/footguns_controller.rb +30 -0
  102. data/spec/dummy/app/controllers/concerns_controller.rb +1 -1
  103. data/spec/dummy/app/controllers/{concerns/extending_concern.rb → extending_concern.rb} +0 -2
  104. data/spec/dummy/app/controllers/included_param_group_controller.rb +19 -0
  105. data/spec/dummy/app/controllers/overridden_concerns_controller.rb +2 -2
  106. data/spec/dummy/app/controllers/pets_controller.rb +5 -5
  107. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +2 -2
  108. data/spec/dummy/app/controllers/{concerns/sample_controller.rb → sample_controller.rb} +0 -2
  109. data/spec/dummy/app/controllers/twitter_example_controller.rb +2 -2
  110. data/spec/dummy/app/controllers/users_controller.rb +17 -5
  111. data/spec/dummy/app/helpers/random_param_group.rb +8 -0
  112. data/spec/dummy/components/test_engine/test_engine.gemspec +1 -1
  113. data/spec/dummy/config/application.rb +2 -5
  114. data/spec/dummy/config/boot.rb +2 -2
  115. data/spec/dummy/config/environment.rb +1 -1
  116. data/spec/dummy/config/environments/development.rb +0 -3
  117. data/spec/dummy/config/environments/production.rb +0 -3
  118. data/spec/dummy/config/environments/test.rb +0 -5
  119. data/spec/dummy/config/initializers/apipie.rb +2 -2
  120. data/spec/dummy/config/routes.rb +8 -0
  121. data/spec/dummy/config.ru +1 -1
  122. data/spec/dummy/script/rails +2 -2
  123. data/spec/{controllers → lib/apipie}/apipies_controller_spec.rb +95 -23
  124. data/spec/lib/apipie/application_spec.rb +62 -0
  125. data/spec/lib/apipie/configuration_spec.rb +38 -0
  126. data/spec/lib/apipie/extractor/collector_spec.rb +57 -0
  127. data/spec/lib/apipie/extractor/recorder_spec.rb +77 -0
  128. data/spec/lib/{extractor → apipie/extractor}/writer_spec.rb +8 -6
  129. data/spec/lib/{extractor → apipie}/extractor_spec.rb +1 -1
  130. data/spec/lib/{file_handler_spec.rb → apipie/file_handler_spec.rb} +7 -0
  131. data/spec/lib/apipie/generator/swagger/config_spec.rb +19 -0
  132. data/spec/lib/apipie/generator/swagger/context_spec.rb +56 -0
  133. data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +119 -0
  134. data/spec/lib/apipie/generator/swagger/method_description/response_schema_service_spec.rb +105 -0
  135. data/spec/lib/apipie/generator/swagger/operation_id_spec.rb +63 -0
  136. data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +215 -0
  137. data/spec/lib/apipie/generator/swagger/param_description/composite_spec.rb +95 -0
  138. data/spec/lib/apipie/generator/swagger/param_description/description_spec.rb +79 -0
  139. data/spec/lib/apipie/generator/swagger/param_description/in_spec.rb +86 -0
  140. data/spec/lib/apipie/generator/swagger/param_description/name_spec.rb +81 -0
  141. data/spec/lib/apipie/generator/swagger/param_description/type_spec.rb +183 -0
  142. data/spec/lib/apipie/generator/swagger/param_description_spec.rb +28 -0
  143. data/spec/lib/apipie/generator/swagger/path_decorator_spec.rb +57 -0
  144. data/spec/lib/apipie/generator/swagger/referenced_definitions_spec.rb +35 -0
  145. data/spec/lib/apipie/generator/swagger/resource_description_composite_spec.rb +37 -0
  146. data/spec/lib/apipie/generator/swagger/resource_descriptions_collection_spec.rb +57 -0
  147. data/spec/lib/apipie/generator/swagger/schema_spec.rb +89 -0
  148. data/spec/lib/apipie/generator/swagger/type_extractor_spec.rb +38 -0
  149. data/spec/lib/apipie/generator/swagger/warning_spec.rb +51 -0
  150. data/spec/lib/apipie/generator/swagger/warning_writer_spec.rb +71 -0
  151. data/spec/lib/apipie/method_description/apis_service_spec.rb +60 -0
  152. data/spec/lib/apipie/method_description_spec.rb +133 -0
  153. data/spec/lib/apipie/no_documented_method_spec.rb +17 -0
  154. data/spec/lib/apipie/param_description/deprecation_spec.rb +31 -0
  155. data/spec/lib/{param_description_spec.rb → apipie/param_description_spec.rb} +332 -6
  156. data/spec/lib/{param_group_spec.rb → apipie/param_group_spec.rb} +6 -5
  157. data/spec/lib/apipie/resource_description_spec.rb +91 -0
  158. data/spec/lib/apipie/response_does_not_match_swagger_schema_spec.rb +35 -0
  159. data/spec/lib/apipie/swagger_generator_spec.rb +94 -0
  160. data/spec/lib/{validator_spec.rb → apipie/validator_spec.rb} +48 -12
  161. data/spec/lib/rake_spec.rb +3 -5
  162. data/spec/lib/swagger/openapi_2_0_schema.json +8 -1
  163. data/spec/lib/swagger/rake_swagger_spec.rb +30 -10
  164. data/spec/lib/swagger/swagger_dsl_spec.rb +18 -12
  165. data/spec/lib/validators/array_validator_spec.rb +1 -1
  166. data/spec/spec_helper.rb +10 -32
  167. data/spec/support/custom_bool_validator.rb +17 -0
  168. data/spec/{controllers → test_engine}/memes_controller_spec.rb +1 -1
  169. metadata +173 -125
  170. data/.travis.yml +0 -41
  171. data/Gemfile +0 -1
  172. data/Gemfile.rails41 +0 -7
  173. data/Gemfile.rails42 +0 -14
  174. data/Gemfile.rails50 +0 -9
  175. data/Gemfile.rails51 +0 -9
  176. data/Gemfile.rails60 +0 -10
  177. data/Gemfile.rails61 +0 -10
  178. data/spec/lib/application_spec.rb +0 -49
  179. data/spec/lib/method_description_spec.rb +0 -98
  180. data/spec/lib/resource_description_spec.rb +0 -48
  181. /data/spec/lib/{extractor → apipie/extractor/recorder}/middleware_spec.rb +0 -0
@@ -1,8 +1,8 @@
1
1
  /* ===================================================
2
- * bootstrap-transition.js v2.0.2
3
- * http://twitter.github.com/bootstrap/javascript.html#transitions
2
+ * bootstrap-transition.js v2.3.2
3
+ * http://getbootstrap.com/2.3.2/javascript.html#transitions
4
4
  * ===================================================
5
- * Copyright 2012 Twitter, Inc.
5
+ * Copyright 2013 Twitter, Inc.
6
6
  *
7
7
  * Licensed under the Apache License, Version 2.0 (the "License");
8
8
  * you may not use this file except in compliance with the License.
@@ -17,42 +17,51 @@
17
17
  * limitations under the License.
18
18
  * ========================================================== */
19
19
 
20
- !function( $ ) {
21
20
 
22
- $(function () {
21
+ !function ($) {
22
+
23
+ "use strict"; // jshint ;_;
23
24
 
24
- "use strict"
25
25
 
26
- /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
27
- * ======================================================= */
26
+ /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27
+ * ======================================================= */
28
+
29
+ $(function () {
28
30
 
29
31
  $.support.transition = (function () {
30
- var thisBody = document.body || document.documentElement
31
- , thisStyle = thisBody.style
32
- , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
33
-
34
- return support && {
35
- end: (function () {
36
- var transitionEnd = "TransitionEnd"
37
- if ( $.browser.webkit ) {
38
- transitionEnd = "webkitTransitionEnd"
39
- } else if ( $.browser.mozilla ) {
40
- transitionEnd = "transitionend"
41
- } else if ( $.browser.opera ) {
42
- transitionEnd = "oTransitionEnd"
32
+
33
+ var transitionEnd = (function () {
34
+
35
+ var el = document.createElement('bootstrap')
36
+ , transEndEventNames = {
37
+ 'WebkitTransition' : 'webkitTransitionEnd'
38
+ , 'MozTransition' : 'transitionend'
39
+ , 'OTransition' : 'oTransitionEnd otransitionend'
40
+ , 'transition' : 'transitionend'
41
+ }
42
+ , name
43
+
44
+ for (name in transEndEventNames){
45
+ if (el.style[name] !== undefined) {
46
+ return transEndEventNames[name]
43
47
  }
44
- return transitionEnd
45
- }())
48
+ }
49
+
50
+ }())
51
+
52
+ return transitionEnd && {
53
+ end: transitionEnd
46
54
  }
55
+
47
56
  })()
48
57
 
49
58
  })
50
59
 
51
- }( window.jQuery );/* ==========================================================
52
- * bootstrap-alert.js v2.0.2
53
- * http://twitter.github.com/bootstrap/javascript.html#alerts
60
+ }(window.jQuery);/* ==========================================================
61
+ * bootstrap-alert.js v2.3.2
62
+ * http://getbootstrap.com/2.3.2/javascript.html#alerts
54
63
  * ==========================================================
55
- * Copyright 2012 Twitter, Inc.
64
+ * Copyright 2013 Twitter, Inc.
56
65
  *
57
66
  * Licensed under the Apache License, Version 2.0 (the "License");
58
67
  * you may not use this file except in compliance with the License.
@@ -68,61 +77,59 @@
68
77
  * ========================================================== */
69
78
 
70
79
 
71
- !function( $ ){
80
+ !function ($) {
81
+
82
+ "use strict"; // jshint ;_;
72
83
 
73
- "use strict"
74
84
 
75
85
  /* ALERT CLASS DEFINITION
76
86
  * ====================== */
77
87
 
78
88
  var dismiss = '[data-dismiss="alert"]'
79
- , Alert = function ( el ) {
89
+ , Alert = function (el) {
80
90
  $(el).on('click', dismiss, this.close)
81
91
  }
82
92
 
83
- Alert.prototype = {
93
+ Alert.prototype.close = function (e) {
94
+ var $this = $(this)
95
+ , selector = $this.attr('data-target')
96
+ , $parent
84
97
 
85
- constructor: Alert
86
-
87
- , close: function ( e ) {
88
- var $this = $(this)
89
- , selector = $this.attr('data-target')
90
- , $parent
98
+ if (!selector) {
99
+ selector = $this.attr('href')
100
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
101
+ }
91
102
 
92
- if (!selector) {
93
- selector = $this.attr('href')
94
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
95
- }
103
+ $parent = $(selector)
96
104
 
97
- $parent = $(selector)
98
- $parent.trigger('close')
105
+ e && e.preventDefault()
99
106
 
100
- e && e.preventDefault()
107
+ $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
101
108
 
102
- $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
109
+ $parent.trigger(e = $.Event('close'))
103
110
 
104
- $parent
105
- .trigger('close')
106
- .removeClass('in')
111
+ if (e.isDefaultPrevented()) return
107
112
 
108
- function removeElement() {
109
- $parent
110
- .trigger('closed')
111
- .remove()
112
- }
113
+ $parent.removeClass('in')
113
114
 
114
- $.support.transition && $parent.hasClass('fade') ?
115
- $parent.on($.support.transition.end, removeElement) :
116
- removeElement()
115
+ function removeElement() {
116
+ $parent
117
+ .trigger('closed')
118
+ .remove()
117
119
  }
118
120
 
121
+ $.support.transition && $parent.hasClass('fade') ?
122
+ $parent.on($.support.transition.end, removeElement) :
123
+ removeElement()
119
124
  }
120
125
 
121
126
 
122
127
  /* ALERT PLUGIN DEFINITION
123
128
  * ======================= */
124
129
 
125
- $.fn.alert = function ( option ) {
130
+ var old = $.fn.alert
131
+
132
+ $.fn.alert = function (option) {
126
133
  return this.each(function () {
127
134
  var $this = $(this)
128
135
  , data = $this.data('alert')
@@ -134,18 +141,25 @@
134
141
  $.fn.alert.Constructor = Alert
135
142
 
136
143
 
144
+ /* ALERT NO CONFLICT
145
+ * ================= */
146
+
147
+ $.fn.alert.noConflict = function () {
148
+ $.fn.alert = old
149
+ return this
150
+ }
151
+
152
+
137
153
  /* ALERT DATA-API
138
154
  * ============== */
139
155
 
140
- $(function () {
141
- $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
142
- })
156
+ $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
143
157
 
144
- }( window.jQuery );/* ============================================================
145
- * bootstrap-button.js v2.0.2
146
- * http://twitter.github.com/bootstrap/javascript.html#buttons
158
+ }(window.jQuery);/* ============================================================
159
+ * bootstrap-button.js v2.3.2
160
+ * http://getbootstrap.com/2.3.2/javascript.html#buttons
147
161
  * ============================================================
148
- * Copyright 2012 Twitter, Inc.
162
+ * Copyright 2013 Twitter, Inc.
149
163
  *
150
164
  * Licensed under the Apache License, Version 2.0 (the "License");
151
165
  * you may not use this file except in compliance with the License.
@@ -160,58 +174,56 @@
160
174
  * limitations under the License.
161
175
  * ============================================================ */
162
176
 
163
- !function( $ ){
164
177
 
165
- "use strict"
178
+ !function ($) {
179
+
180
+ "use strict"; // jshint ;_;
181
+
166
182
 
167
183
  /* BUTTON PUBLIC CLASS DEFINITION
168
184
  * ============================== */
169
185
 
170
- var Button = function ( element, options ) {
186
+ var Button = function (element, options) {
171
187
  this.$element = $(element)
172
188
  this.options = $.extend({}, $.fn.button.defaults, options)
173
189
  }
174
190
 
175
- Button.prototype = {
176
-
177
- constructor: Button
178
-
179
- , setState: function ( state ) {
180
- var d = 'disabled'
181
- , $el = this.$element
182
- , data = $el.data()
183
- , val = $el.is('input') ? 'val' : 'html'
191
+ Button.prototype.setState = function (state) {
192
+ var d = 'disabled'
193
+ , $el = this.$element
194
+ , data = $el.data()
195
+ , val = $el.is('input') ? 'val' : 'html'
184
196
 
185
- state = state + 'Text'
186
- data.resetText || $el.data('resetText', $el[val]())
197
+ state = state + 'Text'
198
+ data.resetText || $el.data('resetText', $el[val]())
187
199
 
188
- $el[val](data[state] || this.options[state])
200
+ $el[val](data[state] || this.options[state])
189
201
 
190
- // push to event loop to allow forms to submit
191
- setTimeout(function () {
192
- state == 'loadingText' ?
193
- $el.addClass(d).attr(d, d) :
194
- $el.removeClass(d).removeAttr(d)
195
- }, 0)
196
- }
202
+ // push to event loop to allow forms to submit
203
+ setTimeout(function () {
204
+ state == 'loadingText' ?
205
+ $el.addClass(d).attr(d, d) :
206
+ $el.removeClass(d).removeAttr(d)
207
+ }, 0)
208
+ }
197
209
 
198
- , toggle: function () {
199
- var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
210
+ Button.prototype.toggle = function () {
211
+ var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
200
212
 
201
- $parent && $parent
202
- .find('.active')
203
- .removeClass('active')
204
-
205
- this.$element.toggleClass('active')
206
- }
213
+ $parent && $parent
214
+ .find('.active')
215
+ .removeClass('active')
207
216
 
217
+ this.$element.toggleClass('active')
208
218
  }
209
219
 
210
220
 
211
221
  /* BUTTON PLUGIN DEFINITION
212
222
  * ======================== */
213
223
 
214
- $.fn.button = function ( option ) {
224
+ var old = $.fn.button
225
+
226
+ $.fn.button = function (option) {
215
227
  return this.each(function () {
216
228
  var $this = $(this)
217
229
  , data = $this.data('button')
@@ -229,22 +241,29 @@
229
241
  $.fn.button.Constructor = Button
230
242
 
231
243
 
244
+ /* BUTTON NO CONFLICT
245
+ * ================== */
246
+
247
+ $.fn.button.noConflict = function () {
248
+ $.fn.button = old
249
+ return this
250
+ }
251
+
252
+
232
253
  /* BUTTON DATA-API
233
254
  * =============== */
234
255
 
235
- $(function () {
236
- $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
237
- var $btn = $(e.target)
238
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
239
- $btn.button('toggle')
240
- })
256
+ $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
257
+ var $btn = $(e.target)
258
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
259
+ $btn.button('toggle')
241
260
  })
242
261
 
243
- }( window.jQuery );/* ==========================================================
244
- * bootstrap-carousel.js v2.0.2
245
- * http://twitter.github.com/bootstrap/javascript.html#carousel
262
+ }(window.jQuery);/* ==========================================================
263
+ * bootstrap-carousel.js v2.3.2
264
+ * http://getbootstrap.com/2.3.2/javascript.html#carousel
246
265
  * ==========================================================
247
- * Copyright 2012 Twitter, Inc.
266
+ * Copyright 2013 Twitter, Inc.
248
267
  *
249
268
  * Licensed under the Apache License, Version 2.0 (the "License");
250
269
  * you may not use this file except in compliance with the License.
@@ -260,17 +279,18 @@
260
279
  * ========================================================== */
261
280
 
262
281
 
263
- !function( $ ){
282
+ !function ($) {
283
+
284
+ "use strict"; // jshint ;_;
264
285
 
265
- "use strict"
266
286
 
267
287
  /* CAROUSEL CLASS DEFINITION
268
288
  * ========================= */
269
289
 
270
290
  var Carousel = function (element, options) {
271
291
  this.$element = $(element)
272
- this.options = $.extend({}, $.fn.carousel.defaults, options)
273
- this.options.slide && this.slide(this.options.slide)
292
+ this.$indicators = this.$element.find('.carousel-indicators')
293
+ this.options = options
274
294
  this.options.pause == 'hover' && this.$element
275
295
  .on('mouseenter', $.proxy(this.pause, this))
276
296
  .on('mouseleave', $.proxy(this.cycle, this))
@@ -278,18 +298,26 @@
278
298
 
279
299
  Carousel.prototype = {
280
300
 
281
- cycle: function () {
282
- this.interval = setInterval($.proxy(this.next, this), this.options.interval)
301
+ cycle: function (e) {
302
+ if (!e) this.paused = false
303
+ if (this.interval) clearInterval(this.interval);
304
+ this.options.interval
305
+ && !this.paused
306
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
283
307
  return this
284
308
  }
285
309
 
310
+ , getActiveIndex: function () {
311
+ this.$active = this.$element.find('.item.active')
312
+ this.$items = this.$active.parent().children()
313
+ return this.$items.index(this.$active)
314
+ }
315
+
286
316
  , to: function (pos) {
287
- var $active = this.$element.find('.active')
288
- , children = $active.parent().children()
289
- , activePos = children.index($active)
317
+ var activeIndex = this.getActiveIndex()
290
318
  , that = this
291
319
 
292
- if (pos > (children.length - 1) || pos < 0) return
320
+ if (pos > (this.$items.length - 1) || pos < 0) return
293
321
 
294
322
  if (this.sliding) {
295
323
  return this.$element.one('slid', function () {
@@ -297,14 +325,19 @@
297
325
  })
298
326
  }
299
327
 
300
- if (activePos == pos) {
328
+ if (activeIndex == pos) {
301
329
  return this.pause().cycle()
302
330
  }
303
331
 
304
- return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
332
+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
305
333
  }
306
334
 
307
- , pause: function () {
335
+ , pause: function (e) {
336
+ if (!e) this.paused = true
337
+ if (this.$element.find('.next, .prev').length && $.support.transition.end) {
338
+ this.$element.trigger($.support.transition.end)
339
+ this.cycle(true)
340
+ }
308
341
  clearInterval(this.interval)
309
342
  this.interval = null
310
343
  return this
@@ -321,12 +354,13 @@
321
354
  }
322
355
 
323
356
  , slide: function (type, next) {
324
- var $active = this.$element.find('.active')
357
+ var $active = this.$element.find('.item.active')
325
358
  , $next = next || $active[type]()
326
359
  , isCycling = this.interval
327
360
  , direction = type == 'next' ? 'left' : 'right'
328
361
  , fallback = type == 'next' ? 'first' : 'last'
329
362
  , that = this
363
+ , e
330
364
 
331
365
  this.sliding = true
332
366
 
@@ -334,26 +368,41 @@
334
368
 
335
369
  $next = $next.length ? $next : this.$element.find('.item')[fallback]()
336
370
 
371
+ e = $.Event('slide', {
372
+ relatedTarget: $next[0]
373
+ , direction: direction
374
+ })
375
+
337
376
  if ($next.hasClass('active')) return
338
377
 
339
- if (!$.support.transition && this.$element.hasClass('slide')) {
340
- this.$element.trigger('slide')
341
- $active.removeClass('active')
342
- $next.addClass('active')
343
- this.sliding = false
344
- this.$element.trigger('slid')
345
- } else {
378
+ if (this.$indicators.length) {
379
+ this.$indicators.find('.active').removeClass('active')
380
+ this.$element.one('slid', function () {
381
+ var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
382
+ $nextIndicator && $nextIndicator.addClass('active')
383
+ })
384
+ }
385
+
386
+ if ($.support.transition && this.$element.hasClass('slide')) {
387
+ this.$element.trigger(e)
388
+ if (e.isDefaultPrevented()) return
346
389
  $next.addClass(type)
347
390
  $next[0].offsetWidth // force reflow
348
391
  $active.addClass(direction)
349
392
  $next.addClass(direction)
350
- this.$element.trigger('slide')
351
393
  this.$element.one($.support.transition.end, function () {
352
394
  $next.removeClass([type, direction].join(' ')).addClass('active')
353
395
  $active.removeClass(['active', direction].join(' '))
354
396
  that.sliding = false
355
397
  setTimeout(function () { that.$element.trigger('slid') }, 0)
356
398
  })
399
+ } else {
400
+ this.$element.trigger(e)
401
+ if (e.isDefaultPrevented()) return
402
+ $active.removeClass('active')
403
+ $next.addClass('active')
404
+ this.sliding = false
405
+ this.$element.trigger('slid')
357
406
  }
358
407
 
359
408
  isCycling && this.cycle()
@@ -367,15 +416,18 @@
367
416
  /* CAROUSEL PLUGIN DEFINITION
368
417
  * ========================== */
369
418
 
370
- $.fn.carousel = function ( option ) {
419
+ var old = $.fn.carousel
420
+
421
+ $.fn.carousel = function (option) {
371
422
  return this.each(function () {
372
423
  var $this = $(this)
373
424
  , data = $this.data('carousel')
374
- , options = typeof option == 'object' && option
425
+ , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
426
+ , action = typeof option == 'string' ? option : options.slide
375
427
  if (!data) $this.data('carousel', (data = new Carousel(this, options)))
376
428
  if (typeof option == 'number') data.to(option)
377
- else if (typeof option == 'string' || (option = options.slide)) data[option]()
378
- else data.cycle()
429
+ else if (action) data[action]()
430
+ else if (options.interval) data.pause().cycle()
379
431
  })
380
432
  }
381
433
 
@@ -387,24 +439,37 @@
387
439
  $.fn.carousel.Constructor = Carousel
388
440
 
389
441
 
442
+ /* CAROUSEL NO CONFLICT
443
+ * ==================== */
444
+
445
+ $.fn.carousel.noConflict = function () {
446
+ $.fn.carousel = old
447
+ return this
448
+ }
449
+
390
450
  /* CAROUSEL DATA-API
391
451
  * ================= */
392
452
 
393
- $(function () {
394
- $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
395
- var $this = $(this), href
396
- , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
397
- , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
398
- $target.carousel(options)
399
- e.preventDefault()
400
- })
453
+ $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
454
+ var $this = $(this), href
455
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
456
+ , options = $.extend({}, $target.data(), $this.data())
457
+ , slideIndex
458
+
459
+ $target.carousel(options)
460
+
461
+ if (slideIndex = $this.attr('data-slide-to')) {
462
+ $target.data('carousel').pause().to(slideIndex).cycle()
463
+ }
464
+
465
+ e.preventDefault()
401
466
  })
402
467
 
403
- }( window.jQuery );/* =============================================================
404
- * bootstrap-collapse.js v2.0.2
405
- * http://twitter.github.com/bootstrap/javascript.html#collapse
468
+ }(window.jQuery);/* =============================================================
469
+ * bootstrap-collapse.js v2.3.2
470
+ * http://getbootstrap.com/2.3.2/javascript.html#collapse
406
471
  * =============================================================
407
- * Copyright 2012 Twitter, Inc.
472
+ * Copyright 2013 Twitter, Inc.
408
473
  *
409
474
  * Licensed under the Apache License, Version 2.0 (the "License");
410
475
  * you may not use this file except in compliance with the License.
@@ -419,16 +484,21 @@
419
484
  * limitations under the License.
420
485
  * ============================================================ */
421
486
 
422
- !function( $ ){
423
487
 
424
- "use strict"
488
+ !function ($) {
489
+
490
+ "use strict"; // jshint ;_;
491
+
492
+
493
+ /* COLLAPSE PUBLIC CLASS DEFINITION
494
+ * ================================ */
425
495
 
426
- var Collapse = function ( element, options ) {
427
- this.$element = $(element)
496
+ var Collapse = function (element, options) {
497
+ this.$element = $(element)
428
498
  this.options = $.extend({}, $.fn.collapse.defaults, options)
429
499
 
430
- if (this.options["parent"]) {
431
- this.$parent = $(this.options["parent"])
500
+ if (this.options.parent) {
501
+ this.$parent = $(this.options.parent)
432
502
  }
433
503
 
434
504
  this.options.toggle && this.toggle()
@@ -444,31 +514,39 @@
444
514
  }
445
515
 
446
516
  , show: function () {
447
- var dimension = this.dimension()
448
- , scroll = $.camelCase(['scroll', dimension].join('-'))
449
- , actives = this.$parent && this.$parent.find('.in')
517
+ var dimension
518
+ , scroll
519
+ , actives
450
520
  , hasData
451
521
 
522
+ if (this.transitioning || this.$element.hasClass('in')) return
523
+
524
+ dimension = this.dimension()
525
+ scroll = $.camelCase(['scroll', dimension].join('-'))
526
+ actives = this.$parent && this.$parent.find('> .accordion-group > .in')
527
+
452
528
  if (actives && actives.length) {
453
529
  hasData = actives.data('collapse')
530
+ if (hasData && hasData.transitioning) return
454
531
  actives.collapse('hide')
455
532
  hasData || actives.data('collapse', null)
456
533
  }
457
534
 
458
535
  this.$element[dimension](0)
459
- this.transition('addClass', 'show', 'shown')
460
- this.$element[dimension](this.$element[0][scroll])
461
-
536
+ this.transition('addClass', $.Event('show'), 'shown')
537
+ $.support.transition && this.$element[dimension](this.$element[0][scroll])
462
538
  }
463
539
 
464
540
  , hide: function () {
465
- var dimension = this.dimension()
541
+ var dimension
542
+ if (this.transitioning || !this.$element.hasClass('in')) return
543
+ dimension = this.dimension()
466
544
  this.reset(this.$element[dimension]())
467
- this.transition('removeClass', 'hide', 'hidden')
545
+ this.transition('removeClass', $.Event('hide'), 'hidden')
468
546
  this.$element[dimension](0)
469
547
  }
470
548
 
471
- , reset: function ( size ) {
549
+ , reset: function (size) {
472
550
  var dimension = this.dimension()
473
551
 
474
552
  this.$element
@@ -476,41 +554,49 @@
476
554
  [dimension](size || 'auto')
477
555
  [0].offsetWidth
478
556
 
479
- this.$element[size ? 'addClass' : 'removeClass']('collapse')
557
+ this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
480
558
 
481
559
  return this
482
560
  }
483
561
 
484
- , transition: function ( method, startEvent, completeEvent ) {
562
+ , transition: function (method, startEvent, completeEvent) {
485
563
  var that = this
486
564
  , complete = function () {
487
- if (startEvent == 'show') that.reset()
565
+ if (startEvent.type == 'show') that.reset()
566
+ that.transitioning = 0
488
567
  that.$element.trigger(completeEvent)
489
568
  }
490
569
 
491
- this.$element
492
- .trigger(startEvent)
493
- [method]('in')
570
+ this.$element.trigger(startEvent)
571
+
572
+ if (startEvent.isDefaultPrevented()) return
573
+
574
+ this.transitioning = 1
575
+
576
+ this.$element[method]('in')
494
577
 
495
578
  $.support.transition && this.$element.hasClass('collapse') ?
496
579
  this.$element.one($.support.transition.end, complete) :
497
580
  complete()
498
- }
581
+ }
499
582
 
500
583
  , toggle: function () {
501
584
  this[this.$element.hasClass('in') ? 'hide' : 'show']()
502
- }
585
+ }
503
586
 
504
587
  }
505
588
 
506
- /* COLLAPSIBLE PLUGIN DEFINITION
507
- * ============================== */
508
589
 
509
- $.fn.collapse = function ( option ) {
590
+ /* COLLAPSE PLUGIN DEFINITION
591
+ * ========================== */
592
+
593
+ var old = $.fn.collapse
594
+
595
+ $.fn.collapse = function (option) {
510
596
  return this.each(function () {
511
597
  var $this = $(this)
512
598
  , data = $this.data('collapse')
513
- , options = typeof option == 'object' && option
599
+ , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
514
600
  if (!data) $this.data('collapse', (data = new Collapse(this, options)))
515
601
  if (typeof option == 'string') data[option]()
516
602
  })
@@ -523,25 +609,33 @@
523
609
  $.fn.collapse.Constructor = Collapse
524
610
 
525
611
 
526
- /* COLLAPSIBLE DATA-API
612
+ /* COLLAPSE NO CONFLICT
527
613
  * ==================== */
528
614
 
529
- $(function () {
530
- $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
531
- var $this = $(this), href
532
- , target = $this.attr('data-target')
533
- || e.preventDefault()
534
- || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
535
- , option = $(target).data('collapse') ? 'toggle' : $this.data()
536
- $(target).collapse(option)
537
- })
615
+ $.fn.collapse.noConflict = function () {
616
+ $.fn.collapse = old
617
+ return this
618
+ }
619
+
620
+
621
+ /* COLLAPSE DATA-API
622
+ * ================= */
623
+
624
+ $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
625
+ var $this = $(this), href
626
+ , target = $this.attr('data-target')
627
+ || e.preventDefault()
628
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
629
+ , option = $(target).data('collapse') ? 'toggle' : $this.data()
630
+ $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
631
+ $(target).collapse(option)
538
632
  })
539
633
 
540
- }( window.jQuery );/* ============================================================
541
- * bootstrap-dropdown.js v2.0.2
542
- * http://twitter.github.com/bootstrap/javascript.html#dropdowns
634
+ }(window.jQuery);/* ============================================================
635
+ * bootstrap-dropdown.js v2.3.2
636
+ * http://getbootstrap.com/2.3.2/javascript.html#dropdowns
543
637
  * ============================================================
544
- * Copyright 2012 Twitter, Inc.
638
+ * Copyright 2013 Twitter, Inc.
545
639
  *
546
640
  * Licensed under the Apache License, Version 2.0 (the "License");
547
641
  * you may not use this file except in compliance with the License.
@@ -557,15 +651,16 @@
557
651
  * ============================================================ */
558
652
 
559
653
 
560
- !function( $ ){
654
+ !function ($) {
655
+
656
+ "use strict"; // jshint ;_;
561
657
 
562
- "use strict"
563
658
 
564
659
  /* DROPDOWN CLASS DEFINITION
565
660
  * ========================= */
566
661
 
567
- var toggle = '[data-toggle="dropdown"]'
568
- , Dropdown = function ( element ) {
662
+ var toggle = '[data-toggle=dropdown]'
663
+ , Dropdown = function (element) {
569
664
  var $el = $(element).on('click.dropdown.data-api', this.toggle)
570
665
  $('html').on('click.dropdown.data-api', function () {
571
666
  $el.parent().removeClass('open')
@@ -576,39 +671,105 @@
576
671
 
577
672
  constructor: Dropdown
578
673
 
579
- , toggle: function ( e ) {
674
+ , toggle: function (e) {
580
675
  var $this = $(this)
581
- , selector = $this.attr('data-target')
582
676
  , $parent
583
677
  , isActive
584
678
 
585
- if (!selector) {
586
- selector = $this.attr('href')
587
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
588
- }
679
+ if ($this.is('.disabled, :disabled')) return
589
680
 
590
- $parent = $(selector)
591
- $parent.length || ($parent = $this.parent())
681
+ $parent = getParent($this)
592
682
 
593
683
  isActive = $parent.hasClass('open')
594
684
 
595
685
  clearMenus()
596
- !isActive && $parent.toggleClass('open')
686
+
687
+ if (!isActive) {
688
+ if ('ontouchstart' in document.documentElement) {
689
+ // if mobile we we use a backdrop because click events don't delegate
690
+ $('<div class="dropdown-backdrop"/>').insertBefore($(this)).on('click', clearMenus)
691
+ }
692
+ $parent.toggleClass('open')
693
+ }
694
+
695
+ $this.focus()
597
696
 
598
697
  return false
599
698
  }
600
699
 
700
+ , keydown: function (e) {
701
+ var $this
702
+ , $items
703
+ , $active
704
+ , $parent
705
+ , isActive
706
+ , index
707
+
708
+ if (!/(38|40|27)/.test(e.keyCode)) return
709
+
710
+ $this = $(this)
711
+
712
+ e.preventDefault()
713
+ e.stopPropagation()
714
+
715
+ if ($this.is('.disabled, :disabled')) return
716
+
717
+ $parent = getParent($this)
718
+
719
+ isActive = $parent.hasClass('open')
720
+
721
+ if (!isActive || (isActive && e.keyCode == 27)) {
722
+ if (e.which == 27) $parent.find(toggle).focus()
723
+ return $this.click()
724
+ }
725
+
726
+ $items = $('[role=menu] li:not(.divider):visible a', $parent)
727
+
728
+ if (!$items.length) return
729
+
730
+ index = $items.index($items.filter(':focus'))
731
+
732
+ if (e.keyCode == 38 && index > 0) index-- // up
733
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
734
+ if (!~index) index = 0
735
+
736
+ $items
737
+ .eq(index)
738
+ .focus()
739
+ }
740
+
601
741
  }
602
742
 
603
743
  function clearMenus() {
604
- $(toggle).parent().removeClass('open')
744
+ $('.dropdown-backdrop').remove()
745
+ $(toggle).each(function () {
746
+ getParent($(this)).removeClass('open')
747
+ })
748
+ }
749
+
750
+ function getParent($this) {
751
+ var selector = $this.attr('data-target')
752
+ , $parent
753
+
754
+ if (!selector) {
755
+ selector = $this.attr('href')
756
+ selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
757
+ }
758
+
759
+ $parent = selector && $(selector)
760
+
761
+ if (!$parent || !$parent.length) $parent = $this.parent()
762
+
763
+ return $parent
605
764
  }
606
765
 
607
766
 
608
767
  /* DROPDOWN PLUGIN DEFINITION
609
768
  * ========================== */
610
769
 
611
- $.fn.dropdown = function ( option ) {
770
+ var old = $.fn.dropdown
771
+
772
+ $.fn.dropdown = function (option) {
612
773
  return this.each(function () {
613
774
  var $this = $(this)
614
775
  , data = $this.data('dropdown')
@@ -620,19 +781,30 @@
620
781
  $.fn.dropdown.Constructor = Dropdown
621
782
 
622
783
 
784
+ /* DROPDOWN NO CONFLICT
785
+ * ==================== */
786
+
787
+ $.fn.dropdown.noConflict = function () {
788
+ $.fn.dropdown = old
789
+ return this
790
+ }
791
+
792
+
623
793
  /* APPLY TO STANDARD DROPDOWN ELEMENTS
624
794
  * =================================== */
625
795
 
626
- $(function () {
627
- $('html').on('click.dropdown.data-api', clearMenus)
628
- $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
629
- })
796
+ $(document)
797
+ .on('click.dropdown.data-api', clearMenus)
798
+ .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
799
+ .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
800
+ .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
630
801
 
631
- }( window.jQuery );/* =========================================================
632
- * bootstrap-modal.js v2.0.2
633
- * http://twitter.github.com/bootstrap/javascript.html#modals
802
+ }(window.jQuery);
803
+ /* =========================================================
804
+ * bootstrap-modal.js v2.3.2
805
+ * http://getbootstrap.com/2.3.2/javascript.html#modals
634
806
  * =========================================================
635
- * Copyright 2012 Twitter, Inc.
807
+ * Copyright 2013 Twitter, Inc.
636
808
  *
637
809
  * Licensed under the Apache License, Version 2.0 (the "License");
638
810
  * you may not use this file except in compliance with the License.
@@ -648,17 +820,19 @@
648
820
  * ========================================================= */
649
821
 
650
822
 
651
- !function( $ ){
823
+ !function ($) {
824
+
825
+ "use strict"; // jshint ;_;
652
826
 
653
- "use strict"
654
827
 
655
828
  /* MODAL CLASS DEFINITION
656
829
  * ====================== */
657
830
 
658
- var Modal = function ( content, options ) {
831
+ var Modal = function (element, options) {
659
832
  this.options = options
660
- this.$element = $(content)
833
+ this.$element = $(element)
661
834
  .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
835
+ this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
662
836
  }
663
837
 
664
838
  Modal.prototype = {
@@ -671,139 +845,161 @@
671
845
 
672
846
  , show: function () {
673
847
  var that = this
848
+ , e = $.Event('show')
674
849
 
675
- if (this.isShown) return
850
+ this.$element.trigger(e)
676
851
 
677
- $('body').addClass('modal-open')
852
+ if (this.isShown || e.isDefaultPrevented()) return
678
853
 
679
854
  this.isShown = true
680
- this.$element.trigger('show')
681
855
 
682
- escape.call(this)
683
- backdrop.call(this, function () {
856
+ this.escape()
857
+
858
+ this.backdrop(function () {
684
859
  var transition = $.support.transition && that.$element.hasClass('fade')
685
860
 
686
- !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position
861
+ if (!that.$element.parent().length) {
862
+ that.$element.appendTo(document.body) //don't move modals dom position
863
+ }
687
864
 
688
- that.$element
689
- .show()
865
+ that.$element.show()
690
866
 
691
867
  if (transition) {
692
868
  that.$element[0].offsetWidth // force reflow
693
869
  }
694
870
 
695
- that.$element.addClass('in')
871
+ that.$element
872
+ .addClass('in')
873
+ .attr('aria-hidden', false)
874
+
875
+ that.enforceFocus()
696
876
 
697
877
  transition ?
698
- that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
699
- that.$element.trigger('shown')
878
+ that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
879
+ that.$element.focus().trigger('shown')
700
880
 
701
881
  })
702
882
  }
703
883
 
704
- , hide: function ( e ) {
884
+ , hide: function (e) {
705
885
  e && e.preventDefault()
706
886
 
707
- if (!this.isShown) return
708
-
709
887
  var that = this
888
+
889
+ e = $.Event('hide')
890
+
891
+ this.$element.trigger(e)
892
+
893
+ if (!this.isShown || e.isDefaultPrevented()) return
894
+
710
895
  this.isShown = false
711
896
 
712
- $('body').removeClass('modal-open')
897
+ this.escape()
713
898
 
714
- escape.call(this)
899
+ $(document).off('focusin.modal')
715
900
 
716
901
  this.$element
717
- .trigger('hide')
718
902
  .removeClass('in')
903
+ .attr('aria-hidden', true)
719
904
 
720
905
  $.support.transition && this.$element.hasClass('fade') ?
721
- hideWithTransition.call(this) :
722
- hideModal.call(this)
906
+ this.hideWithTransition() :
907
+ this.hideModal()
723
908
  }
724
909
 
725
- }
726
-
727
-
728
- /* MODAL PRIVATE METHODS
729
- * ===================== */
910
+ , enforceFocus: function () {
911
+ var that = this
912
+ $(document).on('focusin.modal', function (e) {
913
+ if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
914
+ that.$element.focus()
915
+ }
916
+ })
917
+ }
730
918
 
731
- function hideWithTransition() {
732
- var that = this
733
- , timeout = setTimeout(function () {
734
- that.$element.off($.support.transition.end)
735
- hideModal.call(that)
736
- }, 500)
919
+ , escape: function () {
920
+ var that = this
921
+ if (this.isShown && this.options.keyboard) {
922
+ this.$element.on('keyup.dismiss.modal', function ( e ) {
923
+ e.which == 27 && that.hide()
924
+ })
925
+ } else if (!this.isShown) {
926
+ this.$element.off('keyup.dismiss.modal')
927
+ }
928
+ }
737
929
 
738
- this.$element.one($.support.transition.end, function () {
739
- clearTimeout(timeout)
740
- hideModal.call(that)
741
- })
742
- }
930
+ , hideWithTransition: function () {
931
+ var that = this
932
+ , timeout = setTimeout(function () {
933
+ that.$element.off($.support.transition.end)
934
+ that.hideModal()
935
+ }, 500)
743
936
 
744
- function hideModal( that ) {
745
- this.$element
746
- .hide()
747
- .trigger('hidden')
937
+ this.$element.one($.support.transition.end, function () {
938
+ clearTimeout(timeout)
939
+ that.hideModal()
940
+ })
941
+ }
748
942
 
749
- backdrop.call(this)
750
- }
943
+ , hideModal: function () {
944
+ var that = this
945
+ this.$element.hide()
946
+ this.backdrop(function () {
947
+ that.removeBackdrop()
948
+ that.$element.trigger('hidden')
949
+ })
950
+ }
751
951
 
752
- function backdrop( callback ) {
753
- var that = this
754
- , animate = this.$element.hasClass('fade') ? 'fade' : ''
952
+ , removeBackdrop: function () {
953
+ this.$backdrop && this.$backdrop.remove()
954
+ this.$backdrop = null
955
+ }
755
956
 
756
- if (this.isShown && this.options.backdrop) {
757
- var doAnimate = $.support.transition && animate
957
+ , backdrop: function (callback) {
958
+ var that = this
959
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
758
960
 
759
- this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
760
- .appendTo(document.body)
961
+ if (this.isShown && this.options.backdrop) {
962
+ var doAnimate = $.support.transition && animate
761
963
 
762
- if (this.options.backdrop != 'static') {
763
- this.$backdrop.click($.proxy(this.hide, this))
764
- }
964
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
965
+ .appendTo(document.body)
765
966
 
766
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
967
+ this.$backdrop.click(
968
+ this.options.backdrop == 'static' ?
969
+ $.proxy(this.$element[0].focus, this.$element[0])
970
+ : $.proxy(this.hide, this)
971
+ )
767
972
 
768
- this.$backdrop.addClass('in')
973
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
769
974
 
770
- doAnimate ?
771
- this.$backdrop.one($.support.transition.end, callback) :
772
- callback()
975
+ this.$backdrop.addClass('in')
773
976
 
774
- } else if (!this.isShown && this.$backdrop) {
775
- this.$backdrop.removeClass('in')
977
+ if (!callback) return
776
978
 
777
- $.support.transition && this.$element.hasClass('fade')?
778
- this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
779
- removeBackdrop.call(this)
979
+ doAnimate ?
980
+ this.$backdrop.one($.support.transition.end, callback) :
981
+ callback()
780
982
 
781
- } else if (callback) {
782
- callback()
783
- }
784
- }
983
+ } else if (!this.isShown && this.$backdrop) {
984
+ this.$backdrop.removeClass('in')
785
985
 
786
- function removeBackdrop() {
787
- this.$backdrop.remove()
788
- this.$backdrop = null
789
- }
986
+ $.support.transition && this.$element.hasClass('fade')?
987
+ this.$backdrop.one($.support.transition.end, callback) :
988
+ callback()
790
989
 
791
- function escape() {
792
- var that = this
793
- if (this.isShown && this.options.keyboard) {
794
- $(document).on('keyup.dismiss.modal', function ( e ) {
795
- e.which == 27 && that.hide()
796
- })
797
- } else if (!this.isShown) {
798
- $(document).off('keyup.dismiss.modal')
799
- }
990
+ } else if (callback) {
991
+ callback()
992
+ }
993
+ }
800
994
  }
801
995
 
802
996
 
803
997
  /* MODAL PLUGIN DEFINITION
804
998
  * ======================= */
805
999
 
806
- $.fn.modal = function ( option ) {
1000
+ var old = $.fn.modal
1001
+
1002
+ $.fn.modal = function (option) {
807
1003
  return this.each(function () {
808
1004
  var $this = $(this)
809
1005
  , data = $this.data('modal')
@@ -823,26 +1019,40 @@
823
1019
  $.fn.modal.Constructor = Modal
824
1020
 
825
1021
 
1022
+ /* MODAL NO CONFLICT
1023
+ * ================= */
1024
+
1025
+ $.fn.modal.noConflict = function () {
1026
+ $.fn.modal = old
1027
+ return this
1028
+ }
1029
+
1030
+
826
1031
  /* MODAL DATA-API
827
1032
  * ============== */
828
1033
 
829
- $(function () {
830
- $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
831
- var $this = $(this), href
832
- , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
833
- , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
1034
+ $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
1035
+ var $this = $(this)
1036
+ , href = $this.attr('href')
1037
+ , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
1038
+ , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
834
1039
 
835
- e.preventDefault()
836
- $target.modal(option)
837
- })
1040
+ e.preventDefault()
1041
+
1042
+ $target
1043
+ .modal(option)
1044
+ .one('hide', function () {
1045
+ $this.focus()
1046
+ })
838
1047
  })
839
1048
 
840
- }( window.jQuery );/* ===========================================================
841
- * bootstrap-tooltip.js v2.0.2
842
- * http://twitter.github.com/bootstrap/javascript.html#tooltips
1049
+ }(window.jQuery);
1050
+ /* ===========================================================
1051
+ * bootstrap-tooltip.js v2.3.2
1052
+ * http://getbootstrap.com/2.3.2/javascript.html#tooltips
843
1053
  * Inspired by the original jQuery.tipsy by Jason Frame
844
1054
  * ===========================================================
845
- * Copyright 2012 Twitter, Inc.
1055
+ * Copyright 2013 Twitter, Inc.
846
1056
  *
847
1057
  * Licensed under the Apache License, Version 2.0 (the "License");
848
1058
  * you may not use this file except in compliance with the License.
@@ -857,14 +1067,16 @@
857
1067
  * limitations under the License.
858
1068
  * ========================================================== */
859
1069
 
860
- !function( $ ) {
861
1070
 
862
- "use strict"
1071
+ !function ($) {
1072
+
1073
+ "use strict"; // jshint ;_;
1074
+
863
1075
 
864
1076
  /* TOOLTIP PUBLIC CLASS DEFINITION
865
1077
  * =============================== */
866
1078
 
867
- var Tooltip = function ( element, options ) {
1079
+ var Tooltip = function (element, options) {
868
1080
  this.init('tooltip', element, options)
869
1081
  }
870
1082
 
@@ -872,20 +1084,30 @@
872
1084
 
873
1085
  constructor: Tooltip
874
1086
 
875
- , init: function ( type, element, options ) {
1087
+ , init: function (type, element, options) {
876
1088
  var eventIn
877
1089
  , eventOut
1090
+ , triggers
1091
+ , trigger
1092
+ , i
878
1093
 
879
1094
  this.type = type
880
1095
  this.$element = $(element)
881
1096
  this.options = this.getOptions(options)
882
1097
  this.enabled = true
883
1098
 
884
- if (this.options.trigger != 'manual') {
885
- eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
886
- eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
887
- this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
888
- this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
1099
+ triggers = this.options.trigger.split(' ')
1100
+
1101
+ for (i = triggers.length; i--;) {
1102
+ trigger = triggers[i]
1103
+ if (trigger == 'click') {
1104
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1105
+ } else if (trigger != 'manual') {
1106
+ eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
1107
+ eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
1108
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1109
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1110
+ }
889
1111
  }
890
1112
 
891
1113
  this.options.selector ?
@@ -893,8 +1115,8 @@
893
1115
  this.fixTitle()
894
1116
  }
895
1117
 
896
- , getOptions: function ( options ) {
897
- options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
1118
+ , getOptions: function (options) {
1119
+ options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
898
1120
 
899
1121
  if (options.delay && typeof options.delay == 'number') {
900
1122
  options.delay = {
@@ -906,46 +1128,50 @@
906
1128
  return options
907
1129
  }
908
1130
 
909
- , enter: function ( e ) {
910
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
1131
+ , enter: function (e) {
1132
+ var defaults = $.fn[this.type].defaults
1133
+ , options = {}
1134
+ , self
911
1135
 
912
- if (!self.options.delay || !self.options.delay.show) {
913
- self.show()
914
- } else {
915
- self.hoverState = 'in'
916
- setTimeout(function() {
917
- if (self.hoverState == 'in') {
918
- self.show()
919
- }
920
- }, self.options.delay.show)
921
- }
1136
+ this._options && $.each(this._options, function (key, value) {
1137
+ if (defaults[key] != value) options[key] = value
1138
+ }, this)
1139
+
1140
+ self = $(e.currentTarget)[this.type](options).data(this.type)
1141
+
1142
+ if (!self.options.delay || !self.options.delay.show) return self.show()
1143
+
1144
+ clearTimeout(this.timeout)
1145
+ self.hoverState = 'in'
1146
+ this.timeout = setTimeout(function() {
1147
+ if (self.hoverState == 'in') self.show()
1148
+ }, self.options.delay.show)
922
1149
  }
923
1150
 
924
- , leave: function ( e ) {
1151
+ , leave: function (e) {
925
1152
  var self = $(e.currentTarget)[this.type](this._options).data(this.type)
926
1153
 
927
- if (!self.options.delay || !self.options.delay.hide) {
928
- self.hide()
929
- } else {
930
- self.hoverState = 'out'
931
- setTimeout(function() {
932
- if (self.hoverState == 'out') {
933
- self.hide()
934
- }
935
- }, self.options.delay.hide)
936
- }
1154
+ if (this.timeout) clearTimeout(this.timeout)
1155
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
1156
+
1157
+ self.hoverState = 'out'
1158
+ this.timeout = setTimeout(function() {
1159
+ if (self.hoverState == 'out') self.hide()
1160
+ }, self.options.delay.hide)
937
1161
  }
938
1162
 
939
1163
  , show: function () {
940
1164
  var $tip
941
- , inside
942
1165
  , pos
943
1166
  , actualWidth
944
1167
  , actualHeight
945
1168
  , placement
946
1169
  , tp
1170
+ , e = $.Event('show')
947
1171
 
948
1172
  if (this.hasContent() && this.enabled) {
1173
+ this.$element.trigger(e)
1174
+ if (e.isDefaultPrevented()) return
949
1175
  $tip = this.tip()
950
1176
  this.setContent()
951
1177
 
@@ -957,19 +1183,18 @@
957
1183
  this.options.placement.call(this, $tip[0], this.$element[0]) :
958
1184
  this.options.placement
959
1185
 
960
- inside = /in/.test(placement)
961
-
962
1186
  $tip
963
- .remove()
1187
+ .detach()
964
1188
  .css({ top: 0, left: 0, display: 'block' })
965
- .appendTo(inside ? this.$element : document.body)
966
1189
 
967
- pos = this.getPosition(inside)
1190
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1191
+
1192
+ pos = this.getPosition()
968
1193
 
969
1194
  actualWidth = $tip[0].offsetWidth
970
1195
  actualHeight = $tip[0].offsetHeight
971
1196
 
972
- switch (inside ? placement.split(' ')[1] : placement) {
1197
+ switch (placement) {
973
1198
  case 'bottom':
974
1199
  tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
975
1200
  break
@@ -984,45 +1209,100 @@
984
1209
  break
985
1210
  }
986
1211
 
987
- $tip
988
- .css(tp)
989
- .addClass(placement)
990
- .addClass('in')
1212
+ this.applyPlacement(tp, placement)
1213
+ this.$element.trigger('shown')
991
1214
  }
992
1215
  }
993
1216
 
1217
+ , applyPlacement: function(offset, placement){
1218
+ var $tip = this.tip()
1219
+ , width = $tip[0].offsetWidth
1220
+ , height = $tip[0].offsetHeight
1221
+ , actualWidth
1222
+ , actualHeight
1223
+ , delta
1224
+ , replace
1225
+
1226
+ $tip
1227
+ .offset(offset)
1228
+ .addClass(placement)
1229
+ .addClass('in')
1230
+
1231
+ actualWidth = $tip[0].offsetWidth
1232
+ actualHeight = $tip[0].offsetHeight
1233
+
1234
+ if (placement == 'top' && actualHeight != height) {
1235
+ offset.top = offset.top + height - actualHeight
1236
+ replace = true
1237
+ }
1238
+
1239
+ if (placement == 'bottom' || placement == 'top') {
1240
+ delta = 0
1241
+
1242
+ if (offset.left < 0){
1243
+ delta = offset.left * -2
1244
+ offset.left = 0
1245
+ $tip.offset(offset)
1246
+ actualWidth = $tip[0].offsetWidth
1247
+ actualHeight = $tip[0].offsetHeight
1248
+ }
1249
+
1250
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
1251
+ } else {
1252
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
1253
+ }
1254
+
1255
+ if (replace) $tip.offset(offset)
1256
+ }
1257
+
1258
+ , replaceArrow: function(delta, dimension, position){
1259
+ this
1260
+ .arrow()
1261
+ .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
1262
+ }
1263
+
994
1264
  , setContent: function () {
995
1265
  var $tip = this.tip()
996
- $tip.find('.tooltip-inner').html(this.getTitle())
1266
+ , title = this.getTitle()
1267
+
1268
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
997
1269
  $tip.removeClass('fade in top bottom left right')
998
1270
  }
999
1271
 
1000
1272
  , hide: function () {
1001
1273
  var that = this
1002
1274
  , $tip = this.tip()
1275
+ , e = $.Event('hide')
1276
+
1277
+ this.$element.trigger(e)
1278
+ if (e.isDefaultPrevented()) return
1003
1279
 
1004
1280
  $tip.removeClass('in')
1005
1281
 
1006
1282
  function removeWithAnimation() {
1007
1283
  var timeout = setTimeout(function () {
1008
- $tip.off($.support.transition.end).remove()
1284
+ $tip.off($.support.transition.end).detach()
1009
1285
  }, 500)
1010
1286
 
1011
1287
  $tip.one($.support.transition.end, function () {
1012
1288
  clearTimeout(timeout)
1013
- $tip.remove()
1289
+ $tip.detach()
1014
1290
  })
1015
1291
  }
1016
1292
 
1017
1293
  $.support.transition && this.$tip.hasClass('fade') ?
1018
1294
  removeWithAnimation() :
1019
- $tip.remove()
1295
+ $tip.detach()
1296
+
1297
+ this.$element.trigger('hidden')
1298
+
1299
+ return this
1020
1300
  }
1021
1301
 
1022
1302
  , fixTitle: function () {
1023
1303
  var $e = this.$element
1024
1304
  if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
1025
- $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
1305
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1026
1306
  }
1027
1307
  }
1028
1308
 
@@ -1030,11 +1310,12 @@
1030
1310
  return this.getTitle()
1031
1311
  }
1032
1312
 
1033
- , getPosition: function (inside) {
1034
- return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
1035
- width: this.$element[0].offsetWidth
1036
- , height: this.$element[0].offsetHeight
1037
- })
1313
+ , getPosition: function () {
1314
+ var el = this.$element[0]
1315
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
1316
+ width: el.offsetWidth
1317
+ , height: el.offsetHeight
1318
+ }, this.$element.offset())
1038
1319
  }
1039
1320
 
1040
1321
  , getTitle: function () {
@@ -1045,8 +1326,6 @@
1045
1326
  title = $e.attr('data-original-title')
1046
1327
  || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1047
1328
 
1048
- title = (title || '').toString().replace(/(^\s*|\s*$)/, "")
1049
-
1050
1329
  return title
1051
1330
  }
1052
1331
 
@@ -1054,6 +1333,10 @@
1054
1333
  return this.$tip = this.$tip || $(this.options.template)
1055
1334
  }
1056
1335
 
1336
+ , arrow: function(){
1337
+ return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
1338
+ }
1339
+
1057
1340
  , validate: function () {
1058
1341
  if (!this.$element[0].parentNode) {
1059
1342
  this.hide()
@@ -1074,8 +1357,13 @@
1074
1357
  this.enabled = !this.enabled
1075
1358
  }
1076
1359
 
1077
- , toggle: function () {
1078
- this[this.tip().hasClass('in') ? 'hide' : 'show']()
1360
+ , toggle: function (e) {
1361
+ var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
1362
+ self.tip().hasClass('in') ? self.hide() : self.show()
1363
+ }
1364
+
1365
+ , destroy: function () {
1366
+ this.hide().$element.off('.' + this.type).removeData(this.type)
1079
1367
  }
1080
1368
 
1081
1369
  }
@@ -1084,6 +1372,8 @@
1084
1372
  /* TOOLTIP PLUGIN DEFINITION
1085
1373
  * ========================= */
1086
1374
 
1375
+ var old = $.fn.tooltip
1376
+
1087
1377
  $.fn.tooltip = function ( option ) {
1088
1378
  return this.each(function () {
1089
1379
  var $this = $(this)
@@ -1098,19 +1388,31 @@
1098
1388
 
1099
1389
  $.fn.tooltip.defaults = {
1100
1390
  animation: true
1101
- , delay: 0
1102
- , selector: false
1103
1391
  , placement: 'top'
1104
- , trigger: 'hover'
1105
- , title: ''
1392
+ , selector: false
1106
1393
  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
1394
+ , trigger: 'hover focus'
1395
+ , title: ''
1396
+ , delay: 0
1397
+ , html: false
1398
+ , container: false
1399
+ }
1400
+
1401
+
1402
+ /* TOOLTIP NO CONFLICT
1403
+ * =================== */
1404
+
1405
+ $.fn.tooltip.noConflict = function () {
1406
+ $.fn.tooltip = old
1407
+ return this
1107
1408
  }
1108
1409
 
1109
- }( window.jQuery );/* ===========================================================
1110
- * bootstrap-popover.js v2.0.2
1111
- * http://twitter.github.com/bootstrap/javascript.html#popovers
1410
+ }(window.jQuery);
1411
+ /* ===========================================================
1412
+ * bootstrap-popover.js v2.3.2
1413
+ * http://getbootstrap.com/2.3.2/javascript.html#popovers
1112
1414
  * ===========================================================
1113
- * Copyright 2012 Twitter, Inc.
1415
+ * Copyright 2013 Twitter, Inc.
1114
1416
  *
1115
1417
  * Licensed under the Apache License, Version 2.0 (the "License");
1116
1418
  * you may not use this file except in compliance with the License.
@@ -1126,14 +1428,19 @@
1126
1428
  * =========================================================== */
1127
1429
 
1128
1430
 
1129
- !function( $ ) {
1431
+ !function ($) {
1432
+
1433
+ "use strict"; // jshint ;_;
1130
1434
 
1131
- "use strict"
1132
1435
 
1133
- var Popover = function ( element, options ) {
1436
+ /* POPOVER PUBLIC CLASS DEFINITION
1437
+ * =============================== */
1438
+
1439
+ var Popover = function (element, options) {
1134
1440
  this.init('popover', element, options)
1135
1441
  }
1136
1442
 
1443
+
1137
1444
  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
1138
1445
  ========================================== */
1139
1446
 
@@ -1146,8 +1453,8 @@
1146
1453
  , title = this.getTitle()
1147
1454
  , content = this.getContent()
1148
1455
 
1149
- $tip.find('.popover-title')[ $.type(title) == 'object' ? 'append' : 'html' ](title)
1150
- $tip.find('.popover-content > *')[ $.type(content) == 'object' ? 'append' : 'html' ](content)
1456
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1457
+ $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
1151
1458
 
1152
1459
  $tip.removeClass('fade top bottom left right in')
1153
1460
  }
@@ -1161,28 +1468,32 @@
1161
1468
  , $e = this.$element
1162
1469
  , o = this.options
1163
1470
 
1164
- content = $e.attr('data-content')
1165
- || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1166
-
1167
- content = content.toString().replace(/(^\s*|\s*$)/, "")
1471
+ content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1472
+ || $e.attr('data-content')
1168
1473
 
1169
1474
  return content
1170
1475
  }
1171
1476
 
1172
- , tip: function() {
1477
+ , tip: function () {
1173
1478
  if (!this.$tip) {
1174
1479
  this.$tip = $(this.options.template)
1175
1480
  }
1176
1481
  return this.$tip
1177
1482
  }
1178
1483
 
1484
+ , destroy: function () {
1485
+ this.hide().$element.off('.' + this.type).removeData(this.type)
1486
+ }
1487
+
1179
1488
  })
1180
1489
 
1181
1490
 
1182
1491
  /* POPOVER PLUGIN DEFINITION
1183
1492
  * ======================= */
1184
1493
 
1185
- $.fn.popover = function ( option ) {
1494
+ var old = $.fn.popover
1495
+
1496
+ $.fn.popover = function (option) {
1186
1497
  return this.each(function () {
1187
1498
  var $this = $(this)
1188
1499
  , data = $this.data('popover')
@@ -1196,15 +1507,26 @@
1196
1507
 
1197
1508
  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1198
1509
  placement: 'right'
1510
+ , trigger: 'click'
1199
1511
  , content: ''
1200
- , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
1512
+ , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1201
1513
  })
1202
1514
 
1203
- }( window.jQuery );/* =============================================================
1204
- * bootstrap-scrollspy.js v2.0.2
1205
- * http://twitter.github.com/bootstrap/javascript.html#scrollspy
1515
+
1516
+ /* POPOVER NO CONFLICT
1517
+ * =================== */
1518
+
1519
+ $.fn.popover.noConflict = function () {
1520
+ $.fn.popover = old
1521
+ return this
1522
+ }
1523
+
1524
+ }(window.jQuery);
1525
+ /* =============================================================
1526
+ * bootstrap-scrollspy.js v2.3.2
1527
+ * http://getbootstrap.com/2.3.2/javascript.html#scrollspy
1206
1528
  * =============================================================
1207
- * Copyright 2012 Twitter, Inc.
1529
+ * Copyright 2013 Twitter, Inc.
1208
1530
  *
1209
1531
  * Licensed under the Apache License, Version 2.0 (the "License");
1210
1532
  * you may not use this file except in compliance with the License.
@@ -1219,23 +1541,25 @@
1219
1541
  * limitations under the License.
1220
1542
  * ============================================================== */
1221
1543
 
1222
- !function ( $ ) {
1223
1544
 
1224
- "use strict"
1545
+ !function ($) {
1225
1546
 
1226
- /* SCROLLSPY CLASS DEFINITION
1227
- * ========================== */
1547
+ "use strict"; // jshint ;_;
1548
+
1549
+
1550
+ /* SCROLLSPY CLASS DEFINITION
1551
+ * ========================== */
1228
1552
 
1229
- function ScrollSpy( element, options) {
1553
+ function ScrollSpy(element, options) {
1230
1554
  var process = $.proxy(this.process, this)
1231
1555
  , $element = $(element).is('body') ? $(window) : $(element)
1232
1556
  , href
1233
1557
  this.options = $.extend({}, $.fn.scrollspy.defaults, options)
1234
- this.$scrollElement = $element.on('scroll.scroll.data-api', process)
1558
+ this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
1235
1559
  this.selector = (this.options.target
1236
1560
  || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1237
1561
  || '') + ' .nav li > a'
1238
- this.$body = $('body').on('click.scroll.data-api', this.selector, process)
1562
+ this.$body = $('body')
1239
1563
  this.refresh()
1240
1564
  this.process()
1241
1565
  }
@@ -1245,25 +1569,43 @@
1245
1569
  constructor: ScrollSpy
1246
1570
 
1247
1571
  , refresh: function () {
1248
- this.targets = this.$body
1572
+ var self = this
1573
+ , $targets
1574
+
1575
+ this.offsets = $([])
1576
+ this.targets = $([])
1577
+
1578
+ $targets = this.$body
1249
1579
  .find(this.selector)
1250
1580
  .map(function () {
1251
- var href = $(this).attr('href')
1252
- return /^#\w/.test(href) && $(href).length ? href : null
1581
+ var $el = $(this)
1582
+ , href = $el.data('target') || $el.attr('href')
1583
+ , $href = /^#\w/.test(href) && $(href)
1584
+ return ( $href
1585
+ && $href.length
1586
+ && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
1587
+ })
1588
+ .sort(function (a, b) { return a[0] - b[0] })
1589
+ .each(function () {
1590
+ self.offsets.push(this[0])
1591
+ self.targets.push(this[1])
1253
1592
  })
1254
-
1255
- this.offsets = $.map(this.targets, function (id) {
1256
- return $(id).position().top
1257
- })
1258
1593
  }
1259
1594
 
1260
1595
  , process: function () {
1261
1596
  var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1597
+ , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
1598
+ , maxScroll = scrollHeight - this.$scrollElement.height()
1262
1599
  , offsets = this.offsets
1263
1600
  , targets = this.targets
1264
1601
  , activeTarget = this.activeTarget
1265
1602
  , i
1266
1603
 
1604
+ if (scrollTop >= maxScroll) {
1605
+ return activeTarget != (i = targets.last()[0])
1606
+ && this.activate ( i )
1607
+ }
1608
+
1267
1609
  for (i = offsets.length; i--;) {
1268
1610
  activeTarget != targets[i]
1269
1611
  && scrollTop >= offsets[i]
@@ -1274,21 +1616,27 @@
1274
1616
 
1275
1617
  , activate: function (target) {
1276
1618
  var active
1619
+ , selector
1277
1620
 
1278
1621
  this.activeTarget = target
1279
1622
 
1280
- this.$body
1281
- .find(this.selector).parent('.active')
1623
+ $(this.selector)
1624
+ .parent('.active')
1282
1625
  .removeClass('active')
1283
1626
 
1284
- active = this.$body
1285
- .find(this.selector + '[href="' + target + '"]')
1627
+ selector = this.selector
1628
+ + '[data-target="' + target + '"],'
1629
+ + this.selector + '[href="' + target + '"]'
1630
+
1631
+ active = $(selector)
1286
1632
  .parent('li')
1287
1633
  .addClass('active')
1288
1634
 
1289
- if ( active.parent('.dropdown-menu') ) {
1290
- active.closest('li.dropdown').addClass('active')
1635
+ if (active.parent('.dropdown-menu').length) {
1636
+ active = active.closest('li.dropdown').addClass('active')
1291
1637
  }
1638
+
1639
+ active.trigger('activate')
1292
1640
  }
1293
1641
 
1294
1642
  }
@@ -1297,7 +1645,9 @@
1297
1645
  /* SCROLLSPY PLUGIN DEFINITION
1298
1646
  * =========================== */
1299
1647
 
1300
- $.fn.scrollspy = function ( option ) {
1648
+ var old = $.fn.scrollspy
1649
+
1650
+ $.fn.scrollspy = function (option) {
1301
1651
  return this.each(function () {
1302
1652
  var $this = $(this)
1303
1653
  , data = $this.data('scrollspy')
@@ -1314,21 +1664,30 @@
1314
1664
  }
1315
1665
 
1316
1666
 
1667
+ /* SCROLLSPY NO CONFLICT
1668
+ * ===================== */
1669
+
1670
+ $.fn.scrollspy.noConflict = function () {
1671
+ $.fn.scrollspy = old
1672
+ return this
1673
+ }
1674
+
1675
+
1317
1676
  /* SCROLLSPY DATA-API
1318
1677
  * ================== */
1319
1678
 
1320
- $(function () {
1679
+ $(window).on('load', function () {
1321
1680
  $('[data-spy="scroll"]').each(function () {
1322
1681
  var $spy = $(this)
1323
1682
  $spy.scrollspy($spy.data())
1324
1683
  })
1325
1684
  })
1326
1685
 
1327
- }( window.jQuery );/* ========================================================
1328
- * bootstrap-tab.js v2.0.2
1329
- * http://twitter.github.com/bootstrap/javascript.html#tabs
1686
+ }(window.jQuery);/* ========================================================
1687
+ * bootstrap-tab.js v2.3.2
1688
+ * http://getbootstrap.com/2.3.2/javascript.html#tabs
1330
1689
  * ========================================================
1331
- * Copyright 2012 Twitter, Inc.
1690
+ * Copyright 2013 Twitter, Inc.
1332
1691
  *
1333
1692
  * Licensed under the Apache License, Version 2.0 (the "License");
1334
1693
  * you may not use this file except in compliance with the License.
@@ -1344,14 +1703,15 @@
1344
1703
  * ======================================================== */
1345
1704
 
1346
1705
 
1347
- !function( $ ){
1706
+ !function ($) {
1707
+
1708
+ "use strict"; // jshint ;_;
1348
1709
 
1349
- "use strict"
1350
1710
 
1351
1711
  /* TAB CLASS DEFINITION
1352
1712
  * ==================== */
1353
1713
 
1354
- var Tab = function ( element ) {
1714
+ var Tab = function (element) {
1355
1715
  this.element = $(element)
1356
1716
  }
1357
1717
 
@@ -1365,6 +1725,7 @@
1365
1725
  , selector = $this.attr('data-target')
1366
1726
  , previous
1367
1727
  , $target
1728
+ , e
1368
1729
 
1369
1730
  if (!selector) {
1370
1731
  selector = $this.attr('href')
@@ -1373,13 +1734,16 @@
1373
1734
 
1374
1735
  if ( $this.parent('li').hasClass('active') ) return
1375
1736
 
1376
- previous = $ul.find('.active a').last()[0]
1737
+ previous = $ul.find('.active:last a')[0]
1377
1738
 
1378
- $this.trigger({
1379
- type: 'show'
1380
- , relatedTarget: previous
1739
+ e = $.Event('show', {
1740
+ relatedTarget: previous
1381
1741
  })
1382
1742
 
1743
+ $this.trigger(e)
1744
+
1745
+ if (e.isDefaultPrevented()) return
1746
+
1383
1747
  $target = $(selector)
1384
1748
 
1385
1749
  this.activate($this.parent('li'), $ul)
@@ -1431,6 +1795,8 @@
1431
1795
  /* TAB PLUGIN DEFINITION
1432
1796
  * ===================== */
1433
1797
 
1798
+ var old = $.fn.tab
1799
+
1434
1800
  $.fn.tab = function ( option ) {
1435
1801
  return this.each(function () {
1436
1802
  var $this = $(this)
@@ -1443,21 +1809,28 @@
1443
1809
  $.fn.tab.Constructor = Tab
1444
1810
 
1445
1811
 
1812
+ /* TAB NO CONFLICT
1813
+ * =============== */
1814
+
1815
+ $.fn.tab.noConflict = function () {
1816
+ $.fn.tab = old
1817
+ return this
1818
+ }
1819
+
1820
+
1446
1821
  /* TAB DATA-API
1447
1822
  * ============ */
1448
1823
 
1449
- $(function () {
1450
- $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1451
- e.preventDefault()
1452
- $(this).tab('show')
1453
- })
1824
+ $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1825
+ e.preventDefault()
1826
+ $(this).tab('show')
1454
1827
  })
1455
1828
 
1456
- }( window.jQuery );/* =============================================================
1457
- * bootstrap-typeahead.js v2.0.2
1458
- * http://twitter.github.com/bootstrap/javascript.html#typeahead
1829
+ }(window.jQuery);/* =============================================================
1830
+ * bootstrap-typeahead.js v2.3.2
1831
+ * http://getbootstrap.com/2.3.2/javascript.html#typeahead
1459
1832
  * =============================================================
1460
- * Copyright 2012 Twitter, Inc.
1833
+ * Copyright 2013 Twitter, Inc.
1461
1834
  *
1462
1835
  * Licensed under the Apache License, Version 2.0 (the "License");
1463
1836
  * you may not use this file except in compliance with the License.
@@ -1472,18 +1845,24 @@
1472
1845
  * limitations under the License.
1473
1846
  * ============================================================ */
1474
1847
 
1475
- !function( $ ){
1476
1848
 
1477
- "use strict"
1849
+ !function($){
1850
+
1851
+ "use strict"; // jshint ;_;
1478
1852
 
1479
- var Typeahead = function ( element, options ) {
1853
+
1854
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
1855
+ * ================================= */
1856
+
1857
+ var Typeahead = function (element, options) {
1480
1858
  this.$element = $(element)
1481
1859
  this.options = $.extend({}, $.fn.typeahead.defaults, options)
1482
1860
  this.matcher = this.options.matcher || this.matcher
1483
1861
  this.sorter = this.options.sorter || this.sorter
1484
1862
  this.highlighter = this.options.highlighter || this.highlighter
1485
- this.$menu = $(this.options.menu).appendTo('body')
1863
+ this.updater = this.options.updater || this.updater
1486
1864
  this.source = this.options.source
1865
+ this.$menu = $(this.options.menu)
1487
1866
  this.shown = false
1488
1867
  this.listen()
1489
1868
  }
@@ -1494,22 +1873,29 @@
1494
1873
 
1495
1874
  , select: function () {
1496
1875
  var val = this.$menu.find('.active').attr('data-value')
1497
- this.$element.val(val)
1498
- this.$element.change();
1876
+ this.$element
1877
+ .val(this.updater(val))
1878
+ .change()
1499
1879
  return this.hide()
1500
1880
  }
1501
1881
 
1882
+ , updater: function (item) {
1883
+ return item
1884
+ }
1885
+
1502
1886
  , show: function () {
1503
- var pos = $.extend({}, this.$element.offset(), {
1887
+ var pos = $.extend({}, this.$element.position(), {
1504
1888
  height: this.$element[0].offsetHeight
1505
1889
  })
1506
1890
 
1507
- this.$menu.css({
1508
- top: pos.top + pos.height
1509
- , left: pos.left
1510
- })
1891
+ this.$menu
1892
+ .insertAfter(this.$element)
1893
+ .css({
1894
+ top: pos.top + pos.height
1895
+ , left: pos.left
1896
+ })
1897
+ .show()
1511
1898
 
1512
- this.$menu.show()
1513
1899
  this.shown = true
1514
1900
  return this
1515
1901
  }
@@ -1521,18 +1907,24 @@
1521
1907
  }
1522
1908
 
1523
1909
  , lookup: function (event) {
1524
- var that = this
1525
- , items
1526
- , q
1910
+ var items
1527
1911
 
1528
1912
  this.query = this.$element.val()
1529
1913
 
1530
- if (!this.query) {
1914
+ if (!this.query || this.query.length < this.options.minLength) {
1531
1915
  return this.shown ? this.hide() : this
1532
1916
  }
1533
1917
 
1534
- items = $.grep(this.source, function (item) {
1535
- if (that.matcher(item)) return item
1918
+ items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
1919
+
1920
+ return items ? this.process(items) : this
1921
+ }
1922
+
1923
+ , process: function (items) {
1924
+ var that = this
1925
+
1926
+ items = $.grep(items, function (item) {
1927
+ return that.matcher(item)
1536
1928
  })
1537
1929
 
1538
1930
  items = this.sorter(items)
@@ -1564,7 +1956,8 @@
1564
1956
  }
1565
1957
 
1566
1958
  , highlighter: function (item) {
1567
- return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
1959
+ var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1960
+ return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1568
1961
  return '<strong>' + match + '</strong>'
1569
1962
  })
1570
1963
  }
@@ -1607,23 +2000,71 @@
1607
2000
 
1608
2001
  , listen: function () {
1609
2002
  this.$element
2003
+ .on('focus', $.proxy(this.focus, this))
1610
2004
  .on('blur', $.proxy(this.blur, this))
1611
2005
  .on('keypress', $.proxy(this.keypress, this))
1612
2006
  .on('keyup', $.proxy(this.keyup, this))
1613
2007
 
1614
- if ($.browser.webkit || $.browser.msie) {
1615
- this.$element.on('keydown', $.proxy(this.keypress, this))
2008
+ if (this.eventSupported('keydown')) {
2009
+ this.$element.on('keydown', $.proxy(this.keydown, this))
1616
2010
  }
1617
2011
 
1618
2012
  this.$menu
1619
2013
  .on('click', $.proxy(this.click, this))
1620
2014
  .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
2015
+ .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
2016
+ }
2017
+
2018
+ , eventSupported: function(eventName) {
2019
+ var isSupported = eventName in this.$element
2020
+ if (!isSupported) {
2021
+ this.$element.setAttribute(eventName, 'return;')
2022
+ isSupported = typeof this.$element[eventName] === 'function'
2023
+ }
2024
+ return isSupported
2025
+ }
2026
+
2027
+ , move: function (e) {
2028
+ if (!this.shown) return
2029
+
2030
+ switch(e.keyCode) {
2031
+ case 9: // tab
2032
+ case 13: // enter
2033
+ case 27: // escape
2034
+ e.preventDefault()
2035
+ break
2036
+
2037
+ case 38: // up arrow
2038
+ e.preventDefault()
2039
+ this.prev()
2040
+ break
2041
+
2042
+ case 40: // down arrow
2043
+ e.preventDefault()
2044
+ this.next()
2045
+ break
2046
+ }
2047
+
2048
+ e.stopPropagation()
2049
+ }
2050
+
2051
+ , keydown: function (e) {
2052
+ this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
2053
+ this.move(e)
2054
+ }
2055
+
2056
+ , keypress: function (e) {
2057
+ if (this.suppressKeyPressRepeat) return
2058
+ this.move(e)
1621
2059
  }
1622
2060
 
1623
2061
  , keyup: function (e) {
1624
2062
  switch(e.keyCode) {
1625
2063
  case 40: // down arrow
1626
2064
  case 38: // up arrow
2065
+ case 16: // shift
2066
+ case 17: // ctrl
2067
+ case 18: // alt
1627
2068
  break
1628
2069
 
1629
2070
  case 9: // tab
@@ -1645,53 +2086,42 @@
1645
2086
  e.preventDefault()
1646
2087
  }
1647
2088
 
1648
- , keypress: function (e) {
1649
- if (!this.shown) return
1650
-
1651
- switch(e.keyCode) {
1652
- case 9: // tab
1653
- case 13: // enter
1654
- case 27: // escape
1655
- e.preventDefault()
1656
- break
1657
-
1658
- case 38: // up arrow
1659
- e.preventDefault()
1660
- this.prev()
1661
- break
1662
-
1663
- case 40: // down arrow
1664
- e.preventDefault()
1665
- this.next()
1666
- break
1667
- }
1668
-
1669
- e.stopPropagation()
2089
+ , focus: function (e) {
2090
+ this.focused = true
1670
2091
  }
1671
2092
 
1672
2093
  , blur: function (e) {
1673
- var that = this
1674
- setTimeout(function () { that.hide() }, 150)
2094
+ this.focused = false
2095
+ if (!this.mousedover && this.shown) this.hide()
1675
2096
  }
1676
2097
 
1677
2098
  , click: function (e) {
1678
2099
  e.stopPropagation()
1679
2100
  e.preventDefault()
1680
2101
  this.select()
2102
+ this.$element.focus()
1681
2103
  }
1682
2104
 
1683
2105
  , mouseenter: function (e) {
2106
+ this.mousedover = true
1684
2107
  this.$menu.find('.active').removeClass('active')
1685
2108
  $(e.currentTarget).addClass('active')
1686
2109
  }
1687
2110
 
2111
+ , mouseleave: function (e) {
2112
+ this.mousedover = false
2113
+ if (!this.focused && this.shown) this.hide()
2114
+ }
2115
+
1688
2116
  }
1689
2117
 
1690
2118
 
1691
2119
  /* TYPEAHEAD PLUGIN DEFINITION
1692
2120
  * =========================== */
1693
2121
 
1694
- $.fn.typeahead = function ( option ) {
2122
+ var old = $.fn.typeahead
2123
+
2124
+ $.fn.typeahead = function (option) {
1695
2125
  return this.each(function () {
1696
2126
  var $this = $(this)
1697
2127
  , data = $this.data('typeahead')
@@ -1706,21 +2136,145 @@
1706
2136
  , items: 8
1707
2137
  , menu: '<ul class="typeahead dropdown-menu"></ul>'
1708
2138
  , item: '<li><a href="#"></a></li>'
2139
+ , minLength: 1
1709
2140
  }
1710
2141
 
1711
2142
  $.fn.typeahead.Constructor = Typeahead
1712
2143
 
1713
2144
 
2145
+ /* TYPEAHEAD NO CONFLICT
2146
+ * =================== */
2147
+
2148
+ $.fn.typeahead.noConflict = function () {
2149
+ $.fn.typeahead = old
2150
+ return this
2151
+ }
2152
+
2153
+
1714
2154
  /* TYPEAHEAD DATA-API
1715
2155
  * ================== */
1716
2156
 
1717
- $(function () {
1718
- $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
2157
+ $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
2158
+ var $this = $(this)
2159
+ if ($this.data('typeahead')) return
2160
+ $this.typeahead($this.data())
2161
+ })
2162
+
2163
+ }(window.jQuery);
2164
+ /* ==========================================================
2165
+ * bootstrap-affix.js v2.3.2
2166
+ * http://getbootstrap.com/2.3.2/javascript.html#affix
2167
+ * ==========================================================
2168
+ * Copyright 2013 Twitter, Inc.
2169
+ *
2170
+ * Licensed under the Apache License, Version 2.0 (the "License");
2171
+ * you may not use this file except in compliance with the License.
2172
+ * You may obtain a copy of the License at
2173
+ *
2174
+ * http://www.apache.org/licenses/LICENSE-2.0
2175
+ *
2176
+ * Unless required by applicable law or agreed to in writing, software
2177
+ * distributed under the License is distributed on an "AS IS" BASIS,
2178
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2179
+ * See the License for the specific language governing permissions and
2180
+ * limitations under the License.
2181
+ * ========================================================== */
2182
+
2183
+
2184
+ !function ($) {
2185
+
2186
+ "use strict"; // jshint ;_;
2187
+
2188
+
2189
+ /* AFFIX CLASS DEFINITION
2190
+ * ====================== */
2191
+
2192
+ var Affix = function (element, options) {
2193
+ this.options = $.extend({}, $.fn.affix.defaults, options)
2194
+ this.$window = $(window)
2195
+ .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
2196
+ .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
2197
+ this.$element = $(element)
2198
+ this.checkPosition()
2199
+ }
2200
+
2201
+ Affix.prototype.checkPosition = function () {
2202
+ if (!this.$element.is(':visible')) return
2203
+
2204
+ var scrollHeight = $(document).height()
2205
+ , scrollTop = this.$window.scrollTop()
2206
+ , position = this.$element.offset()
2207
+ , offset = this.options.offset
2208
+ , offsetBottom = offset.bottom
2209
+ , offsetTop = offset.top
2210
+ , reset = 'affix affix-top affix-bottom'
2211
+ , affix
2212
+
2213
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
2214
+ if (typeof offsetTop == 'function') offsetTop = offset.top()
2215
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
2216
+
2217
+ affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
2218
+ false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
2219
+ 'bottom' : offsetTop != null && scrollTop <= offsetTop ?
2220
+ 'top' : false
2221
+
2222
+ if (this.affixed === affix) return
2223
+
2224
+ this.affixed = affix
2225
+ this.unpin = affix == 'bottom' ? position.top - scrollTop : null
2226
+
2227
+ this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
2228
+ }
2229
+
2230
+
2231
+ /* AFFIX PLUGIN DEFINITION
2232
+ * ======================= */
2233
+
2234
+ var old = $.fn.affix
2235
+
2236
+ $.fn.affix = function (option) {
2237
+ return this.each(function () {
1719
2238
  var $this = $(this)
1720
- if ($this.data('typeahead')) return
1721
- e.preventDefault()
1722
- $this.typeahead($this.data())
2239
+ , data = $this.data('affix')
2240
+ , options = typeof option == 'object' && option
2241
+ if (!data) $this.data('affix', (data = new Affix(this, options)))
2242
+ if (typeof option == 'string') data[option]()
2243
+ })
2244
+ }
2245
+
2246
+ $.fn.affix.Constructor = Affix
2247
+
2248
+ $.fn.affix.defaults = {
2249
+ offset: 0
2250
+ }
2251
+
2252
+
2253
+ /* AFFIX NO CONFLICT
2254
+ * ================= */
2255
+
2256
+ $.fn.affix.noConflict = function () {
2257
+ $.fn.affix = old
2258
+ return this
2259
+ }
2260
+
2261
+
2262
+ /* AFFIX DATA-API
2263
+ * ============== */
2264
+
2265
+ $(window).on('load', function () {
2266
+ $('[data-spy="affix"]').each(function () {
2267
+ var $spy = $(this)
2268
+ , data = $spy.data()
2269
+
2270
+ data.offset = data.offset || {}
2271
+
2272
+ data.offsetBottom && (data.offset.bottom = data.offsetBottom)
2273
+ data.offsetTop && (data.offset.top = data.offsetTop)
2274
+
2275
+ $spy.affix(data)
1723
2276
  })
1724
2277
  })
1725
2278
 
1726
- }( window.jQuery );
2279
+
2280
+ }(window.jQuery);