flapjack 1.6.0 → 2.0.0b1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -6
  3. data/.gitmodules +1 -1
  4. data/.rspec +1 -1
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +12 -13
  7. data/CHANGELOG.md +2 -9
  8. data/CONTRIBUTING.md +7 -2
  9. data/Gemfile +4 -13
  10. data/LICENCE +1 -0
  11. data/README.md +8 -2
  12. data/Rakefile +2 -2
  13. data/bin/flapjack +3 -12
  14. data/build.sh +4 -2
  15. data/etc/flapjack_config.toml.example +273 -0
  16. data/features/ack_after_sched_maint.feature +18 -21
  17. data/features/cli.feature +11 -71
  18. data/features/cli_flapjack-feed-events.feature +14 -15
  19. data/features/cli_flapjack-nagios-receiver.feature +12 -41
  20. data/features/cli_flapper.feature +12 -41
  21. data/features/cli_purge.feature +5 -6
  22. data/features/cli_receive-events.feature +6 -7
  23. data/features/cli_simulate-failed-check.feature +5 -6
  24. data/features/events.feature +206 -181
  25. data/features/events_check_names.feature +4 -7
  26. data/features/notification_rules.feature +144 -223
  27. data/features/notifications.feature +65 -57
  28. data/features/rollup.feature +45 -47
  29. data/features/steps/cli_steps.rb +4 -5
  30. data/features/steps/events_steps.rb +163 -373
  31. data/features/steps/notifications_steps.rb +408 -264
  32. data/features/steps/packaging-lintian_steps.rb +0 -4
  33. data/features/steps/time_travel_steps.rb +0 -26
  34. data/features/support/daemons.rb +6 -31
  35. data/features/support/env.rb +65 -74
  36. data/flapjack.gemspec +22 -24
  37. data/lib/flapjack.rb +14 -7
  38. data/lib/flapjack/cli/flapper.rb +74 -173
  39. data/lib/flapjack/cli/maintenance.rb +278 -109
  40. data/lib/flapjack/cli/migrate.rb +950 -0
  41. data/lib/flapjack/cli/purge.rb +19 -22
  42. data/lib/flapjack/cli/receiver.rb +150 -326
  43. data/lib/flapjack/cli/server.rb +8 -235
  44. data/lib/flapjack/cli/simulate.rb +42 -57
  45. data/lib/flapjack/configuration.rb +51 -37
  46. data/lib/flapjack/coordinator.rb +138 -129
  47. data/lib/flapjack/data/acknowledgement.rb +177 -0
  48. data/lib/flapjack/data/alert.rb +97 -158
  49. data/lib/flapjack/data/check.rb +611 -0
  50. data/lib/flapjack/data/condition.rb +70 -0
  51. data/lib/flapjack/data/contact.rb +226 -456
  52. data/lib/flapjack/data/event.rb +96 -184
  53. data/lib/flapjack/data/extensions/associations.rb +59 -0
  54. data/lib/flapjack/data/extensions/short_name.rb +25 -0
  55. data/lib/flapjack/data/medium.rb +428 -0
  56. data/lib/flapjack/data/metrics.rb +194 -0
  57. data/lib/flapjack/data/notification.rb +22 -281
  58. data/lib/flapjack/data/rule.rb +473 -0
  59. data/lib/flapjack/data/scheduled_maintenance.rb +244 -0
  60. data/lib/flapjack/data/state.rb +221 -0
  61. data/lib/flapjack/data/statistic.rb +112 -0
  62. data/lib/flapjack/data/tag.rb +277 -0
  63. data/lib/flapjack/data/test_notification.rb +182 -0
  64. data/lib/flapjack/data/unscheduled_maintenance.rb +159 -0
  65. data/lib/flapjack/data/validators/id_validator.rb +20 -0
  66. data/lib/flapjack/exceptions.rb +6 -0
  67. data/lib/flapjack/filters/acknowledgement.rb +23 -16
  68. data/lib/flapjack/filters/base.rb +0 -5
  69. data/lib/flapjack/filters/delays.rb +53 -43
  70. data/lib/flapjack/filters/ok.rb +23 -14
  71. data/lib/flapjack/filters/scheduled_maintenance.rb +3 -3
  72. data/lib/flapjack/filters/unscheduled_maintenance.rb +12 -3
  73. data/lib/flapjack/gateways/aws_sns.rb +65 -49
  74. data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -2
  75. data/lib/flapjack/gateways/aws_sns/alert_subject.text.erb +2 -2
  76. data/lib/flapjack/gateways/aws_sns/rollup_subject.text.erb +1 -1
  77. data/lib/flapjack/gateways/email.rb +107 -90
  78. data/lib/flapjack/gateways/email/alert.html.erb +19 -18
  79. data/lib/flapjack/gateways/email/alert.text.erb +20 -14
  80. data/lib/flapjack/gateways/email/alert_subject.text.erb +2 -1
  81. data/lib/flapjack/gateways/email/rollup.html.erb +14 -13
  82. data/lib/flapjack/gateways/email/rollup.text.erb +13 -10
  83. data/lib/flapjack/gateways/jabber.rb +679 -671
  84. data/lib/flapjack/gateways/jabber/alert.text.erb +9 -6
  85. data/lib/flapjack/gateways/jsonapi.rb +164 -350
  86. data/lib/flapjack/gateways/jsonapi/data/join_descriptor.rb +44 -0
  87. data/lib/flapjack/gateways/jsonapi/data/method_descriptor.rb +21 -0
  88. data/lib/flapjack/gateways/jsonapi/helpers/headers.rb +63 -0
  89. data/lib/flapjack/gateways/jsonapi/helpers/miscellaneous.rb +136 -0
  90. data/lib/flapjack/gateways/jsonapi/helpers/resources.rb +227 -0
  91. data/lib/flapjack/gateways/jsonapi/helpers/serialiser.rb +313 -0
  92. data/lib/flapjack/gateways/jsonapi/helpers/swagger_docs.rb +322 -0
  93. data/lib/flapjack/gateways/jsonapi/methods/association_delete.rb +115 -0
  94. data/lib/flapjack/gateways/jsonapi/methods/association_get.rb +288 -0
  95. data/lib/flapjack/gateways/jsonapi/methods/association_patch.rb +178 -0
  96. data/lib/flapjack/gateways/jsonapi/methods/association_post.rb +116 -0
  97. data/lib/flapjack/gateways/jsonapi/methods/metrics.rb +71 -0
  98. data/lib/flapjack/gateways/jsonapi/methods/resource_delete.rb +119 -0
  99. data/lib/flapjack/gateways/jsonapi/methods/resource_get.rb +186 -0
  100. data/lib/flapjack/gateways/jsonapi/methods/resource_patch.rb +239 -0
  101. data/lib/flapjack/gateways/jsonapi/methods/resource_post.rb +197 -0
  102. data/lib/flapjack/gateways/jsonapi/middleware/array_param_fixer.rb +27 -0
  103. data/lib/flapjack/gateways/jsonapi/{rack → middleware}/json_params_parser.rb +7 -6
  104. data/lib/flapjack/gateways/jsonapi/middleware/request_timestamp.rb +18 -0
  105. data/lib/flapjack/gateways/oobetet.rb +222 -170
  106. data/lib/flapjack/gateways/pager_duty.rb +388 -0
  107. data/lib/flapjack/gateways/pager_duty/alert.text.erb +13 -0
  108. data/lib/flapjack/gateways/slack.rb +56 -48
  109. data/lib/flapjack/gateways/slack/alert.text.erb +1 -1
  110. data/lib/flapjack/gateways/slack/rollup.text.erb +1 -1
  111. data/lib/flapjack/gateways/sms_aspsms.rb +155 -0
  112. data/lib/flapjack/gateways/sms_aspsms/alert.text.erb +7 -0
  113. data/lib/flapjack/gateways/sms_aspsms/rollup.text.erb +2 -0
  114. data/lib/flapjack/gateways/sms_messagenet.rb +77 -57
  115. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +3 -2
  116. data/lib/flapjack/gateways/sms_nexmo.rb +53 -51
  117. data/lib/flapjack/gateways/sms_nexmo/alert.text.erb +2 -2
  118. data/lib/flapjack/gateways/sms_nexmo/rollup.text.erb +1 -1
  119. data/lib/flapjack/gateways/sms_twilio.rb +79 -62
  120. data/lib/flapjack/gateways/sms_twilio/alert.text.erb +3 -2
  121. data/lib/flapjack/gateways/web.rb +437 -345
  122. data/lib/flapjack/gateways/web/middleware/request_timestamp.rb +18 -0
  123. data/lib/flapjack/gateways/web/public/css/bootstrap.css +3793 -4340
  124. data/lib/flapjack/gateways/web/public/css/bootstrap.css.map +1 -0
  125. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
  126. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +273 -214
  127. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  128. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
  129. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  130. data/lib/flapjack/gateways/web/public/js/bootstrap.js +1637 -1607
  131. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -2
  132. data/lib/flapjack/gateways/web/views/_pagination.html.erb +19 -0
  133. data/lib/flapjack/gateways/web/views/check.html.erb +159 -121
  134. data/lib/flapjack/gateways/web/views/checks.html.erb +82 -41
  135. data/lib/flapjack/gateways/web/views/contact.html.erb +59 -71
  136. data/lib/flapjack/gateways/web/views/contacts.html.erb +32 -8
  137. data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
  138. data/lib/flapjack/gateways/web/views/{layout.erb → layout.html.erb} +7 -23
  139. data/lib/flapjack/gateways/web/views/self_stats.html.erb +32 -33
  140. data/lib/flapjack/gateways/web/views/tag.html.erb +32 -0
  141. data/lib/flapjack/gateways/web/views/tags.html.erb +51 -0
  142. data/lib/flapjack/logger.rb +34 -3
  143. data/lib/flapjack/notifier.rb +180 -112
  144. data/lib/flapjack/patches.rb +8 -63
  145. data/lib/flapjack/pikelet.rb +185 -143
  146. data/lib/flapjack/processor.rb +323 -191
  147. data/lib/flapjack/record_queue.rb +33 -0
  148. data/lib/flapjack/redis_proxy.rb +66 -0
  149. data/lib/flapjack/utility.rb +21 -15
  150. data/lib/flapjack/version.rb +2 -1
  151. data/libexec/httpbroker.go +218 -14
  152. data/libexec/oneoff.go +13 -10
  153. data/spec/lib/flapjack/configuration_spec.rb +286 -0
  154. data/spec/lib/flapjack/coordinator_spec.rb +103 -157
  155. data/spec/lib/flapjack/data/check_spec.rb +175 -0
  156. data/spec/lib/flapjack/data/contact_spec.rb +26 -349
  157. data/spec/lib/flapjack/data/event_spec.rb +76 -291
  158. data/spec/lib/flapjack/data/medium_spec.rb +19 -0
  159. data/spec/lib/flapjack/data/rule_spec.rb +43 -0
  160. data/spec/lib/flapjack/data/scheduled_maintenance_spec.rb +976 -0
  161. data/spec/lib/flapjack/data/unscheduled_maintenance_spec.rb +34 -0
  162. data/spec/lib/flapjack/gateways/aws_sns_spec.rb +111 -60
  163. data/spec/lib/flapjack/gateways/email_spec.rb +194 -161
  164. data/spec/lib/flapjack/gateways/jabber_spec.rb +961 -162
  165. data/spec/lib/flapjack/gateways/jsonapi/methods/check_links_spec.rb +155 -0
  166. data/spec/lib/flapjack/gateways/jsonapi/methods/checks_spec.rb +426 -0
  167. data/spec/lib/flapjack/gateways/jsonapi/methods/contact_links_spec.rb +217 -0
  168. data/spec/lib/flapjack/gateways/jsonapi/methods/contacts_spec.rb +425 -0
  169. data/spec/lib/flapjack/gateways/jsonapi/methods/events_spec.rb +271 -0
  170. data/spec/lib/flapjack/gateways/jsonapi/methods/media_spec.rb +257 -0
  171. data/spec/lib/flapjack/gateways/jsonapi/methods/medium_links_spec.rb +163 -0
  172. data/spec/lib/flapjack/gateways/jsonapi/methods/metrics_spec.rb +8 -0
  173. data/spec/lib/flapjack/gateways/jsonapi/methods/rule_links_spec.rb +212 -0
  174. data/spec/lib/flapjack/gateways/jsonapi/methods/rules_spec.rb +289 -0
  175. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenance_links_spec.rb +49 -0
  176. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenances_spec.rb +242 -0
  177. data/spec/lib/flapjack/gateways/jsonapi/methods/tag_links_spec.rb +274 -0
  178. data/spec/lib/flapjack/gateways/jsonapi/methods/tags_spec.rb +302 -0
  179. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenance_links_spec.rb +49 -0
  180. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenances_spec.rb +339 -0
  181. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +1 -1
  182. data/spec/lib/flapjack/gateways/oobetet_spec.rb +151 -79
  183. data/spec/lib/flapjack/gateways/pager_duty_spec.rb +353 -0
  184. data/spec/lib/flapjack/gateways/slack_spec.rb +53 -53
  185. data/spec/lib/flapjack/gateways/sms_aspsms_spec.rb +106 -0
  186. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +111 -54
  187. data/spec/lib/flapjack/gateways/sms_nexmo_spec.rb +50 -51
  188. data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +108 -48
  189. data/spec/lib/flapjack/gateways/web_spec.rb +144 -216
  190. data/spec/lib/flapjack/notifier_spec.rb +132 -1
  191. data/spec/lib/flapjack/pikelet_spec.rb +111 -50
  192. data/spec/lib/flapjack/processor_spec.rb +210 -40
  193. data/spec/lib/flapjack/redis_proxy_spec.rb +45 -0
  194. data/spec/lib/flapjack/utility_spec.rb +11 -15
  195. data/spec/service_consumers/fixture_data.rb +547 -0
  196. data/spec/service_consumers/pact_helper.rb +21 -32
  197. data/spec/service_consumers/pacts/flapjack-diner_v2.0.json +4652 -0
  198. data/spec/service_consumers/provider_states_for_flapjack-diner.rb +279 -322
  199. data/spec/service_consumers/provider_support.rb +8 -0
  200. data/spec/spec_helper.rb +34 -44
  201. data/spec/support/erb_view_helper.rb +1 -1
  202. data/spec/support/factories.rb +58 -0
  203. data/spec/support/jsonapi_helper.rb +15 -26
  204. data/spec/support/mock_logger.rb +43 -0
  205. data/spec/support/xmpp_comparable.rb +24 -0
  206. data/src/flapjack/transport_test.go +30 -1
  207. data/tasks/dump_keys.rake +82 -0
  208. data/tasks/events.rake +7 -7
  209. data/tasks/support/flapjack_config_benchmark.toml +28 -0
  210. data/tasks/support/flapjack_config_benchmark.yaml +0 -2
  211. metadata +175 -222
  212. data/Guardfile +0 -14
  213. data/etc/flapjack_config.yaml.example +0 -477
  214. data/features/cli_flapjack-populator.feature +0 -90
  215. data/features/support/silent_system.rb +0 -4
  216. data/lib/flapjack/cli/import.rb +0 -108
  217. data/lib/flapjack/data/entity.rb +0 -652
  218. data/lib/flapjack/data/entity_check.rb +0 -1044
  219. data/lib/flapjack/data/message.rb +0 -56
  220. data/lib/flapjack/data/migration.rb +0 -234
  221. data/lib/flapjack/data/notification_rule.rb +0 -425
  222. data/lib/flapjack/data/semaphore.rb +0 -44
  223. data/lib/flapjack/data/tagged.rb +0 -48
  224. data/lib/flapjack/gateways/jsonapi/check_methods.rb +0 -206
  225. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +0 -221
  226. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +0 -186
  227. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +0 -223
  228. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +0 -185
  229. data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +0 -132
  230. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +0 -141
  231. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +0 -139
  232. data/lib/flapjack/gateways/jsonapi/report_methods.rb +0 -146
  233. data/lib/flapjack/gateways/pagerduty.rb +0 -318
  234. data/lib/flapjack/gateways/pagerduty/alert.text.erb +0 -10
  235. data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +0 -87
  236. data/lib/flapjack/gateways/web/public/css/select2.css +0 -615
  237. data/lib/flapjack/gateways/web/public/css/tablesort.css +0 -67
  238. data/lib/flapjack/gateways/web/public/img/select2-spinner.gif +0 -0
  239. data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
  240. data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
  241. data/lib/flapjack/gateways/web/public/js/backbone.js +0 -1581
  242. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +0 -322
  243. data/lib/flapjack/gateways/web/public/js/flapjack.js +0 -82
  244. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.js +0 -1640
  245. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.widgets.js +0 -1390
  246. data/lib/flapjack/gateways/web/public/js/modules/contact.js +0 -520
  247. data/lib/flapjack/gateways/web/public/js/modules/entity.js +0 -28
  248. data/lib/flapjack/gateways/web/public/js/modules/medium.js +0 -40
  249. data/lib/flapjack/gateways/web/public/js/select2.js +0 -3397
  250. data/lib/flapjack/gateways/web/public/js/tablesort.js +0 -44
  251. data/lib/flapjack/gateways/web/public/js/underscore.js +0 -1276
  252. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +0 -173
  253. data/lib/flapjack/gateways/web/views/entities.html.erb +0 -30
  254. data/lib/flapjack/gateways/web/views/entity.html.erb +0 -51
  255. data/lib/flapjack/rack_logger.rb +0 -47
  256. data/lib/flapjack/redis_pool.rb +0 -42
  257. data/spec/lib/flapjack/data/entity_check_spec.rb +0 -1418
  258. data/spec/lib/flapjack/data/entity_spec.rb +0 -872
  259. data/spec/lib/flapjack/data/message_spec.rb +0 -30
  260. data/spec/lib/flapjack/data/migration_spec.rb +0 -104
  261. data/spec/lib/flapjack/data/notification_rule_spec.rb +0 -232
  262. data/spec/lib/flapjack/data/notification_spec.rb +0 -53
  263. data/spec/lib/flapjack/data/semaphore_spec.rb +0 -24
  264. data/spec/lib/flapjack/filters/acknowledgement_spec.rb +0 -6
  265. data/spec/lib/flapjack/filters/delays_spec.rb +0 -6
  266. data/spec/lib/flapjack/filters/ok_spec.rb +0 -6
  267. data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +0 -6
  268. data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +0 -6
  269. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +0 -315
  270. data/spec/lib/flapjack/gateways/jsonapi/check_presenter_spec.rb +0 -223
  271. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +0 -131
  272. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +0 -389
  273. data/spec/lib/flapjack/gateways/jsonapi/medium_methods_spec.rb +0 -231
  274. data/spec/lib/flapjack/gateways/jsonapi/notification_rule_methods_spec.rb +0 -169
  275. data/spec/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods_spec.rb +0 -114
  276. data/spec/lib/flapjack/gateways/jsonapi/report_methods_spec.rb +0 -590
  277. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +0 -249
  278. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +0 -21
  279. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +0 -24
  280. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +0 -16
  281. data/spec/lib/flapjack/redis_pool_spec.rb +0 -29
  282. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +0 -4702
  283. data/tasks/entities.rake +0 -151
  284. data/tasks/profile.rake +0 -282
  285. data/tmp/acknowledge.rb +0 -13
  286. data/tmp/create_config_yaml.rb +0 -16
  287. data/tmp/create_event_ok.rb +0 -30
  288. data/tmp/create_event_unknown.rb +0 -30
  289. data/tmp/create_events_failure.rb +0 -34
  290. data/tmp/create_events_ok.rb +0 -32
  291. data/tmp/create_events_ok_fail_ack_ok.rb +0 -53
  292. data/tmp/create_events_ok_failure.rb +0 -41
  293. data/tmp/create_events_ok_failure_ack.rb +0 -53
  294. data/tmp/dummy_contacts.json +0 -43
  295. data/tmp/dummy_entities.json +0 -37
  296. data/tmp/generate_nagios_test_hosts.rb +0 -16
  297. data/tmp/notification_rules.rb +0 -73
  298. data/tmp/parse_config_yaml.rb +0 -7
  299. data/tmp/redis_find_spurious_unknown_states.rb +0 -52
  300. data/tmp/test_json_post.rb +0 -19
  301. data/tmp/test_notification_rules_api.rb +0 -171
@@ -1,148 +1,162 @@
1
- /* ===================================================
2
- * bootstrap-transition.js v2.3.1
3
- * http://twitter.github.com/bootstrap/javascript.html#transitions
4
- * ===================================================
5
- * Copyright 2012 Twitter, Inc.
6
- *
7
- * Licensed under the Apache License, Version 2.0 (the "License");
8
- * you may not use this file except in compliance with the License.
9
- * You may obtain a copy of the License at
10
- *
11
- * http://www.apache.org/licenses/LICENSE-2.0
12
- *
13
- * Unless required by applicable law or agreed to in writing, software
14
- * distributed under the License is distributed on an "AS IS" BASIS,
15
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- * See the License for the specific language governing permissions and
17
- * limitations under the License.
18
- * ========================================================== */
19
-
20
-
21
- !function ($) {
22
-
23
- "use strict"; // jshint ;_;
24
-
25
-
26
- /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
27
- * ======================================================= */
1
+ /*!
2
+ * Bootstrap v3.3.2 (http://getbootstrap.com)
3
+ * Copyright 2011-2015 Twitter, Inc.
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5
+ */
6
+
7
+ if (typeof jQuery === 'undefined') {
8
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
9
+ }
10
+
11
+ +function ($) {
12
+ 'use strict';
13
+ var version = $.fn.jquery.split(' ')[0].split('.')
14
+ if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
15
+ throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
16
+ }
17
+ }(jQuery);
28
18
 
29
- $(function () {
19
+ /* ========================================================================
20
+ * Bootstrap: transition.js v3.3.2
21
+ * http://getbootstrap.com/javascript/#transitions
22
+ * ========================================================================
23
+ * Copyright 2011-2015 Twitter, Inc.
24
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
25
+ * ======================================================================== */
30
26
 
31
- $.support.transition = (function () {
32
27
 
33
- var transitionEnd = (function () {
28
+ +function ($) {
29
+ 'use strict';
34
30
 
35
- var el = document.createElement('bootstrap')
36
- , transEndEventNames = {
37
- 'WebkitTransition' : 'webkitTransitionEnd'
38
- , 'MozTransition' : 'transitionend'
39
- , 'OTransition' : 'oTransitionEnd otransitionend'
40
- , 'transition' : 'transitionend'
41
- }
42
- , name
31
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
32
+ // ============================================================
43
33
 
44
- for (name in transEndEventNames){
45
- if (el.style[name] !== undefined) {
46
- return transEndEventNames[name]
47
- }
48
- }
34
+ function transitionEnd() {
35
+ var el = document.createElement('bootstrap')
49
36
 
50
- }())
37
+ var transEndEventNames = {
38
+ WebkitTransition : 'webkitTransitionEnd',
39
+ MozTransition : 'transitionend',
40
+ OTransition : 'oTransitionEnd otransitionend',
41
+ transition : 'transitionend'
42
+ }
51
43
 
52
- return transitionEnd && {
53
- end: transitionEnd
44
+ for (var name in transEndEventNames) {
45
+ if (el.style[name] !== undefined) {
46
+ return { end: transEndEventNames[name] }
54
47
  }
48
+ }
55
49
 
56
- })()
50
+ return false // explicit for ie8 ( ._.)
51
+ }
57
52
 
58
- })
53
+ // http://blog.alexmaccaw.com/css-transitions
54
+ $.fn.emulateTransitionEnd = function (duration) {
55
+ var called = false
56
+ var $el = this
57
+ $(this).one('bsTransitionEnd', function () { called = true })
58
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
59
+ setTimeout(callback, duration)
60
+ return this
61
+ }
62
+
63
+ $(function () {
64
+ $.support.transition = transitionEnd()
65
+
66
+ if (!$.support.transition) return
59
67
 
60
- }(window.jQuery);/* ==========================================================
61
- * bootstrap-alert.js v2.3.1
62
- * http://twitter.github.com/bootstrap/javascript.html#alerts
63
- * ==========================================================
64
- * Copyright 2012 Twitter, Inc.
65
- *
66
- * Licensed under the Apache License, Version 2.0 (the "License");
67
- * you may not use this file except in compliance with the License.
68
- * You may obtain a copy of the License at
69
- *
70
- * http://www.apache.org/licenses/LICENSE-2.0
71
- *
72
- * Unless required by applicable law or agreed to in writing, software
73
- * distributed under the License is distributed on an "AS IS" BASIS,
74
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
75
- * See the License for the specific language governing permissions and
76
- * limitations under the License.
77
- * ========================================================== */
68
+ $.event.special.bsTransitionEnd = {
69
+ bindType: $.support.transition.end,
70
+ delegateType: $.support.transition.end,
71
+ handle: function (e) {
72
+ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
73
+ }
74
+ }
75
+ })
78
76
 
77
+ }(jQuery);
79
78
 
80
- !function ($) {
79
+ /* ========================================================================
80
+ * Bootstrap: alert.js v3.3.2
81
+ * http://getbootstrap.com/javascript/#alerts
82
+ * ========================================================================
83
+ * Copyright 2011-2015 Twitter, Inc.
84
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
85
+ * ======================================================================== */
81
86
 
82
- "use strict"; // jshint ;_;
83
87
 
88
+ +function ($) {
89
+ 'use strict';
84
90
 
85
- /* ALERT CLASS DEFINITION
86
- * ====================== */
91
+ // ALERT CLASS DEFINITION
92
+ // ======================
87
93
 
88
94
  var dismiss = '[data-dismiss="alert"]'
89
- , Alert = function (el) {
90
- $(el).on('click', dismiss, this.close)
91
- }
95
+ var Alert = function (el) {
96
+ $(el).on('click', dismiss, this.close)
97
+ }
98
+
99
+ Alert.VERSION = '3.3.2'
100
+
101
+ Alert.TRANSITION_DURATION = 150
92
102
 
93
103
  Alert.prototype.close = function (e) {
94
- var $this = $(this)
95
- , selector = $this.attr('data-target')
96
- , $parent
104
+ var $this = $(this)
105
+ var selector = $this.attr('data-target')
97
106
 
98
107
  if (!selector) {
99
108
  selector = $this.attr('href')
100
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
109
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
101
110
  }
102
111
 
103
- $parent = $(selector)
112
+ var $parent = $(selector)
104
113
 
105
- e && e.preventDefault()
114
+ if (e) e.preventDefault()
106
115
 
107
- $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
116
+ if (!$parent.length) {
117
+ $parent = $this.closest('.alert')
118
+ }
108
119
 
109
- $parent.trigger(e = $.Event('close'))
120
+ $parent.trigger(e = $.Event('close.bs.alert'))
110
121
 
111
122
  if (e.isDefaultPrevented()) return
112
123
 
113
124
  $parent.removeClass('in')
114
125
 
115
126
  function removeElement() {
116
- $parent
117
- .trigger('closed')
118
- .remove()
127
+ // detach from parent, fire event then clean up data
128
+ $parent.detach().trigger('closed.bs.alert').remove()
119
129
  }
120
130
 
121
131
  $.support.transition && $parent.hasClass('fade') ?
122
- $parent.on($.support.transition.end, removeElement) :
132
+ $parent
133
+ .one('bsTransitionEnd', removeElement)
134
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
123
135
  removeElement()
124
136
  }
125
137
 
126
138
 
127
- /* ALERT PLUGIN DEFINITION
128
- * ======================= */
139
+ // ALERT PLUGIN DEFINITION
140
+ // =======================
129
141
 
130
- var old = $.fn.alert
131
-
132
- $.fn.alert = function (option) {
142
+ function Plugin(option) {
133
143
  return this.each(function () {
134
144
  var $this = $(this)
135
- , data = $this.data('alert')
136
- if (!data) $this.data('alert', (data = new Alert(this)))
145
+ var data = $this.data('bs.alert')
146
+
147
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
137
148
  if (typeof option == 'string') data[option].call($this)
138
149
  })
139
150
  }
140
151
 
152
+ var old = $.fn.alert
153
+
154
+ $.fn.alert = Plugin
141
155
  $.fn.alert.Constructor = Alert
142
156
 
143
157
 
144
- /* ALERT NO CONFLICT
145
- * ================= */
158
+ // ALERT NO CONFLICT
159
+ // =================
146
160
 
147
161
  $.fn.alert.noConflict = function () {
148
162
  $.fn.alert = old
@@ -150,99 +164,107 @@
150
164
  }
151
165
 
152
166
 
153
- /* ALERT DATA-API
154
- * ============== */
155
-
156
- $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
167
+ // ALERT DATA-API
168
+ // ==============
157
169
 
158
- }(window.jQuery);/* ============================================================
159
- * bootstrap-button.js v2.3.1
160
- * http://twitter.github.com/bootstrap/javascript.html#buttons
161
- * ============================================================
162
- * Copyright 2012 Twitter, Inc.
163
- *
164
- * Licensed under the Apache License, Version 2.0 (the "License");
165
- * you may not use this file except in compliance with the License.
166
- * You may obtain a copy of the License at
167
- *
168
- * http://www.apache.org/licenses/LICENSE-2.0
169
- *
170
- * Unless required by applicable law or agreed to in writing, software
171
- * distributed under the License is distributed on an "AS IS" BASIS,
172
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
173
- * See the License for the specific language governing permissions and
174
- * limitations under the License.
175
- * ============================================================ */
170
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
176
171
 
172
+ }(jQuery);
177
173
 
178
- !function ($) {
174
+ /* ========================================================================
175
+ * Bootstrap: button.js v3.3.2
176
+ * http://getbootstrap.com/javascript/#buttons
177
+ * ========================================================================
178
+ * Copyright 2011-2015 Twitter, Inc.
179
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
180
+ * ======================================================================== */
179
181
 
180
- "use strict"; // jshint ;_;
181
182
 
183
+ +function ($) {
184
+ 'use strict';
182
185
 
183
- /* BUTTON PUBLIC CLASS DEFINITION
184
- * ============================== */
186
+ // BUTTON PUBLIC CLASS DEFINITION
187
+ // ==============================
185
188
 
186
189
  var Button = function (element, options) {
187
- this.$element = $(element)
188
- this.options = $.extend({}, $.fn.button.defaults, options)
190
+ this.$element = $(element)
191
+ this.options = $.extend({}, Button.DEFAULTS, options)
192
+ this.isLoading = false
193
+ }
194
+
195
+ Button.VERSION = '3.3.2'
196
+
197
+ Button.DEFAULTS = {
198
+ loadingText: 'loading...'
189
199
  }
190
200
 
191
201
  Button.prototype.setState = function (state) {
192
- var d = 'disabled'
193
- , $el = this.$element
194
- , data = $el.data()
195
- , val = $el.is('input') ? 'val' : 'html'
202
+ var d = 'disabled'
203
+ var $el = this.$element
204
+ var val = $el.is('input') ? 'val' : 'html'
205
+ var data = $el.data()
196
206
 
197
207
  state = state + 'Text'
198
- data.resetText || $el.data('resetText', $el[val]())
199
208
 
200
- $el[val](data[state] || this.options[state])
209
+ if (data.resetText == null) $el.data('resetText', $el[val]())
201
210
 
202
211
  // push to event loop to allow forms to submit
203
- setTimeout(function () {
204
- state == 'loadingText' ?
205
- $el.addClass(d).attr(d, d) :
212
+ setTimeout($.proxy(function () {
213
+ $el[val](data[state] == null ? this.options[state] : data[state])
214
+
215
+ if (state == 'loadingText') {
216
+ this.isLoading = true
217
+ $el.addClass(d).attr(d, d)
218
+ } else if (this.isLoading) {
219
+ this.isLoading = false
206
220
  $el.removeClass(d).removeAttr(d)
207
- }, 0)
221
+ }
222
+ }, this), 0)
208
223
  }
209
224
 
210
225
  Button.prototype.toggle = function () {
211
- var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
212
-
213
- $parent && $parent
214
- .find('.active')
215
- .removeClass('active')
226
+ var changed = true
227
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
228
+
229
+ if ($parent.length) {
230
+ var $input = this.$element.find('input')
231
+ if ($input.prop('type') == 'radio') {
232
+ if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
233
+ else $parent.find('.active').removeClass('active')
234
+ }
235
+ if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
236
+ } else {
237
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
238
+ }
216
239
 
217
- this.$element.toggleClass('active')
240
+ if (changed) this.$element.toggleClass('active')
218
241
  }
219
242
 
220
243
 
221
- /* BUTTON PLUGIN DEFINITION
222
- * ======================== */
223
-
224
- var old = $.fn.button
244
+ // BUTTON PLUGIN DEFINITION
245
+ // ========================
225
246
 
226
- $.fn.button = function (option) {
247
+ function Plugin(option) {
227
248
  return this.each(function () {
228
- var $this = $(this)
229
- , data = $this.data('button')
230
- , options = typeof option == 'object' && option
231
- if (!data) $this.data('button', (data = new Button(this, options)))
249
+ var $this = $(this)
250
+ var data = $this.data('bs.button')
251
+ var options = typeof option == 'object' && option
252
+
253
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
254
+
232
255
  if (option == 'toggle') data.toggle()
233
256
  else if (option) data.setState(option)
234
257
  })
235
258
  }
236
259
 
237
- $.fn.button.defaults = {
238
- loadingText: 'loading...'
239
- }
260
+ var old = $.fn.button
240
261
 
262
+ $.fn.button = Plugin
241
263
  $.fn.button.Constructor = Button
242
264
 
243
265
 
244
- /* BUTTON NO CONFLICT
245
- * ================== */
266
+ // BUTTON NO CONFLICT
267
+ // ==================
246
268
 
247
269
  $.fn.button.noConflict = function () {
248
270
  $.fn.button = old
@@ -250,367 +272,448 @@
250
272
  }
251
273
 
252
274
 
253
- /* BUTTON DATA-API
254
- * =============== */
255
-
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')
260
- })
275
+ // BUTTON DATA-API
276
+ // ===============
261
277
 
262
- }(window.jQuery);/* ==========================================================
263
- * bootstrap-carousel.js v2.3.1
264
- * http://twitter.github.com/bootstrap/javascript.html#carousel
265
- * ==========================================================
266
- * Copyright 2012 Twitter, Inc.
267
- *
268
- * Licensed under the Apache License, Version 2.0 (the "License");
269
- * you may not use this file except in compliance with the License.
270
- * You may obtain a copy of the License at
271
- *
272
- * http://www.apache.org/licenses/LICENSE-2.0
273
- *
274
- * Unless required by applicable law or agreed to in writing, software
275
- * distributed under the License is distributed on an "AS IS" BASIS,
276
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
277
- * See the License for the specific language governing permissions and
278
- * limitations under the License.
279
- * ========================================================== */
278
+ $(document)
279
+ .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
280
+ var $btn = $(e.target)
281
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
282
+ Plugin.call($btn, 'toggle')
283
+ e.preventDefault()
284
+ })
285
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
286
+ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
287
+ })
280
288
 
289
+ }(jQuery);
281
290
 
282
- !function ($) {
291
+ /* ========================================================================
292
+ * Bootstrap: carousel.js v3.3.2
293
+ * http://getbootstrap.com/javascript/#carousel
294
+ * ========================================================================
295
+ * Copyright 2011-2015 Twitter, Inc.
296
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
297
+ * ======================================================================== */
283
298
 
284
- "use strict"; // jshint ;_;
285
299
 
300
+ +function ($) {
301
+ 'use strict';
286
302
 
287
- /* CAROUSEL CLASS DEFINITION
288
- * ========================= */
303
+ // CAROUSEL CLASS DEFINITION
304
+ // =========================
289
305
 
290
306
  var Carousel = function (element, options) {
291
- this.$element = $(element)
307
+ this.$element = $(element)
292
308
  this.$indicators = this.$element.find('.carousel-indicators')
293
- this.options = options
294
- this.options.pause == 'hover' && this.$element
295
- .on('mouseenter', $.proxy(this.pause, this))
296
- .on('mouseleave', $.proxy(this.cycle, this))
309
+ this.options = options
310
+ this.paused =
311
+ this.sliding =
312
+ this.interval =
313
+ this.$active =
314
+ this.$items = null
315
+
316
+ this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
317
+
318
+ this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
319
+ .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
320
+ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
297
321
  }
298
322
 
299
- Carousel.prototype = {
323
+ Carousel.VERSION = '3.3.2'
300
324
 
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))
307
- return this
308
- }
325
+ Carousel.TRANSITION_DURATION = 600
326
+
327
+ Carousel.DEFAULTS = {
328
+ interval: 5000,
329
+ pause: 'hover',
330
+ wrap: true,
331
+ keyboard: true
332
+ }
309
333
 
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)
334
+ Carousel.prototype.keydown = function (e) {
335
+ if (/input|textarea/i.test(e.target.tagName)) return
336
+ switch (e.which) {
337
+ case 37: this.prev(); break
338
+ case 39: this.next(); break
339
+ default: return
314
340
  }
315
341
 
316
- , to: function (pos) {
317
- var activeIndex = this.getActiveIndex()
318
- , that = this
342
+ e.preventDefault()
343
+ }
319
344
 
320
- if (pos > (this.$items.length - 1) || pos < 0) return
345
+ Carousel.prototype.cycle = function (e) {
346
+ e || (this.paused = false)
321
347
 
322
- if (this.sliding) {
323
- return this.$element.one('slid', function () {
324
- that.to(pos)
325
- })
326
- }
348
+ this.interval && clearInterval(this.interval)
327
349
 
328
- if (activeIndex == pos) {
329
- return this.pause().cycle()
330
- }
350
+ this.options.interval
351
+ && !this.paused
352
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
331
353
 
332
- return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
333
- }
354
+ return this
355
+ }
334
356
 
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
- }
341
- clearInterval(this.interval)
342
- this.interval = null
343
- return this
344
- }
357
+ Carousel.prototype.getItemIndex = function (item) {
358
+ this.$items = item.parent().children('.item')
359
+ return this.$items.index(item || this.$active)
360
+ }
345
361
 
346
- , next: function () {
347
- if (this.sliding) return
348
- return this.slide('next')
349
- }
362
+ Carousel.prototype.getItemForDirection = function (direction, active) {
363
+ var activeIndex = this.getItemIndex(active)
364
+ var willWrap = (direction == 'prev' && activeIndex === 0)
365
+ || (direction == 'next' && activeIndex == (this.$items.length - 1))
366
+ if (willWrap && !this.options.wrap) return active
367
+ var delta = direction == 'prev' ? -1 : 1
368
+ var itemIndex = (activeIndex + delta) % this.$items.length
369
+ return this.$items.eq(itemIndex)
370
+ }
371
+
372
+ Carousel.prototype.to = function (pos) {
373
+ var that = this
374
+ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
375
+
376
+ if (pos > (this.$items.length - 1) || pos < 0) return
377
+
378
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
379
+ if (activeIndex == pos) return this.pause().cycle()
350
380
 
351
- , prev: function () {
352
- if (this.sliding) return
353
- return this.slide('prev')
381
+ return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
382
+ }
383
+
384
+ Carousel.prototype.pause = function (e) {
385
+ e || (this.paused = true)
386
+
387
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
388
+ this.$element.trigger($.support.transition.end)
389
+ this.cycle(true)
354
390
  }
355
391
 
356
- , slide: function (type, next) {
357
- var $active = this.$element.find('.item.active')
358
- , $next = next || $active[type]()
359
- , isCycling = this.interval
360
- , direction = type == 'next' ? 'left' : 'right'
361
- , fallback = type == 'next' ? 'first' : 'last'
362
- , that = this
363
- , e
392
+ this.interval = clearInterval(this.interval)
364
393
 
365
- this.sliding = true
394
+ return this
395
+ }
366
396
 
367
- isCycling && this.pause()
397
+ Carousel.prototype.next = function () {
398
+ if (this.sliding) return
399
+ return this.slide('next')
400
+ }
368
401
 
369
- $next = $next.length ? $next : this.$element.find('.item')[fallback]()
402
+ Carousel.prototype.prev = function () {
403
+ if (this.sliding) return
404
+ return this.slide('prev')
405
+ }
370
406
 
371
- e = $.Event('slide', {
372
- relatedTarget: $next[0]
373
- , direction: direction
374
- })
407
+ Carousel.prototype.slide = function (type, next) {
408
+ var $active = this.$element.find('.item.active')
409
+ var $next = next || this.getItemForDirection(type, $active)
410
+ var isCycling = this.interval
411
+ var direction = type == 'next' ? 'left' : 'right'
412
+ var that = this
375
413
 
376
- if ($next.hasClass('active')) return
414
+ if ($next.hasClass('active')) return (this.sliding = false)
377
415
 
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
- }
416
+ var relatedTarget = $next[0]
417
+ var slideEvent = $.Event('slide.bs.carousel', {
418
+ relatedTarget: relatedTarget,
419
+ direction: direction
420
+ })
421
+ this.$element.trigger(slideEvent)
422
+ if (slideEvent.isDefaultPrevented()) return
423
+
424
+ this.sliding = true
385
425
 
386
- if ($.support.transition && this.$element.hasClass('slide')) {
387
- this.$element.trigger(e)
388
- if (e.isDefaultPrevented()) return
389
- $next.addClass(type)
390
- $next[0].offsetWidth // force reflow
391
- $active.addClass(direction)
392
- $next.addClass(direction)
393
- this.$element.one($.support.transition.end, function () {
426
+ isCycling && this.pause()
427
+
428
+ if (this.$indicators.length) {
429
+ this.$indicators.find('.active').removeClass('active')
430
+ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
431
+ $nextIndicator && $nextIndicator.addClass('active')
432
+ }
433
+
434
+ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
435
+ if ($.support.transition && this.$element.hasClass('slide')) {
436
+ $next.addClass(type)
437
+ $next[0].offsetWidth // force reflow
438
+ $active.addClass(direction)
439
+ $next.addClass(direction)
440
+ $active
441
+ .one('bsTransitionEnd', function () {
394
442
  $next.removeClass([type, direction].join(' ')).addClass('active')
395
443
  $active.removeClass(['active', direction].join(' '))
396
444
  that.sliding = false
397
- setTimeout(function () { that.$element.trigger('slid') }, 0)
445
+ setTimeout(function () {
446
+ that.$element.trigger(slidEvent)
447
+ }, 0)
398
448
  })
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')
406
- }
407
-
408
- isCycling && this.cycle()
409
-
410
- return this
449
+ .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
450
+ } else {
451
+ $active.removeClass('active')
452
+ $next.addClass('active')
453
+ this.sliding = false
454
+ this.$element.trigger(slidEvent)
411
455
  }
412
456
 
413
- }
457
+ isCycling && this.cycle()
414
458
 
459
+ return this
460
+ }
415
461
 
416
- /* CAROUSEL PLUGIN DEFINITION
417
- * ========================== */
418
462
 
419
- var old = $.fn.carousel
463
+ // CAROUSEL PLUGIN DEFINITION
464
+ // ==========================
420
465
 
421
- $.fn.carousel = function (option) {
466
+ function Plugin(option) {
422
467
  return this.each(function () {
423
- var $this = $(this)
424
- , data = $this.data('carousel')
425
- , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
426
- , action = typeof option == 'string' ? option : options.slide
427
- if (!data) $this.data('carousel', (data = new Carousel(this, options)))
468
+ var $this = $(this)
469
+ var data = $this.data('bs.carousel')
470
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
471
+ var action = typeof option == 'string' ? option : options.slide
472
+
473
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
428
474
  if (typeof option == 'number') data.to(option)
429
475
  else if (action) data[action]()
430
476
  else if (options.interval) data.pause().cycle()
431
477
  })
432
478
  }
433
479
 
434
- $.fn.carousel.defaults = {
435
- interval: 5000
436
- , pause: 'hover'
437
- }
480
+ var old = $.fn.carousel
438
481
 
482
+ $.fn.carousel = Plugin
439
483
  $.fn.carousel.Constructor = Carousel
440
484
 
441
485
 
442
- /* CAROUSEL NO CONFLICT
443
- * ==================== */
486
+ // CAROUSEL NO CONFLICT
487
+ // ====================
444
488
 
445
489
  $.fn.carousel.noConflict = function () {
446
490
  $.fn.carousel = old
447
491
  return this
448
492
  }
449
493
 
450
- /* CAROUSEL DATA-API
451
- * ================= */
452
494
 
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
495
+ // CAROUSEL DATA-API
496
+ // =================
497
+
498
+ var clickHandler = function (e) {
499
+ var href
500
+ var $this = $(this)
501
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
502
+ if (!$target.hasClass('carousel')) return
503
+ var options = $.extend({}, $target.data(), $this.data())
504
+ var slideIndex = $this.attr('data-slide-to')
505
+ if (slideIndex) options.interval = false
458
506
 
459
- $target.carousel(options)
507
+ Plugin.call($target, options)
460
508
 
461
- if (slideIndex = $this.attr('data-slide-to')) {
462
- $target.data('carousel').pause().to(slideIndex).cycle()
509
+ if (slideIndex) {
510
+ $target.data('bs.carousel').to(slideIndex)
463
511
  }
464
512
 
465
513
  e.preventDefault()
466
- })
514
+ }
515
+
516
+ $(document)
517
+ .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
518
+ .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
467
519
 
468
- }(window.jQuery);/* =============================================================
469
- * bootstrap-collapse.js v2.3.1
470
- * http://twitter.github.com/bootstrap/javascript.html#collapse
471
- * =============================================================
472
- * Copyright 2012 Twitter, Inc.
473
- *
474
- * Licensed under the Apache License, Version 2.0 (the "License");
475
- * you may not use this file except in compliance with the License.
476
- * You may obtain a copy of the License at
477
- *
478
- * http://www.apache.org/licenses/LICENSE-2.0
479
- *
480
- * Unless required by applicable law or agreed to in writing, software
481
- * distributed under the License is distributed on an "AS IS" BASIS,
482
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
483
- * See the License for the specific language governing permissions and
484
- * limitations under the License.
485
- * ============================================================ */
520
+ $(window).on('load', function () {
521
+ $('[data-ride="carousel"]').each(function () {
522
+ var $carousel = $(this)
523
+ Plugin.call($carousel, $carousel.data())
524
+ })
525
+ })
486
526
 
527
+ }(jQuery);
487
528
 
488
- !function ($) {
529
+ /* ========================================================================
530
+ * Bootstrap: collapse.js v3.3.2
531
+ * http://getbootstrap.com/javascript/#collapse
532
+ * ========================================================================
533
+ * Copyright 2011-2015 Twitter, Inc.
534
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
535
+ * ======================================================================== */
489
536
 
490
- "use strict"; // jshint ;_;
491
537
 
538
+ +function ($) {
539
+ 'use strict';
492
540
 
493
- /* COLLAPSE PUBLIC CLASS DEFINITION
494
- * ================================ */
541
+ // COLLAPSE PUBLIC CLASS DEFINITION
542
+ // ================================
495
543
 
496
544
  var Collapse = function (element, options) {
497
- this.$element = $(element)
498
- this.options = $.extend({}, $.fn.collapse.defaults, options)
545
+ this.$element = $(element)
546
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
547
+ this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
548
+ this.transitioning = null
499
549
 
500
550
  if (this.options.parent) {
501
- this.$parent = $(this.options.parent)
551
+ this.$parent = this.getParent()
552
+ } else {
553
+ this.addAriaAndCollapsedClass(this.$element, this.$trigger)
502
554
  }
503
555
 
504
- this.options.toggle && this.toggle()
556
+ if (this.options.toggle) this.toggle()
505
557
  }
506
558
 
507
- Collapse.prototype = {
508
-
509
- constructor: Collapse
559
+ Collapse.VERSION = '3.3.2'
510
560
 
511
- , dimension: function () {
512
- var hasWidth = this.$element.hasClass('width')
513
- return hasWidth ? 'width' : 'height'
514
- }
561
+ Collapse.TRANSITION_DURATION = 350
515
562
 
516
- , show: function () {
517
- var dimension
518
- , scroll
519
- , actives
520
- , hasData
563
+ Collapse.DEFAULTS = {
564
+ toggle: true,
565
+ trigger: '[data-toggle="collapse"]'
566
+ }
521
567
 
522
- if (this.transitioning || this.$element.hasClass('in')) return
568
+ Collapse.prototype.dimension = function () {
569
+ var hasWidth = this.$element.hasClass('width')
570
+ return hasWidth ? 'width' : 'height'
571
+ }
523
572
 
524
- dimension = this.dimension()
525
- scroll = $.camelCase(['scroll', dimension].join('-'))
526
- actives = this.$parent && this.$parent.find('> .accordion-group > .in')
573
+ Collapse.prototype.show = function () {
574
+ if (this.transitioning || this.$element.hasClass('in')) return
527
575
 
528
- if (actives && actives.length) {
529
- hasData = actives.data('collapse')
530
- if (hasData && hasData.transitioning) return
531
- actives.collapse('hide')
532
- hasData || actives.data('collapse', null)
533
- }
576
+ var activesData
577
+ var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
534
578
 
535
- this.$element[dimension](0)
536
- this.transition('addClass', $.Event('show'), 'shown')
537
- $.support.transition && this.$element[dimension](this.$element[0][scroll])
579
+ if (actives && actives.length) {
580
+ activesData = actives.data('bs.collapse')
581
+ if (activesData && activesData.transitioning) return
538
582
  }
539
583
 
540
- , hide: function () {
541
- var dimension
542
- if (this.transitioning || !this.$element.hasClass('in')) return
543
- dimension = this.dimension()
544
- this.reset(this.$element[dimension]())
545
- this.transition('removeClass', $.Event('hide'), 'hidden')
546
- this.$element[dimension](0)
584
+ var startEvent = $.Event('show.bs.collapse')
585
+ this.$element.trigger(startEvent)
586
+ if (startEvent.isDefaultPrevented()) return
587
+
588
+ if (actives && actives.length) {
589
+ Plugin.call(actives, 'hide')
590
+ activesData || actives.data('bs.collapse', null)
547
591
  }
548
592
 
549
- , reset: function (size) {
550
- var dimension = this.dimension()
593
+ var dimension = this.dimension()
551
594
 
552
- this.$element
553
- .removeClass('collapse')
554
- [dimension](size || 'auto')
555
- [0].offsetWidth
595
+ this.$element
596
+ .removeClass('collapse')
597
+ .addClass('collapsing')[dimension](0)
598
+ .attr('aria-expanded', true)
556
599
 
557
- this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
600
+ this.$trigger
601
+ .removeClass('collapsed')
602
+ .attr('aria-expanded', true)
558
603
 
559
- return this
604
+ this.transitioning = 1
605
+
606
+ var complete = function () {
607
+ this.$element
608
+ .removeClass('collapsing')
609
+ .addClass('collapse in')[dimension]('')
610
+ this.transitioning = 0
611
+ this.$element
612
+ .trigger('shown.bs.collapse')
560
613
  }
561
614
 
562
- , transition: function (method, startEvent, completeEvent) {
563
- var that = this
564
- , complete = function () {
565
- if (startEvent.type == 'show') that.reset()
566
- that.transitioning = 0
567
- that.$element.trigger(completeEvent)
568
- }
615
+ if (!$.support.transition) return complete.call(this)
569
616
 
570
- this.$element.trigger(startEvent)
617
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
571
618
 
572
- if (startEvent.isDefaultPrevented()) return
619
+ this.$element
620
+ .one('bsTransitionEnd', $.proxy(complete, this))
621
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
622
+ }
573
623
 
574
- this.transitioning = 1
624
+ Collapse.prototype.hide = function () {
625
+ if (this.transitioning || !this.$element.hasClass('in')) return
575
626
 
576
- this.$element[method]('in')
627
+ var startEvent = $.Event('hide.bs.collapse')
628
+ this.$element.trigger(startEvent)
629
+ if (startEvent.isDefaultPrevented()) return
577
630
 
578
- $.support.transition && this.$element.hasClass('collapse') ?
579
- this.$element.one($.support.transition.end, complete) :
580
- complete()
581
- }
631
+ var dimension = this.dimension()
632
+
633
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
634
+
635
+ this.$element
636
+ .addClass('collapsing')
637
+ .removeClass('collapse in')
638
+ .attr('aria-expanded', false)
639
+
640
+ this.$trigger
641
+ .addClass('collapsed')
642
+ .attr('aria-expanded', false)
582
643
 
583
- , toggle: function () {
584
- this[this.$element.hasClass('in') ? 'hide' : 'show']()
644
+ this.transitioning = 1
645
+
646
+ var complete = function () {
647
+ this.transitioning = 0
648
+ this.$element
649
+ .removeClass('collapsing')
650
+ .addClass('collapse')
651
+ .trigger('hidden.bs.collapse')
585
652
  }
586
653
 
654
+ if (!$.support.transition) return complete.call(this)
655
+
656
+ this.$element
657
+ [dimension](0)
658
+ .one('bsTransitionEnd', $.proxy(complete, this))
659
+ .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
660
+ }
661
+
662
+ Collapse.prototype.toggle = function () {
663
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
587
664
  }
588
665
 
666
+ Collapse.prototype.getParent = function () {
667
+ return $(this.options.parent)
668
+ .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
669
+ .each($.proxy(function (i, element) {
670
+ var $element = $(element)
671
+ this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
672
+ }, this))
673
+ .end()
674
+ }
589
675
 
590
- /* COLLAPSE PLUGIN DEFINITION
591
- * ========================== */
676
+ Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
677
+ var isOpen = $element.hasClass('in')
678
+
679
+ $element.attr('aria-expanded', isOpen)
680
+ $trigger
681
+ .toggleClass('collapsed', !isOpen)
682
+ .attr('aria-expanded', isOpen)
683
+ }
684
+
685
+ function getTargetFromTrigger($trigger) {
686
+ var href
687
+ var target = $trigger.attr('data-target')
688
+ || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
689
+
690
+ return $(target)
691
+ }
592
692
 
593
- var old = $.fn.collapse
594
693
 
595
- $.fn.collapse = function (option) {
694
+ // COLLAPSE PLUGIN DEFINITION
695
+ // ==========================
696
+
697
+ function Plugin(option) {
596
698
  return this.each(function () {
597
- var $this = $(this)
598
- , data = $this.data('collapse')
599
- , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
600
- if (!data) $this.data('collapse', (data = new Collapse(this, options)))
699
+ var $this = $(this)
700
+ var data = $this.data('bs.collapse')
701
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
702
+
703
+ if (!data && options.toggle && option == 'show') options.toggle = false
704
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
601
705
  if (typeof option == 'string') data[option]()
602
706
  })
603
707
  }
604
708
 
605
- $.fn.collapse.defaults = {
606
- toggle: true
607
- }
709
+ var old = $.fn.collapse
608
710
 
711
+ $.fn.collapse = Plugin
609
712
  $.fn.collapse.Constructor = Collapse
610
713
 
611
714
 
612
- /* COLLAPSE NO CONFLICT
613
- * ==================== */
715
+ // COLLAPSE NO CONFLICT
716
+ // ====================
614
717
 
615
718
  $.fn.collapse.noConflict = function () {
616
719
  $.fn.collapse = old
@@ -618,166 +721,165 @@
618
721
  }
619
722
 
620
723
 
621
- /* COLLAPSE DATA-API
622
- * ================= */
724
+ // COLLAPSE DATA-API
725
+ // =================
726
+
727
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
728
+ var $this = $(this)
729
+
730
+ if (!$this.attr('data-target')) e.preventDefault()
731
+
732
+ var $target = getTargetFromTrigger($this)
733
+ var data = $target.data('bs.collapse')
734
+ var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
623
735
 
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)
736
+ Plugin.call($target, option)
632
737
  })
633
738
 
634
- }(window.jQuery);/* ============================================================
635
- * bootstrap-dropdown.js v2.3.1
636
- * http://twitter.github.com/bootstrap/javascript.html#dropdowns
637
- * ============================================================
638
- * Copyright 2012 Twitter, Inc.
639
- *
640
- * Licensed under the Apache License, Version 2.0 (the "License");
641
- * you may not use this file except in compliance with the License.
642
- * You may obtain a copy of the License at
643
- *
644
- * http://www.apache.org/licenses/LICENSE-2.0
645
- *
646
- * Unless required by applicable law or agreed to in writing, software
647
- * distributed under the License is distributed on an "AS IS" BASIS,
648
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
649
- * See the License for the specific language governing permissions and
650
- * limitations under the License.
651
- * ============================================================ */
652
-
653
-
654
- !function ($) {
655
-
656
- "use strict"; // jshint ;_;
657
-
658
-
659
- /* DROPDOWN CLASS DEFINITION
660
- * ========================= */
661
-
662
- var toggle = '[data-toggle=dropdown]'
663
- , Dropdown = function (element) {
664
- var $el = $(element).on('click.dropdown.data-api', this.toggle)
665
- $('html').on('click.dropdown.data-api', function () {
666
- $el.parent().removeClass('open')
667
- })
668
- }
739
+ }(jQuery);
669
740
 
670
- Dropdown.prototype = {
741
+ /* ========================================================================
742
+ * Bootstrap: dropdown.js v3.3.2
743
+ * http://getbootstrap.com/javascript/#dropdowns
744
+ * ========================================================================
745
+ * Copyright 2011-2015 Twitter, Inc.
746
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
747
+ * ======================================================================== */
671
748
 
672
- constructor: Dropdown
673
749
 
674
- , toggle: function (e) {
675
- var $this = $(this)
676
- , $parent
677
- , isActive
750
+ +function ($) {
751
+ 'use strict';
752
+
753
+ // DROPDOWN CLASS DEFINITION
754
+ // =========================
678
755
 
679
- if ($this.is('.disabled, :disabled')) return
756
+ var backdrop = '.dropdown-backdrop'
757
+ var toggle = '[data-toggle="dropdown"]'
758
+ var Dropdown = function (element) {
759
+ $(element).on('click.bs.dropdown', this.toggle)
760
+ }
761
+
762
+ Dropdown.VERSION = '3.3.2'
763
+
764
+ Dropdown.prototype.toggle = function (e) {
765
+ var $this = $(this)
680
766
 
681
- $parent = getParent($this)
767
+ if ($this.is('.disabled, :disabled')) return
682
768
 
683
- isActive = $parent.hasClass('open')
769
+ var $parent = getParent($this)
770
+ var isActive = $parent.hasClass('open')
684
771
 
685
- clearMenus()
772
+ clearMenus()
686
773
 
687
- if (!isActive) {
688
- $parent.toggleClass('open')
774
+ if (!isActive) {
775
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
776
+ // if mobile we use a backdrop because click events don't delegate
777
+ $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
689
778
  }
690
779
 
691
- $this.focus()
780
+ var relatedTarget = { relatedTarget: this }
781
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
692
782
 
693
- return false
694
- }
783
+ if (e.isDefaultPrevented()) return
695
784
 
696
- , keydown: function (e) {
697
- var $this
698
- , $items
699
- , $active
700
- , $parent
701
- , isActive
702
- , index
785
+ $this
786
+ .trigger('focus')
787
+ .attr('aria-expanded', 'true')
703
788
 
704
- if (!/(38|40|27)/.test(e.keyCode)) return
789
+ $parent
790
+ .toggleClass('open')
791
+ .trigger('shown.bs.dropdown', relatedTarget)
792
+ }
705
793
 
706
- $this = $(this)
794
+ return false
795
+ }
707
796
 
708
- e.preventDefault()
709
- e.stopPropagation()
797
+ Dropdown.prototype.keydown = function (e) {
798
+ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
710
799
 
711
- if ($this.is('.disabled, :disabled')) return
800
+ var $this = $(this)
712
801
 
713
- $parent = getParent($this)
802
+ e.preventDefault()
803
+ e.stopPropagation()
714
804
 
715
- isActive = $parent.hasClass('open')
805
+ if ($this.is('.disabled, :disabled')) return
716
806
 
717
- if (!isActive || (isActive && e.keyCode == 27)) {
718
- if (e.which == 27) $parent.find(toggle).focus()
719
- return $this.click()
720
- }
807
+ var $parent = getParent($this)
808
+ var isActive = $parent.hasClass('open')
721
809
 
722
- $items = $('[role=menu] li:not(.divider):visible a', $parent)
810
+ if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
811
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
812
+ return $this.trigger('click')
813
+ }
723
814
 
724
- if (!$items.length) return
815
+ var desc = ' li:not(.divider):visible a'
816
+ var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
725
817
 
726
- index = $items.index($items.filter(':focus'))
818
+ if (!$items.length) return
727
819
 
728
- if (e.keyCode == 38 && index > 0) index-- // up
729
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
730
- if (!~index) index = 0
820
+ var index = $items.index(e.target)
731
821
 
732
- $items
733
- .eq(index)
734
- .focus()
735
- }
822
+ if (e.which == 38 && index > 0) index-- // up
823
+ if (e.which == 40 && index < $items.length - 1) index++ // down
824
+ if (!~index) index = 0
736
825
 
826
+ $items.eq(index).trigger('focus')
737
827
  }
738
828
 
739
- function clearMenus() {
829
+ function clearMenus(e) {
830
+ if (e && e.which === 3) return
831
+ $(backdrop).remove()
740
832
  $(toggle).each(function () {
741
- getParent($(this)).removeClass('open')
833
+ var $this = $(this)
834
+ var $parent = getParent($this)
835
+ var relatedTarget = { relatedTarget: this }
836
+
837
+ if (!$parent.hasClass('open')) return
838
+
839
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
840
+
841
+ if (e.isDefaultPrevented()) return
842
+
843
+ $this.attr('aria-expanded', 'false')
844
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
742
845
  })
743
846
  }
744
847
 
745
848
  function getParent($this) {
746
849
  var selector = $this.attr('data-target')
747
- , $parent
748
850
 
749
851
  if (!selector) {
750
852
  selector = $this.attr('href')
751
- selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
853
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
752
854
  }
753
855
 
754
- $parent = selector && $(selector)
856
+ var $parent = selector && $(selector)
755
857
 
756
- if (!$parent || !$parent.length) $parent = $this.parent()
757
-
758
- return $parent
858
+ return $parent && $parent.length ? $parent : $this.parent()
759
859
  }
760
860
 
761
861
 
762
- /* DROPDOWN PLUGIN DEFINITION
763
- * ========================== */
764
-
765
- var old = $.fn.dropdown
862
+ // DROPDOWN PLUGIN DEFINITION
863
+ // ==========================
766
864
 
767
- $.fn.dropdown = function (option) {
865
+ function Plugin(option) {
768
866
  return this.each(function () {
769
867
  var $this = $(this)
770
- , data = $this.data('dropdown')
771
- if (!data) $this.data('dropdown', (data = new Dropdown(this)))
868
+ var data = $this.data('bs.dropdown')
869
+
870
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
772
871
  if (typeof option == 'string') data[option].call($this)
773
872
  })
774
873
  }
775
874
 
875
+ var old = $.fn.dropdown
876
+
877
+ $.fn.dropdown = Plugin
776
878
  $.fn.dropdown.Constructor = Dropdown
777
879
 
778
880
 
779
- /* DROPDOWN NO CONFLICT
780
- * ==================== */
881
+ // DROPDOWN NO CONFLICT
882
+ // ====================
781
883
 
782
884
  $.fn.dropdown.noConflict = function () {
783
885
  $.fn.dropdown = old
@@ -785,238 +887,315 @@
785
887
  }
786
888
 
787
889
 
788
- /* APPLY TO STANDARD DROPDOWN ELEMENTS
789
- * =================================== */
890
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
891
+ // ===================================
790
892
 
791
893
  $(document)
792
- .on('click.dropdown.data-api', clearMenus)
793
- .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
794
- .on('click.dropdown-menu', function (e) { e.stopPropagation() })
795
- .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
796
- .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
797
-
798
- }(window.jQuery);
799
- /* =========================================================
800
- * bootstrap-modal.js v2.3.1
801
- * http://twitter.github.com/bootstrap/javascript.html#modals
802
- * =========================================================
803
- * Copyright 2012 Twitter, Inc.
804
- *
805
- * Licensed under the Apache License, Version 2.0 (the "License");
806
- * you may not use this file except in compliance with the License.
807
- * You may obtain a copy of the License at
808
- *
809
- * http://www.apache.org/licenses/LICENSE-2.0
810
- *
811
- * Unless required by applicable law or agreed to in writing, software
812
- * distributed under the License is distributed on an "AS IS" BASIS,
813
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
814
- * See the License for the specific language governing permissions and
815
- * limitations under the License.
816
- * ========================================================= */
817
-
818
-
819
- !function ($) {
820
-
821
- "use strict"; // jshint ;_;
822
-
823
-
824
- /* MODAL CLASS DEFINITION
825
- * ====================== */
894
+ .on('click.bs.dropdown.data-api', clearMenus)
895
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
896
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
897
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
898
+ .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
899
+ .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
900
+
901
+ }(jQuery);
902
+
903
+ /* ========================================================================
904
+ * Bootstrap: modal.js v3.3.2
905
+ * http://getbootstrap.com/javascript/#modals
906
+ * ========================================================================
907
+ * Copyright 2011-2015 Twitter, Inc.
908
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
909
+ * ======================================================================== */
910
+
911
+
912
+ +function ($) {
913
+ 'use strict';
914
+
915
+ // MODAL CLASS DEFINITION
916
+ // ======================
826
917
 
827
918
  var Modal = function (element, options) {
828
- this.options = options
829
- this.$element = $(element)
830
- .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
831
- this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
919
+ this.options = options
920
+ this.$body = $(document.body)
921
+ this.$element = $(element)
922
+ this.$backdrop =
923
+ this.isShown = null
924
+ this.scrollbarWidth = 0
925
+
926
+ if (this.options.remote) {
927
+ this.$element
928
+ .find('.modal-content')
929
+ .load(this.options.remote, $.proxy(function () {
930
+ this.$element.trigger('loaded.bs.modal')
931
+ }, this))
932
+ }
832
933
  }
833
934
 
834
- Modal.prototype = {
935
+ Modal.VERSION = '3.3.2'
835
936
 
836
- constructor: Modal
937
+ Modal.TRANSITION_DURATION = 300
938
+ Modal.BACKDROP_TRANSITION_DURATION = 150
837
939
 
838
- , toggle: function () {
839
- return this[!this.isShown ? 'show' : 'hide']()
840
- }
940
+ Modal.DEFAULTS = {
941
+ backdrop: true,
942
+ keyboard: true,
943
+ show: true
944
+ }
841
945
 
842
- , show: function () {
843
- var that = this
844
- , e = $.Event('show')
946
+ Modal.prototype.toggle = function (_relatedTarget) {
947
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
948
+ }
845
949
 
846
- this.$element.trigger(e)
950
+ Modal.prototype.show = function (_relatedTarget) {
951
+ var that = this
952
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
847
953
 
848
- if (this.isShown || e.isDefaultPrevented()) return
954
+ this.$element.trigger(e)
849
955
 
850
- this.isShown = true
956
+ if (this.isShown || e.isDefaultPrevented()) return
851
957
 
852
- this.escape()
958
+ this.isShown = true
853
959
 
854
- this.backdrop(function () {
855
- var transition = $.support.transition && that.$element.hasClass('fade')
960
+ this.checkScrollbar()
961
+ this.setScrollbar()
962
+ this.$body.addClass('modal-open')
856
963
 
857
- if (!that.$element.parent().length) {
858
- that.$element.appendTo(document.body) //don't move modals dom position
859
- }
964
+ this.escape()
965
+ this.resize()
860
966
 
861
- that.$element.show()
967
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
862
968
 
863
- if (transition) {
864
- that.$element[0].offsetWidth // force reflow
865
- }
969
+ this.backdrop(function () {
970
+ var transition = $.support.transition && that.$element.hasClass('fade')
866
971
 
867
- that.$element
868
- .addClass('in')
869
- .attr('aria-hidden', false)
972
+ if (!that.$element.parent().length) {
973
+ that.$element.appendTo(that.$body) // don't move modals dom position
974
+ }
870
975
 
871
- that.enforceFocus()
976
+ that.$element
977
+ .show()
978
+ .scrollTop(0)
872
979
 
873
- transition ?
874
- that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
875
- that.$element.focus().trigger('shown')
980
+ if (that.options.backdrop) that.adjustBackdrop()
981
+ that.adjustDialog()
876
982
 
877
- })
983
+ if (transition) {
984
+ that.$element[0].offsetWidth // force reflow
878
985
  }
879
986
 
880
- , hide: function (e) {
881
- e && e.preventDefault()
987
+ that.$element
988
+ .addClass('in')
989
+ .attr('aria-hidden', false)
990
+
991
+ that.enforceFocus()
992
+
993
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
882
994
 
883
- var that = this
995
+ transition ?
996
+ that.$element.find('.modal-dialog') // wait for modal to slide in
997
+ .one('bsTransitionEnd', function () {
998
+ that.$element.trigger('focus').trigger(e)
999
+ })
1000
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1001
+ that.$element.trigger('focus').trigger(e)
1002
+ })
1003
+ }
884
1004
 
885
- e = $.Event('hide')
1005
+ Modal.prototype.hide = function (e) {
1006
+ if (e) e.preventDefault()
886
1007
 
887
- this.$element.trigger(e)
1008
+ e = $.Event('hide.bs.modal')
888
1009
 
889
- if (!this.isShown || e.isDefaultPrevented()) return
1010
+ this.$element.trigger(e)
890
1011
 
891
- this.isShown = false
1012
+ if (!this.isShown || e.isDefaultPrevented()) return
892
1013
 
893
- this.escape()
1014
+ this.isShown = false
894
1015
 
895
- $(document).off('focusin.modal')
1016
+ this.escape()
1017
+ this.resize()
896
1018
 
897
- this.$element
898
- .removeClass('in')
899
- .attr('aria-hidden', true)
1019
+ $(document).off('focusin.bs.modal')
900
1020
 
901
- $.support.transition && this.$element.hasClass('fade') ?
902
- this.hideWithTransition() :
903
- this.hideModal()
904
- }
1021
+ this.$element
1022
+ .removeClass('in')
1023
+ .attr('aria-hidden', true)
1024
+ .off('click.dismiss.bs.modal')
905
1025
 
906
- , enforceFocus: function () {
907
- var that = this
908
- $(document).on('focusin.modal', function (e) {
909
- if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
910
- that.$element.focus()
911
- }
912
- })
913
- }
1026
+ $.support.transition && this.$element.hasClass('fade') ?
1027
+ this.$element
1028
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
1029
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
1030
+ this.hideModal()
1031
+ }
914
1032
 
915
- , escape: function () {
916
- var that = this
917
- if (this.isShown && this.options.keyboard) {
918
- this.$element.on('keyup.dismiss.modal', function ( e ) {
919
- e.which == 27 && that.hide()
920
- })
921
- } else if (!this.isShown) {
922
- this.$element.off('keyup.dismiss.modal')
1033
+ Modal.prototype.enforceFocus = function () {
1034
+ $(document)
1035
+ .off('focusin.bs.modal') // guard against infinite focus loop
1036
+ .on('focusin.bs.modal', $.proxy(function (e) {
1037
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
1038
+ this.$element.trigger('focus')
923
1039
  }
924
- }
1040
+ }, this))
1041
+ }
925
1042
 
926
- , hideWithTransition: function () {
927
- var that = this
928
- , timeout = setTimeout(function () {
929
- that.$element.off($.support.transition.end)
930
- that.hideModal()
931
- }, 500)
1043
+ Modal.prototype.escape = function () {
1044
+ if (this.isShown && this.options.keyboard) {
1045
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
1046
+ e.which == 27 && this.hide()
1047
+ }, this))
1048
+ } else if (!this.isShown) {
1049
+ this.$element.off('keydown.dismiss.bs.modal')
1050
+ }
1051
+ }
932
1052
 
933
- this.$element.one($.support.transition.end, function () {
934
- clearTimeout(timeout)
935
- that.hideModal()
936
- })
937
- }
1053
+ Modal.prototype.resize = function () {
1054
+ if (this.isShown) {
1055
+ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
1056
+ } else {
1057
+ $(window).off('resize.bs.modal')
1058
+ }
1059
+ }
938
1060
 
939
- , hideModal: function () {
940
- var that = this
941
- this.$element.hide()
942
- this.backdrop(function () {
943
- that.removeBackdrop()
944
- that.$element.trigger('hidden')
945
- })
946
- }
1061
+ Modal.prototype.hideModal = function () {
1062
+ var that = this
1063
+ this.$element.hide()
1064
+ this.backdrop(function () {
1065
+ that.$body.removeClass('modal-open')
1066
+ that.resetAdjustments()
1067
+ that.resetScrollbar()
1068
+ that.$element.trigger('hidden.bs.modal')
1069
+ })
1070
+ }
947
1071
 
948
- , removeBackdrop: function () {
949
- this.$backdrop && this.$backdrop.remove()
950
- this.$backdrop = null
951
- }
1072
+ Modal.prototype.removeBackdrop = function () {
1073
+ this.$backdrop && this.$backdrop.remove()
1074
+ this.$backdrop = null
1075
+ }
952
1076
 
953
- , backdrop: function (callback) {
954
- var that = this
955
- , animate = this.$element.hasClass('fade') ? 'fade' : ''
1077
+ Modal.prototype.backdrop = function (callback) {
1078
+ var that = this
1079
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
956
1080
 
957
- if (this.isShown && this.options.backdrop) {
958
- var doAnimate = $.support.transition && animate
1081
+ if (this.isShown && this.options.backdrop) {
1082
+ var doAnimate = $.support.transition && animate
959
1083
 
960
- this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
961
- .appendTo(document.body)
1084
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
1085
+ .prependTo(this.$element)
1086
+ .on('click.dismiss.bs.modal', $.proxy(function (e) {
1087
+ if (e.target !== e.currentTarget) return
1088
+ this.options.backdrop == 'static'
1089
+ ? this.$element[0].focus.call(this.$element[0])
1090
+ : this.hide.call(this)
1091
+ }, this))
962
1092
 
963
- this.$backdrop.click(
964
- this.options.backdrop == 'static' ?
965
- $.proxy(this.$element[0].focus, this.$element[0])
966
- : $.proxy(this.hide, this)
967
- )
1093
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
968
1094
 
969
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
1095
+ this.$backdrop.addClass('in')
970
1096
 
971
- this.$backdrop.addClass('in')
1097
+ if (!callback) return
972
1098
 
973
- if (!callback) return
1099
+ doAnimate ?
1100
+ this.$backdrop
1101
+ .one('bsTransitionEnd', callback)
1102
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1103
+ callback()
974
1104
 
975
- doAnimate ?
976
- this.$backdrop.one($.support.transition.end, callback) :
977
- callback()
1105
+ } else if (!this.isShown && this.$backdrop) {
1106
+ this.$backdrop.removeClass('in')
1107
+
1108
+ var callbackRemove = function () {
1109
+ that.removeBackdrop()
1110
+ callback && callback()
1111
+ }
1112
+ $.support.transition && this.$element.hasClass('fade') ?
1113
+ this.$backdrop
1114
+ .one('bsTransitionEnd', callbackRemove)
1115
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
1116
+ callbackRemove()
978
1117
 
979
- } else if (!this.isShown && this.$backdrop) {
980
- this.$backdrop.removeClass('in')
1118
+ } else if (callback) {
1119
+ callback()
1120
+ }
1121
+ }
981
1122
 
982
- $.support.transition && this.$element.hasClass('fade')?
983
- this.$backdrop.one($.support.transition.end, callback) :
984
- callback()
1123
+ // these following methods are used to handle overflowing modals
985
1124
 
986
- } else if (callback) {
987
- callback()
988
- }
989
- }
1125
+ Modal.prototype.handleUpdate = function () {
1126
+ if (this.options.backdrop) this.adjustBackdrop()
1127
+ this.adjustDialog()
990
1128
  }
991
1129
 
1130
+ Modal.prototype.adjustBackdrop = function () {
1131
+ this.$backdrop
1132
+ .css('height', 0)
1133
+ .css('height', this.$element[0].scrollHeight)
1134
+ }
992
1135
 
993
- /* MODAL PLUGIN DEFINITION
994
- * ======================= */
1136
+ Modal.prototype.adjustDialog = function () {
1137
+ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
995
1138
 
996
- var old = $.fn.modal
1139
+ this.$element.css({
1140
+ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
1141
+ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
1142
+ })
1143
+ }
997
1144
 
998
- $.fn.modal = function (option) {
999
- return this.each(function () {
1000
- var $this = $(this)
1001
- , data = $this.data('modal')
1002
- , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
1003
- if (!data) $this.data('modal', (data = new Modal(this, options)))
1004
- if (typeof option == 'string') data[option]()
1005
- else if (options.show) data.show()
1145
+ Modal.prototype.resetAdjustments = function () {
1146
+ this.$element.css({
1147
+ paddingLeft: '',
1148
+ paddingRight: ''
1006
1149
  })
1007
1150
  }
1008
1151
 
1009
- $.fn.modal.defaults = {
1010
- backdrop: true
1011
- , keyboard: true
1012
- , show: true
1152
+ Modal.prototype.checkScrollbar = function () {
1153
+ this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
1154
+ this.scrollbarWidth = this.measureScrollbar()
1155
+ }
1156
+
1157
+ Modal.prototype.setScrollbar = function () {
1158
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
1159
+ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
1160
+ }
1161
+
1162
+ Modal.prototype.resetScrollbar = function () {
1163
+ this.$body.css('padding-right', '')
1164
+ }
1165
+
1166
+ Modal.prototype.measureScrollbar = function () { // thx walsh
1167
+ var scrollDiv = document.createElement('div')
1168
+ scrollDiv.className = 'modal-scrollbar-measure'
1169
+ this.$body.append(scrollDiv)
1170
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
1171
+ this.$body[0].removeChild(scrollDiv)
1172
+ return scrollbarWidth
1173
+ }
1174
+
1175
+
1176
+ // MODAL PLUGIN DEFINITION
1177
+ // =======================
1178
+
1179
+ function Plugin(option, _relatedTarget) {
1180
+ return this.each(function () {
1181
+ var $this = $(this)
1182
+ var data = $this.data('bs.modal')
1183
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
1184
+
1185
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
1186
+ if (typeof option == 'string') data[option](_relatedTarget)
1187
+ else if (options.show) data.show(_relatedTarget)
1188
+ })
1013
1189
  }
1014
1190
 
1191
+ var old = $.fn.modal
1192
+
1193
+ $.fn.modal = Plugin
1015
1194
  $.fn.modal.Constructor = Modal
1016
1195
 
1017
1196
 
1018
- /* MODAL NO CONFLICT
1019
- * ================= */
1197
+ // MODAL NO CONFLICT
1198
+ // =================
1020
1199
 
1021
1200
  $.fn.modal.noConflict = function () {
1022
1201
  $.fn.modal = old
@@ -1024,1230 +1203,1082 @@
1024
1203
  }
1025
1204
 
1026
1205
 
1027
- /* MODAL DATA-API
1028
- * ============== */
1206
+ // MODAL DATA-API
1207
+ // ==============
1029
1208
 
1030
- $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
1031
- var $this = $(this)
1032
- , href = $this.attr('href')
1033
- , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
1034
- , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
1209
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
1210
+ var $this = $(this)
1211
+ var href = $this.attr('href')
1212
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
1213
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
1035
1214
 
1036
- e.preventDefault()
1215
+ if ($this.is('a')) e.preventDefault()
1037
1216
 
1038
- $target
1039
- .modal(option)
1040
- .one('hide', function () {
1041
- $this.focus()
1217
+ $target.one('show.bs.modal', function (showEvent) {
1218
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
1219
+ $target.one('hidden.bs.modal', function () {
1220
+ $this.is(':visible') && $this.trigger('focus')
1042
1221
  })
1222
+ })
1223
+ Plugin.call($target, option, this)
1043
1224
  })
1044
1225
 
1045
- }(window.jQuery);
1046
- /* ===========================================================
1047
- * bootstrap-tooltip.js v2.3.1
1048
- * http://twitter.github.com/bootstrap/javascript.html#tooltips
1049
- * Inspired by the original jQuery.tipsy by Jason Frame
1050
- * ===========================================================
1051
- * Copyright 2012 Twitter, Inc.
1052
- *
1053
- * Licensed under the Apache License, Version 2.0 (the "License");
1054
- * you may not use this file except in compliance with the License.
1055
- * You may obtain a copy of the License at
1056
- *
1057
- * http://www.apache.org/licenses/LICENSE-2.0
1058
- *
1059
- * Unless required by applicable law or agreed to in writing, software
1060
- * distributed under the License is distributed on an "AS IS" BASIS,
1061
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1062
- * See the License for the specific language governing permissions and
1063
- * limitations under the License.
1064
- * ========================================================== */
1065
-
1226
+ }(jQuery);
1066
1227
 
1067
- !function ($) {
1228
+ /* ========================================================================
1229
+ * Bootstrap: tooltip.js v3.3.2
1230
+ * http://getbootstrap.com/javascript/#tooltip
1231
+ * Inspired by the original jQuery.tipsy by Jason Frame
1232
+ * ========================================================================
1233
+ * Copyright 2011-2015 Twitter, Inc.
1234
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1235
+ * ======================================================================== */
1068
1236
 
1069
- "use strict"; // jshint ;_;
1070
1237
 
1238
+ +function ($) {
1239
+ 'use strict';
1071
1240
 
1072
- /* TOOLTIP PUBLIC CLASS DEFINITION
1073
- * =============================== */
1241
+ // TOOLTIP PUBLIC CLASS DEFINITION
1242
+ // ===============================
1074
1243
 
1075
1244
  var Tooltip = function (element, options) {
1245
+ this.type =
1246
+ this.options =
1247
+ this.enabled =
1248
+ this.timeout =
1249
+ this.hoverState =
1250
+ this.$element = null
1251
+
1076
1252
  this.init('tooltip', element, options)
1077
1253
  }
1078
1254
 
1079
- Tooltip.prototype = {
1255
+ Tooltip.VERSION = '3.3.2'
1256
+
1257
+ Tooltip.TRANSITION_DURATION = 150
1258
+
1259
+ Tooltip.DEFAULTS = {
1260
+ animation: true,
1261
+ placement: 'top',
1262
+ selector: false,
1263
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
1264
+ trigger: 'hover focus',
1265
+ title: '',
1266
+ delay: 0,
1267
+ html: false,
1268
+ container: false,
1269
+ viewport: {
1270
+ selector: 'body',
1271
+ padding: 0
1272
+ }
1273
+ }
1080
1274
 
1081
- constructor: Tooltip
1275
+ Tooltip.prototype.init = function (type, element, options) {
1276
+ this.enabled = true
1277
+ this.type = type
1278
+ this.$element = $(element)
1279
+ this.options = this.getOptions(options)
1280
+ this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
1082
1281
 
1083
- , init: function (type, element, options) {
1084
- var eventIn
1085
- , eventOut
1086
- , triggers
1087
- , trigger
1088
- , i
1282
+ var triggers = this.options.trigger.split(' ')
1089
1283
 
1090
- this.type = type
1091
- this.$element = $(element)
1092
- this.options = this.getOptions(options)
1093
- this.enabled = true
1284
+ for (var i = triggers.length; i--;) {
1285
+ var trigger = triggers[i]
1094
1286
 
1095
- triggers = this.options.trigger.split(' ')
1287
+ if (trigger == 'click') {
1288
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1289
+ } else if (trigger != 'manual') {
1290
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
1291
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
1096
1292
 
1097
- for (i = triggers.length; i--;) {
1098
- trigger = triggers[i]
1099
- if (trigger == 'click') {
1100
- this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
1101
- } else if (trigger != 'manual') {
1102
- eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
1103
- eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
1104
- this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1105
- this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1106
- }
1293
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
1294
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
1107
1295
  }
1108
-
1109
- this.options.selector ?
1110
- (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
1111
- this.fixTitle()
1112
1296
  }
1113
1297
 
1114
- , getOptions: function (options) {
1115
- options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
1298
+ this.options.selector ?
1299
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
1300
+ this.fixTitle()
1301
+ }
1116
1302
 
1117
- if (options.delay && typeof options.delay == 'number') {
1118
- options.delay = {
1119
- show: options.delay
1120
- , hide: options.delay
1121
- }
1122
- }
1303
+ Tooltip.prototype.getDefaults = function () {
1304
+ return Tooltip.DEFAULTS
1305
+ }
1306
+
1307
+ Tooltip.prototype.getOptions = function (options) {
1308
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
1123
1309
 
1124
- return options
1310
+ if (options.delay && typeof options.delay == 'number') {
1311
+ options.delay = {
1312
+ show: options.delay,
1313
+ hide: options.delay
1314
+ }
1125
1315
  }
1126
1316
 
1127
- , enter: function (e) {
1128
- var defaults = $.fn[this.type].defaults
1129
- , options = {}
1130
- , self
1317
+ return options
1318
+ }
1131
1319
 
1132
- this._options && $.each(this._options, function (key, value) {
1133
- if (defaults[key] != value) options[key] = value
1134
- }, this)
1320
+ Tooltip.prototype.getDelegateOptions = function () {
1321
+ var options = {}
1322
+ var defaults = this.getDefaults()
1135
1323
 
1136
- self = $(e.currentTarget)[this.type](options).data(this.type)
1324
+ this._options && $.each(this._options, function (key, value) {
1325
+ if (defaults[key] != value) options[key] = value
1326
+ })
1327
+
1328
+ return options
1329
+ }
1137
1330
 
1138
- if (!self.options.delay || !self.options.delay.show) return self.show()
1331
+ Tooltip.prototype.enter = function (obj) {
1332
+ var self = obj instanceof this.constructor ?
1333
+ obj : $(obj.currentTarget).data('bs.' + this.type)
1139
1334
 
1140
- clearTimeout(this.timeout)
1335
+ if (self && self.$tip && self.$tip.is(':visible')) {
1141
1336
  self.hoverState = 'in'
1142
- this.timeout = setTimeout(function() {
1143
- if (self.hoverState == 'in') self.show()
1144
- }, self.options.delay.show)
1337
+ return
1145
1338
  }
1146
1339
 
1147
- , leave: function (e) {
1148
- var self = $(e.currentTarget)[this.type](this._options).data(this.type)
1149
-
1150
- if (this.timeout) clearTimeout(this.timeout)
1151
- if (!self.options.delay || !self.options.delay.hide) return self.hide()
1152
-
1153
- self.hoverState = 'out'
1154
- this.timeout = setTimeout(function() {
1155
- if (self.hoverState == 'out') self.hide()
1156
- }, self.options.delay.hide)
1340
+ if (!self) {
1341
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1342
+ $(obj.currentTarget).data('bs.' + this.type, self)
1157
1343
  }
1158
1344
 
1159
- , show: function () {
1160
- var $tip
1161
- , pos
1162
- , actualWidth
1163
- , actualHeight
1164
- , placement
1165
- , tp
1166
- , e = $.Event('show')
1167
-
1168
- if (this.hasContent() && this.enabled) {
1169
- this.$element.trigger(e)
1170
- if (e.isDefaultPrevented()) return
1171
- $tip = this.tip()
1172
- this.setContent()
1173
-
1174
- if (this.options.animation) {
1175
- $tip.addClass('fade')
1176
- }
1345
+ clearTimeout(self.timeout)
1177
1346
 
1178
- placement = typeof this.options.placement == 'function' ?
1179
- this.options.placement.call(this, $tip[0], this.$element[0]) :
1180
- this.options.placement
1347
+ self.hoverState = 'in'
1181
1348
 
1182
- $tip
1183
- .detach()
1184
- .css({ top: 0, left: 0, display: 'block' })
1185
-
1186
- this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1187
-
1188
- pos = this.getPosition()
1189
-
1190
- actualWidth = $tip[0].offsetWidth
1191
- actualHeight = $tip[0].offsetHeight
1192
-
1193
- switch (placement) {
1194
- case 'bottom':
1195
- tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
1196
- break
1197
- case 'top':
1198
- tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
1199
- break
1200
- case 'left':
1201
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
1202
- break
1203
- case 'right':
1204
- tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
1205
- break
1206
- }
1349
+ if (!self.options.delay || !self.options.delay.show) return self.show()
1207
1350
 
1208
- this.applyPlacement(tp, placement)
1209
- this.$element.trigger('shown')
1210
- }
1211
- }
1351
+ self.timeout = setTimeout(function () {
1352
+ if (self.hoverState == 'in') self.show()
1353
+ }, self.options.delay.show)
1354
+ }
1212
1355
 
1213
- , applyPlacement: function(offset, placement){
1214
- var $tip = this.tip()
1215
- , width = $tip[0].offsetWidth
1216
- , height = $tip[0].offsetHeight
1217
- , actualWidth
1218
- , actualHeight
1219
- , delta
1220
- , replace
1356
+ Tooltip.prototype.leave = function (obj) {
1357
+ var self = obj instanceof this.constructor ?
1358
+ obj : $(obj.currentTarget).data('bs.' + this.type)
1221
1359
 
1222
- $tip
1223
- .offset(offset)
1224
- .addClass(placement)
1225
- .addClass('in')
1360
+ if (!self) {
1361
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1362
+ $(obj.currentTarget).data('bs.' + this.type, self)
1363
+ }
1226
1364
 
1227
- actualWidth = $tip[0].offsetWidth
1228
- actualHeight = $tip[0].offsetHeight
1365
+ clearTimeout(self.timeout)
1229
1366
 
1230
- if (placement == 'top' && actualHeight != height) {
1231
- offset.top = offset.top + height - actualHeight
1232
- replace = true
1233
- }
1367
+ self.hoverState = 'out'
1234
1368
 
1235
- if (placement == 'bottom' || placement == 'top') {
1236
- delta = 0
1369
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
1237
1370
 
1238
- if (offset.left < 0){
1239
- delta = offset.left * -2
1240
- offset.left = 0
1241
- $tip.offset(offset)
1242
- actualWidth = $tip[0].offsetWidth
1243
- actualHeight = $tip[0].offsetHeight
1244
- }
1371
+ self.timeout = setTimeout(function () {
1372
+ if (self.hoverState == 'out') self.hide()
1373
+ }, self.options.delay.hide)
1374
+ }
1245
1375
 
1246
- this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
1247
- } else {
1248
- this.replaceArrow(actualHeight - height, actualHeight, 'top')
1249
- }
1376
+ Tooltip.prototype.show = function () {
1377
+ var e = $.Event('show.bs.' + this.type)
1250
1378
 
1251
- if (replace) $tip.offset(offset)
1252
- }
1379
+ if (this.hasContent() && this.enabled) {
1380
+ this.$element.trigger(e)
1253
1381
 
1254
- , replaceArrow: function(delta, dimension, position){
1255
- this
1256
- .arrow()
1257
- .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
1258
- }
1382
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
1383
+ if (e.isDefaultPrevented() || !inDom) return
1384
+ var that = this
1259
1385
 
1260
- , setContent: function () {
1261
1386
  var $tip = this.tip()
1262
- , title = this.getTitle()
1263
1387
 
1264
- $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
1265
- $tip.removeClass('fade in top bottom left right')
1266
- }
1388
+ var tipId = this.getUID(this.type)
1267
1389
 
1268
- , hide: function () {
1269
- var that = this
1270
- , $tip = this.tip()
1271
- , e = $.Event('hide')
1390
+ this.setContent()
1391
+ $tip.attr('id', tipId)
1392
+ this.$element.attr('aria-describedby', tipId)
1272
1393
 
1273
- this.$element.trigger(e)
1274
- if (e.isDefaultPrevented()) return
1394
+ if (this.options.animation) $tip.addClass('fade')
1275
1395
 
1276
- $tip.removeClass('in')
1396
+ var placement = typeof this.options.placement == 'function' ?
1397
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
1398
+ this.options.placement
1277
1399
 
1278
- function removeWithAnimation() {
1279
- var timeout = setTimeout(function () {
1280
- $tip.off($.support.transition.end).detach()
1281
- }, 500)
1400
+ var autoToken = /\s?auto?\s?/i
1401
+ var autoPlace = autoToken.test(placement)
1402
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1282
1403
 
1283
- $tip.one($.support.transition.end, function () {
1284
- clearTimeout(timeout)
1285
- $tip.detach()
1286
- })
1287
- }
1404
+ $tip
1405
+ .detach()
1406
+ .css({ top: 0, left: 0, display: 'block' })
1407
+ .addClass(placement)
1408
+ .data('bs.' + this.type, this)
1288
1409
 
1289
- $.support.transition && this.$tip.hasClass('fade') ?
1290
- removeWithAnimation() :
1291
- $tip.detach()
1410
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1292
1411
 
1293
- this.$element.trigger('hidden')
1412
+ var pos = this.getPosition()
1413
+ var actualWidth = $tip[0].offsetWidth
1414
+ var actualHeight = $tip[0].offsetHeight
1294
1415
 
1295
- return this
1296
- }
1416
+ if (autoPlace) {
1417
+ var orgPlacement = placement
1418
+ var $container = this.options.container ? $(this.options.container) : this.$element.parent()
1419
+ var containerDim = this.getPosition($container)
1420
+
1421
+ placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
1422
+ placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
1423
+ placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
1424
+ placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
1425
+ placement
1297
1426
 
1298
- , fixTitle: function () {
1299
- var $e = this.$element
1300
- if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
1301
- $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1427
+ $tip
1428
+ .removeClass(orgPlacement)
1429
+ .addClass(placement)
1302
1430
  }
1303
- }
1304
1431
 
1305
- , hasContent: function () {
1306
- return this.getTitle()
1307
- }
1432
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1308
1433
 
1309
- , getPosition: function () {
1310
- var el = this.$element[0]
1311
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
1312
- width: el.offsetWidth
1313
- , height: el.offsetHeight
1314
- }, this.$element.offset())
1315
- }
1434
+ this.applyPlacement(calculatedOffset, placement)
1316
1435
 
1317
- , getTitle: function () {
1318
- var title
1319
- , $e = this.$element
1320
- , o = this.options
1436
+ var complete = function () {
1437
+ var prevHoverState = that.hoverState
1438
+ that.$element.trigger('shown.bs.' + that.type)
1439
+ that.hoverState = null
1321
1440
 
1322
- title = $e.attr('data-original-title')
1323
- || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1441
+ if (prevHoverState == 'out') that.leave(that)
1442
+ }
1324
1443
 
1325
- return title
1444
+ $.support.transition && this.$tip.hasClass('fade') ?
1445
+ $tip
1446
+ .one('bsTransitionEnd', complete)
1447
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1448
+ complete()
1326
1449
  }
1450
+ }
1327
1451
 
1328
- , tip: function () {
1329
- return this.$tip = this.$tip || $(this.options.template)
1330
- }
1452
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
1453
+ var $tip = this.tip()
1454
+ var width = $tip[0].offsetWidth
1455
+ var height = $tip[0].offsetHeight
1456
+
1457
+ // manually read margins because getBoundingClientRect includes difference
1458
+ var marginTop = parseInt($tip.css('margin-top'), 10)
1459
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
1460
+
1461
+ // we must check for NaN for ie 8/9
1462
+ if (isNaN(marginTop)) marginTop = 0
1463
+ if (isNaN(marginLeft)) marginLeft = 0
1464
+
1465
+ offset.top = offset.top + marginTop
1466
+ offset.left = offset.left + marginLeft
1467
+
1468
+ // $.fn.offset doesn't round pixel values
1469
+ // so we use setOffset directly with our own function B-0
1470
+ $.offset.setOffset($tip[0], $.extend({
1471
+ using: function (props) {
1472
+ $tip.css({
1473
+ top: Math.round(props.top),
1474
+ left: Math.round(props.left)
1475
+ })
1476
+ }
1477
+ }, offset), 0)
1331
1478
 
1332
- , arrow: function(){
1333
- return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
1334
- }
1479
+ $tip.addClass('in')
1335
1480
 
1336
- , validate: function () {
1337
- if (!this.$element[0].parentNode) {
1338
- this.hide()
1339
- this.$element = null
1340
- this.options = null
1341
- }
1342
- }
1481
+ // check to see if placing tip in new offset caused the tip to resize itself
1482
+ var actualWidth = $tip[0].offsetWidth
1483
+ var actualHeight = $tip[0].offsetHeight
1343
1484
 
1344
- , enable: function () {
1345
- this.enabled = true
1485
+ if (placement == 'top' && actualHeight != height) {
1486
+ offset.top = offset.top + height - actualHeight
1346
1487
  }
1347
1488
 
1348
- , disable: function () {
1349
- this.enabled = false
1350
- }
1489
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
1351
1490
 
1352
- , toggleEnabled: function () {
1353
- this.enabled = !this.enabled
1354
- }
1491
+ if (delta.left) offset.left += delta.left
1492
+ else offset.top += delta.top
1355
1493
 
1356
- , toggle: function (e) {
1357
- var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
1358
- self.tip().hasClass('in') ? self.hide() : self.show()
1359
- }
1494
+ var isVertical = /top|bottom/.test(placement)
1495
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1496
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
1360
1497
 
1361
- , destroy: function () {
1362
- this.hide().$element.off('.' + this.type).removeData(this.type)
1363
- }
1498
+ $tip.offset(offset)
1499
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
1500
+ }
1364
1501
 
1502
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
1503
+ this.arrow()
1504
+ .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
1505
+ .css(isHorizontal ? 'top' : 'left', '')
1365
1506
  }
1366
1507
 
1508
+ Tooltip.prototype.setContent = function () {
1509
+ var $tip = this.tip()
1510
+ var title = this.getTitle()
1367
1511
 
1368
- /* TOOLTIP PLUGIN DEFINITION
1369
- * ========================= */
1512
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
1513
+ $tip.removeClass('fade in top bottom left right')
1514
+ }
1370
1515
 
1371
- var old = $.fn.tooltip
1516
+ Tooltip.prototype.hide = function (callback) {
1517
+ var that = this
1518
+ var $tip = this.tip()
1519
+ var e = $.Event('hide.bs.' + this.type)
1372
1520
 
1373
- $.fn.tooltip = function ( option ) {
1374
- return this.each(function () {
1375
- var $this = $(this)
1376
- , data = $this.data('tooltip')
1377
- , options = typeof option == 'object' && option
1378
- if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
1379
- if (typeof option == 'string') data[option]()
1380
- })
1381
- }
1521
+ function complete() {
1522
+ if (that.hoverState != 'in') $tip.detach()
1523
+ that.$element
1524
+ .removeAttr('aria-describedby')
1525
+ .trigger('hidden.bs.' + that.type)
1526
+ callback && callback()
1527
+ }
1382
1528
 
1383
- $.fn.tooltip.Constructor = Tooltip
1529
+ this.$element.trigger(e)
1384
1530
 
1385
- $.fn.tooltip.defaults = {
1386
- animation: true
1387
- , placement: 'top'
1388
- , selector: false
1389
- , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
1390
- , trigger: 'hover focus'
1391
- , title: ''
1392
- , delay: 0
1393
- , html: false
1394
- , container: false
1395
- }
1531
+ if (e.isDefaultPrevented()) return
1532
+
1533
+ $tip.removeClass('in')
1396
1534
 
1535
+ $.support.transition && this.$tip.hasClass('fade') ?
1536
+ $tip
1537
+ .one('bsTransitionEnd', complete)
1538
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
1539
+ complete()
1397
1540
 
1398
- /* TOOLTIP NO CONFLICT
1399
- * =================== */
1541
+ this.hoverState = null
1400
1542
 
1401
- $.fn.tooltip.noConflict = function () {
1402
- $.fn.tooltip = old
1403
1543
  return this
1404
1544
  }
1405
1545
 
1406
- }(window.jQuery);
1407
- /* ===========================================================
1408
- * bootstrap-popover.js v2.3.1
1409
- * http://twitter.github.com/bootstrap/javascript.html#popovers
1410
- * ===========================================================
1411
- * Copyright 2012 Twitter, Inc.
1412
- *
1413
- * Licensed under the Apache License, Version 2.0 (the "License");
1414
- * you may not use this file except in compliance with the License.
1415
- * You may obtain a copy of the License at
1416
- *
1417
- * http://www.apache.org/licenses/LICENSE-2.0
1418
- *
1419
- * Unless required by applicable law or agreed to in writing, software
1420
- * distributed under the License is distributed on an "AS IS" BASIS,
1421
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1422
- * See the License for the specific language governing permissions and
1423
- * limitations under the License.
1424
- * =========================================================== */
1546
+ Tooltip.prototype.fixTitle = function () {
1547
+ var $e = this.$element
1548
+ if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
1549
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1550
+ }
1551
+ }
1425
1552
 
1553
+ Tooltip.prototype.hasContent = function () {
1554
+ return this.getTitle()
1555
+ }
1426
1556
 
1427
- !function ($) {
1557
+ Tooltip.prototype.getPosition = function ($element) {
1558
+ $element = $element || this.$element
1428
1559
 
1429
- "use strict"; // jshint ;_;
1560
+ var el = $element[0]
1561
+ var isBody = el.tagName == 'BODY'
1430
1562
 
1563
+ var elRect = el.getBoundingClientRect()
1564
+ if (elRect.width == null) {
1565
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
1566
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
1567
+ }
1568
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
1569
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
1570
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
1431
1571
 
1432
- /* POPOVER PUBLIC CLASS DEFINITION
1433
- * =============================== */
1572
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
1573
+ }
1574
+
1575
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
1576
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1577
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1578
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
1579
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
1434
1580
 
1435
- var Popover = function (element, options) {
1436
- this.init('popover', element, options)
1437
1581
  }
1438
1582
 
1583
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
1584
+ var delta = { top: 0, left: 0 }
1585
+ if (!this.$viewport) return delta
1439
1586
 
1440
- /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
1441
- ========================================== */
1587
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
1588
+ var viewportDimensions = this.getPosition(this.$viewport)
1442
1589
 
1443
- Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
1590
+ if (/right|left/.test(placement)) {
1591
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
1592
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
1593
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
1594
+ delta.top = viewportDimensions.top - topEdgeOffset
1595
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
1596
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
1597
+ }
1598
+ } else {
1599
+ var leftEdgeOffset = pos.left - viewportPadding
1600
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
1601
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
1602
+ delta.left = viewportDimensions.left - leftEdgeOffset
1603
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
1604
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
1605
+ }
1606
+ }
1444
1607
 
1445
- constructor: Popover
1608
+ return delta
1609
+ }
1446
1610
 
1447
- , setContent: function () {
1448
- var $tip = this.tip()
1449
- , title = this.getTitle()
1450
- , content = this.getContent()
1611
+ Tooltip.prototype.getTitle = function () {
1612
+ var title
1613
+ var $e = this.$element
1614
+ var o = this.options
1451
1615
 
1452
- $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1453
- $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
1616
+ title = $e.attr('data-original-title')
1617
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1454
1618
 
1455
- $tip.removeClass('fade top bottom left right in')
1456
- }
1619
+ return title
1620
+ }
1457
1621
 
1458
- , hasContent: function () {
1459
- return this.getTitle() || this.getContent()
1460
- }
1622
+ Tooltip.prototype.getUID = function (prefix) {
1623
+ do prefix += ~~(Math.random() * 1000000)
1624
+ while (document.getElementById(prefix))
1625
+ return prefix
1626
+ }
1461
1627
 
1462
- , getContent: function () {
1463
- var content
1464
- , $e = this.$element
1465
- , o = this.options
1628
+ Tooltip.prototype.tip = function () {
1629
+ return (this.$tip = this.$tip || $(this.options.template))
1630
+ }
1466
1631
 
1467
- content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
1468
- || $e.attr('data-content')
1632
+ Tooltip.prototype.arrow = function () {
1633
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
1634
+ }
1469
1635
 
1470
- return content
1471
- }
1636
+ Tooltip.prototype.enable = function () {
1637
+ this.enabled = true
1638
+ }
1472
1639
 
1473
- , tip: function () {
1474
- if (!this.$tip) {
1475
- this.$tip = $(this.options.template)
1476
- }
1477
- return this.$tip
1478
- }
1640
+ Tooltip.prototype.disable = function () {
1641
+ this.enabled = false
1642
+ }
1479
1643
 
1480
- , destroy: function () {
1481
- this.hide().$element.off('.' + this.type).removeData(this.type)
1644
+ Tooltip.prototype.toggleEnabled = function () {
1645
+ this.enabled = !this.enabled
1646
+ }
1647
+
1648
+ Tooltip.prototype.toggle = function (e) {
1649
+ var self = this
1650
+ if (e) {
1651
+ self = $(e.currentTarget).data('bs.' + this.type)
1652
+ if (!self) {
1653
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
1654
+ $(e.currentTarget).data('bs.' + this.type, self)
1655
+ }
1482
1656
  }
1483
1657
 
1484
- })
1658
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
1659
+ }
1485
1660
 
1661
+ Tooltip.prototype.destroy = function () {
1662
+ var that = this
1663
+ clearTimeout(this.timeout)
1664
+ this.hide(function () {
1665
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
1666
+ })
1667
+ }
1486
1668
 
1487
- /* POPOVER PLUGIN DEFINITION
1488
- * ======================= */
1489
1669
 
1490
- var old = $.fn.popover
1670
+ // TOOLTIP PLUGIN DEFINITION
1671
+ // =========================
1491
1672
 
1492
- $.fn.popover = function (option) {
1673
+ function Plugin(option) {
1493
1674
  return this.each(function () {
1494
- var $this = $(this)
1495
- , data = $this.data('popover')
1496
- , options = typeof option == 'object' && option
1497
- if (!data) $this.data('popover', (data = new Popover(this, options)))
1675
+ var $this = $(this)
1676
+ var data = $this.data('bs.tooltip')
1677
+ var options = typeof option == 'object' && option
1678
+
1679
+ if (!data && option == 'destroy') return
1680
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1498
1681
  if (typeof option == 'string') data[option]()
1499
1682
  })
1500
1683
  }
1501
1684
 
1502
- $.fn.popover.Constructor = Popover
1685
+ var old = $.fn.tooltip
1503
1686
 
1504
- $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
1505
- placement: 'right'
1506
- , trigger: 'click'
1507
- , content: ''
1508
- , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1509
- })
1687
+ $.fn.tooltip = Plugin
1688
+ $.fn.tooltip.Constructor = Tooltip
1510
1689
 
1511
1690
 
1512
- /* POPOVER NO CONFLICT
1513
- * =================== */
1691
+ // TOOLTIP NO CONFLICT
1692
+ // ===================
1514
1693
 
1515
- $.fn.popover.noConflict = function () {
1516
- $.fn.popover = old
1694
+ $.fn.tooltip.noConflict = function () {
1695
+ $.fn.tooltip = old
1517
1696
  return this
1518
1697
  }
1519
1698
 
1520
- }(window.jQuery);
1521
- /* =============================================================
1522
- * bootstrap-scrollspy.js v2.3.1
1523
- * http://twitter.github.com/bootstrap/javascript.html#scrollspy
1524
- * =============================================================
1525
- * Copyright 2012 Twitter, Inc.
1526
- *
1527
- * Licensed under the Apache License, Version 2.0 (the "License");
1528
- * you may not use this file except in compliance with the License.
1529
- * You may obtain a copy of the License at
1530
- *
1531
- * http://www.apache.org/licenses/LICENSE-2.0
1532
- *
1533
- * Unless required by applicable law or agreed to in writing, software
1534
- * distributed under the License is distributed on an "AS IS" BASIS,
1535
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1536
- * See the License for the specific language governing permissions and
1537
- * limitations under the License.
1538
- * ============================================================== */
1699
+ }(jQuery);
1539
1700
 
1701
+ /* ========================================================================
1702
+ * Bootstrap: popover.js v3.3.2
1703
+ * http://getbootstrap.com/javascript/#popovers
1704
+ * ========================================================================
1705
+ * Copyright 2011-2015 Twitter, Inc.
1706
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1707
+ * ======================================================================== */
1540
1708
 
1541
- !function ($) {
1542
1709
 
1543
- "use strict"; // jshint ;_;
1710
+ +function ($) {
1711
+ 'use strict';
1544
1712
 
1713
+ // POPOVER PUBLIC CLASS DEFINITION
1714
+ // ===============================
1545
1715
 
1546
- /* SCROLLSPY CLASS DEFINITION
1547
- * ========================== */
1548
-
1549
- function ScrollSpy(element, options) {
1550
- var process = $.proxy(this.process, this)
1551
- , $element = $(element).is('body') ? $(window) : $(element)
1552
- , href
1553
- this.options = $.extend({}, $.fn.scrollspy.defaults, options)
1554
- this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
1555
- this.selector = (this.options.target
1556
- || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
1557
- || '') + ' .nav li > a'
1558
- this.$body = $('body')
1559
- this.refresh()
1560
- this.process()
1716
+ var Popover = function (element, options) {
1717
+ this.init('popover', element, options)
1561
1718
  }
1562
1719
 
1563
- ScrollSpy.prototype = {
1720
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
1564
1721
 
1565
- constructor: ScrollSpy
1722
+ Popover.VERSION = '3.3.2'
1566
1723
 
1567
- , refresh: function () {
1568
- var self = this
1569
- , $targets
1724
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
1725
+ placement: 'right',
1726
+ trigger: 'click',
1727
+ content: '',
1728
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1729
+ })
1570
1730
 
1571
- this.offsets = $([])
1572
- this.targets = $([])
1573
1731
 
1574
- $targets = this.$body
1575
- .find(this.selector)
1576
- .map(function () {
1577
- var $el = $(this)
1578
- , href = $el.data('target') || $el.attr('href')
1579
- , $href = /^#\w/.test(href) && $(href)
1580
- return ( $href
1581
- && $href.length
1582
- && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
1583
- })
1584
- .sort(function (a, b) { return a[0] - b[0] })
1585
- .each(function () {
1586
- self.offsets.push(this[0])
1587
- self.targets.push(this[1])
1588
- })
1589
- }
1732
+ // NOTE: POPOVER EXTENDS tooltip.js
1733
+ // ================================
1590
1734
 
1591
- , process: function () {
1592
- var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1593
- , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
1594
- , maxScroll = scrollHeight - this.$scrollElement.height()
1595
- , offsets = this.offsets
1596
- , targets = this.targets
1597
- , activeTarget = this.activeTarget
1598
- , i
1599
-
1600
- if (scrollTop >= maxScroll) {
1601
- return activeTarget != (i = targets.last()[0])
1602
- && this.activate ( i )
1603
- }
1735
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1604
1736
 
1605
- for (i = offsets.length; i--;) {
1606
- activeTarget != targets[i]
1607
- && scrollTop >= offsets[i]
1608
- && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1609
- && this.activate( targets[i] )
1610
- }
1611
- }
1737
+ Popover.prototype.constructor = Popover
1612
1738
 
1613
- , activate: function (target) {
1614
- var active
1615
- , selector
1739
+ Popover.prototype.getDefaults = function () {
1740
+ return Popover.DEFAULTS
1741
+ }
1616
1742
 
1617
- this.activeTarget = target
1743
+ Popover.prototype.setContent = function () {
1744
+ var $tip = this.tip()
1745
+ var title = this.getTitle()
1746
+ var content = this.getContent()
1618
1747
 
1619
- $(this.selector)
1620
- .parent('.active')
1621
- .removeClass('active')
1748
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1749
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
1750
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
1751
+ ](content)
1622
1752
 
1623
- selector = this.selector
1624
- + '[data-target="' + target + '"],'
1625
- + this.selector + '[href="' + target + '"]'
1753
+ $tip.removeClass('fade top bottom left right in')
1626
1754
 
1627
- active = $(selector)
1628
- .parent('li')
1629
- .addClass('active')
1755
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
1756
+ // this manually by checking the contents.
1757
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
1758
+ }
1630
1759
 
1631
- if (active.parent('.dropdown-menu').length) {
1632
- active = active.closest('li.dropdown').addClass('active')
1633
- }
1760
+ Popover.prototype.hasContent = function () {
1761
+ return this.getTitle() || this.getContent()
1762
+ }
1634
1763
 
1635
- active.trigger('activate')
1636
- }
1764
+ Popover.prototype.getContent = function () {
1765
+ var $e = this.$element
1766
+ var o = this.options
1637
1767
 
1768
+ return $e.attr('data-content')
1769
+ || (typeof o.content == 'function' ?
1770
+ o.content.call($e[0]) :
1771
+ o.content)
1638
1772
  }
1639
1773
 
1774
+ Popover.prototype.arrow = function () {
1775
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
1776
+ }
1640
1777
 
1641
- /* SCROLLSPY PLUGIN DEFINITION
1642
- * =========================== */
1778
+ Popover.prototype.tip = function () {
1779
+ if (!this.$tip) this.$tip = $(this.options.template)
1780
+ return this.$tip
1781
+ }
1643
1782
 
1644
- var old = $.fn.scrollspy
1645
1783
 
1646
- $.fn.scrollspy = function (option) {
1784
+ // POPOVER PLUGIN DEFINITION
1785
+ // =========================
1786
+
1787
+ function Plugin(option) {
1647
1788
  return this.each(function () {
1648
- var $this = $(this)
1649
- , data = $this.data('scrollspy')
1650
- , options = typeof option == 'object' && option
1651
- if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
1789
+ var $this = $(this)
1790
+ var data = $this.data('bs.popover')
1791
+ var options = typeof option == 'object' && option
1792
+
1793
+ if (!data && option == 'destroy') return
1794
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
1652
1795
  if (typeof option == 'string') data[option]()
1653
1796
  })
1654
1797
  }
1655
1798
 
1656
- $.fn.scrollspy.Constructor = ScrollSpy
1799
+ var old = $.fn.popover
1657
1800
 
1658
- $.fn.scrollspy.defaults = {
1659
- offset: 10
1660
- }
1801
+ $.fn.popover = Plugin
1802
+ $.fn.popover.Constructor = Popover
1661
1803
 
1662
1804
 
1663
- /* SCROLLSPY NO CONFLICT
1664
- * ===================== */
1805
+ // POPOVER NO CONFLICT
1806
+ // ===================
1665
1807
 
1666
- $.fn.scrollspy.noConflict = function () {
1667
- $.fn.scrollspy = old
1808
+ $.fn.popover.noConflict = function () {
1809
+ $.fn.popover = old
1668
1810
  return this
1669
1811
  }
1670
1812
 
1813
+ }(jQuery);
1671
1814
 
1672
- /* SCROLLSPY DATA-API
1673
- * ================== */
1674
-
1675
- $(window).on('load', function () {
1676
- $('[data-spy="scroll"]').each(function () {
1677
- var $spy = $(this)
1678
- $spy.scrollspy($spy.data())
1679
- })
1680
- })
1681
-
1682
- }(window.jQuery);/* ========================================================
1683
- * bootstrap-tab.js v2.3.1
1684
- * http://twitter.github.com/bootstrap/javascript.html#tabs
1685
- * ========================================================
1686
- * Copyright 2012 Twitter, Inc.
1687
- *
1688
- * Licensed under the Apache License, Version 2.0 (the "License");
1689
- * you may not use this file except in compliance with the License.
1690
- * You may obtain a copy of the License at
1691
- *
1692
- * http://www.apache.org/licenses/LICENSE-2.0
1693
- *
1694
- * Unless required by applicable law or agreed to in writing, software
1695
- * distributed under the License is distributed on an "AS IS" BASIS,
1696
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1697
- * See the License for the specific language governing permissions and
1698
- * limitations under the License.
1699
- * ======================================================== */
1815
+ /* ========================================================================
1816
+ * Bootstrap: scrollspy.js v3.3.2
1817
+ * http://getbootstrap.com/javascript/#scrollspy
1818
+ * ========================================================================
1819
+ * Copyright 2011-2015 Twitter, Inc.
1820
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1821
+ * ======================================================================== */
1700
1822
 
1701
1823
 
1702
- !function ($) {
1824
+ +function ($) {
1825
+ 'use strict';
1703
1826
 
1704
- "use strict"; // jshint ;_;
1827
+ // SCROLLSPY CLASS DEFINITION
1828
+ // ==========================
1705
1829
 
1830
+ function ScrollSpy(element, options) {
1831
+ var process = $.proxy(this.process, this)
1832
+
1833
+ this.$body = $('body')
1834
+ this.$scrollElement = $(element).is('body') ? $(window) : $(element)
1835
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
1836
+ this.selector = (this.options.target || '') + ' .nav li > a'
1837
+ this.offsets = []
1838
+ this.targets = []
1839
+ this.activeTarget = null
1840
+ this.scrollHeight = 0
1841
+
1842
+ this.$scrollElement.on('scroll.bs.scrollspy', process)
1843
+ this.refresh()
1844
+ this.process()
1845
+ }
1706
1846
 
1707
- /* TAB CLASS DEFINITION
1708
- * ==================== */
1847
+ ScrollSpy.VERSION = '3.3.2'
1709
1848
 
1710
- var Tab = function (element) {
1711
- this.element = $(element)
1849
+ ScrollSpy.DEFAULTS = {
1850
+ offset: 10
1712
1851
  }
1713
1852
 
1714
- Tab.prototype = {
1853
+ ScrollSpy.prototype.getScrollHeight = function () {
1854
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
1855
+ }
1715
1856
 
1716
- constructor: Tab
1857
+ ScrollSpy.prototype.refresh = function () {
1858
+ var offsetMethod = 'offset'
1859
+ var offsetBase = 0
1717
1860
 
1718
- , show: function () {
1719
- var $this = this.element
1720
- , $ul = $this.closest('ul:not(.dropdown-menu)')
1721
- , selector = $this.attr('data-target')
1722
- , previous
1723
- , $target
1724
- , e
1861
+ if (!$.isWindow(this.$scrollElement[0])) {
1862
+ offsetMethod = 'position'
1863
+ offsetBase = this.$scrollElement.scrollTop()
1864
+ }
1725
1865
 
1726
- if (!selector) {
1727
- selector = $this.attr('href')
1728
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
1729
- }
1866
+ this.offsets = []
1867
+ this.targets = []
1868
+ this.scrollHeight = this.getScrollHeight()
1730
1869
 
1731
- if ( $this.parent('li').hasClass('active') ) return
1870
+ var self = this
1732
1871
 
1733
- previous = $ul.find('.active:last a')[0]
1872
+ this.$body
1873
+ .find(this.selector)
1874
+ .map(function () {
1875
+ var $el = $(this)
1876
+ var href = $el.data('target') || $el.attr('href')
1877
+ var $href = /^#./.test(href) && $(href)
1734
1878
 
1735
- e = $.Event('show', {
1736
- relatedTarget: previous
1879
+ return ($href
1880
+ && $href.length
1881
+ && $href.is(':visible')
1882
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
1737
1883
  })
1884
+ .sort(function (a, b) { return a[0] - b[0] })
1885
+ .each(function () {
1886
+ self.offsets.push(this[0])
1887
+ self.targets.push(this[1])
1888
+ })
1889
+ }
1738
1890
 
1739
- $this.trigger(e)
1740
-
1741
- if (e.isDefaultPrevented()) return
1742
-
1743
- $target = $(selector)
1891
+ ScrollSpy.prototype.process = function () {
1892
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1893
+ var scrollHeight = this.getScrollHeight()
1894
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
1895
+ var offsets = this.offsets
1896
+ var targets = this.targets
1897
+ var activeTarget = this.activeTarget
1898
+ var i
1744
1899
 
1745
- this.activate($this.parent('li'), $ul)
1746
- this.activate($target, $target.parent(), function () {
1747
- $this.trigger({
1748
- type: 'shown'
1749
- , relatedTarget: previous
1750
- })
1751
- })
1900
+ if (this.scrollHeight != scrollHeight) {
1901
+ this.refresh()
1752
1902
  }
1753
1903
 
1754
- , activate: function ( element, container, callback) {
1755
- var $active = container.find('> .active')
1756
- , transition = callback
1757
- && $.support.transition
1758
- && $active.hasClass('fade')
1904
+ if (scrollTop >= maxScroll) {
1905
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
1906
+ }
1759
1907
 
1760
- function next() {
1761
- $active
1762
- .removeClass('active')
1763
- .find('> .dropdown-menu > .active')
1764
- .removeClass('active')
1908
+ if (activeTarget && scrollTop < offsets[0]) {
1909
+ this.activeTarget = null
1910
+ return this.clear()
1911
+ }
1765
1912
 
1766
- element.addClass('active')
1913
+ for (i = offsets.length; i--;) {
1914
+ activeTarget != targets[i]
1915
+ && scrollTop >= offsets[i]
1916
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1917
+ && this.activate(targets[i])
1918
+ }
1919
+ }
1767
1920
 
1768
- if (transition) {
1769
- element[0].offsetWidth // reflow for transition
1770
- element.addClass('in')
1771
- } else {
1772
- element.removeClass('fade')
1773
- }
1921
+ ScrollSpy.prototype.activate = function (target) {
1922
+ this.activeTarget = target
1774
1923
 
1775
- if ( element.parent('.dropdown-menu') ) {
1776
- element.closest('li.dropdown').addClass('active')
1777
- }
1924
+ this.clear()
1778
1925
 
1779
- callback && callback()
1780
- }
1926
+ var selector = this.selector +
1927
+ '[data-target="' + target + '"],' +
1928
+ this.selector + '[href="' + target + '"]'
1781
1929
 
1782
- transition ?
1783
- $active.one($.support.transition.end, next) :
1784
- next()
1930
+ var active = $(selector)
1931
+ .parents('li')
1932
+ .addClass('active')
1785
1933
 
1786
- $active.removeClass('in')
1934
+ if (active.parent('.dropdown-menu').length) {
1935
+ active = active
1936
+ .closest('li.dropdown')
1937
+ .addClass('active')
1787
1938
  }
1939
+
1940
+ active.trigger('activate.bs.scrollspy')
1788
1941
  }
1789
1942
 
1943
+ ScrollSpy.prototype.clear = function () {
1944
+ $(this.selector)
1945
+ .parentsUntil(this.options.target, '.active')
1946
+ .removeClass('active')
1947
+ }
1790
1948
 
1791
- /* TAB PLUGIN DEFINITION
1792
- * ===================== */
1793
1949
 
1794
- var old = $.fn.tab
1950
+ // SCROLLSPY PLUGIN DEFINITION
1951
+ // ===========================
1795
1952
 
1796
- $.fn.tab = function ( option ) {
1953
+ function Plugin(option) {
1797
1954
  return this.each(function () {
1798
- var $this = $(this)
1799
- , data = $this.data('tab')
1800
- if (!data) $this.data('tab', (data = new Tab(this)))
1955
+ var $this = $(this)
1956
+ var data = $this.data('bs.scrollspy')
1957
+ var options = typeof option == 'object' && option
1958
+
1959
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
1801
1960
  if (typeof option == 'string') data[option]()
1802
1961
  })
1803
1962
  }
1804
1963
 
1805
- $.fn.tab.Constructor = Tab
1964
+ var old = $.fn.scrollspy
1806
1965
 
1966
+ $.fn.scrollspy = Plugin
1967
+ $.fn.scrollspy.Constructor = ScrollSpy
1807
1968
 
1808
- /* TAB NO CONFLICT
1809
- * =============== */
1810
1969
 
1811
- $.fn.tab.noConflict = function () {
1812
- $.fn.tab = old
1970
+ // SCROLLSPY NO CONFLICT
1971
+ // =====================
1972
+
1973
+ $.fn.scrollspy.noConflict = function () {
1974
+ $.fn.scrollspy = old
1813
1975
  return this
1814
1976
  }
1815
1977
 
1816
1978
 
1817
- /* TAB DATA-API
1818
- * ============ */
1979
+ // SCROLLSPY DATA-API
1980
+ // ==================
1819
1981
 
1820
- $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1821
- e.preventDefault()
1822
- $(this).tab('show')
1982
+ $(window).on('load.bs.scrollspy.data-api', function () {
1983
+ $('[data-spy="scroll"]').each(function () {
1984
+ var $spy = $(this)
1985
+ Plugin.call($spy, $spy.data())
1986
+ })
1823
1987
  })
1824
1988
 
1825
- }(window.jQuery);/* =============================================================
1826
- * bootstrap-typeahead.js v2.3.1
1827
- * http://twitter.github.com/bootstrap/javascript.html#typeahead
1828
- * =============================================================
1829
- * Copyright 2012 Twitter, Inc.
1830
- *
1831
- * Licensed under the Apache License, Version 2.0 (the "License");
1832
- * you may not use this file except in compliance with the License.
1833
- * You may obtain a copy of the License at
1834
- *
1835
- * http://www.apache.org/licenses/LICENSE-2.0
1836
- *
1837
- * Unless required by applicable law or agreed to in writing, software
1838
- * distributed under the License is distributed on an "AS IS" BASIS,
1839
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1840
- * See the License for the specific language governing permissions and
1841
- * limitations under the License.
1842
- * ============================================================ */
1843
-
1844
-
1845
- !function($){
1846
-
1847
- "use strict"; // jshint ;_;
1848
-
1849
-
1850
- /* TYPEAHEAD PUBLIC CLASS DEFINITION
1851
- * ================================= */
1852
-
1853
- var Typeahead = function (element, options) {
1854
- this.$element = $(element)
1855
- this.options = $.extend({}, $.fn.typeahead.defaults, options)
1856
- this.matcher = this.options.matcher || this.matcher
1857
- this.sorter = this.options.sorter || this.sorter
1858
- this.highlighter = this.options.highlighter || this.highlighter
1859
- this.updater = this.options.updater || this.updater
1860
- this.source = this.options.source
1861
- this.$menu = $(this.options.menu)
1862
- this.shown = false
1863
- this.listen()
1864
- }
1865
-
1866
- Typeahead.prototype = {
1867
-
1868
- constructor: Typeahead
1869
-
1870
- , select: function () {
1871
- var val = this.$menu.find('.active').attr('data-value')
1872
- this.$element
1873
- .val(this.updater(val))
1874
- .change()
1875
- return this.hide()
1876
- }
1877
-
1878
- , updater: function (item) {
1879
- return item
1880
- }
1989
+ }(jQuery);
1881
1990
 
1882
- , show: function () {
1883
- var pos = $.extend({}, this.$element.position(), {
1884
- height: this.$element[0].offsetHeight
1885
- })
1991
+ /* ========================================================================
1992
+ * Bootstrap: tab.js v3.3.2
1993
+ * http://getbootstrap.com/javascript/#tabs
1994
+ * ========================================================================
1995
+ * Copyright 2011-2015 Twitter, Inc.
1996
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1997
+ * ======================================================================== */
1886
1998
 
1887
- this.$menu
1888
- .insertAfter(this.$element)
1889
- .css({
1890
- top: pos.top + pos.height
1891
- , left: pos.left
1892
- })
1893
- .show()
1894
1999
 
1895
- this.shown = true
1896
- return this
1897
- }
2000
+ +function ($) {
2001
+ 'use strict';
1898
2002
 
1899
- , hide: function () {
1900
- this.$menu.hide()
1901
- this.shown = false
1902
- return this
1903
- }
2003
+ // TAB CLASS DEFINITION
2004
+ // ====================
1904
2005
 
1905
- , lookup: function (event) {
1906
- var items
2006
+ var Tab = function (element) {
2007
+ this.element = $(element)
2008
+ }
1907
2009
 
1908
- this.query = this.$element.val()
2010
+ Tab.VERSION = '3.3.2'
1909
2011
 
1910
- if (!this.query || this.query.length < this.options.minLength) {
1911
- return this.shown ? this.hide() : this
1912
- }
2012
+ Tab.TRANSITION_DURATION = 150
1913
2013
 
1914
- items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
2014
+ Tab.prototype.show = function () {
2015
+ var $this = this.element
2016
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
2017
+ var selector = $this.data('target')
1915
2018
 
1916
- return items ? this.process(items) : this
2019
+ if (!selector) {
2020
+ selector = $this.attr('href')
2021
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
1917
2022
  }
1918
2023
 
1919
- , process: function (items) {
1920
- var that = this
1921
-
1922
- items = $.grep(items, function (item) {
1923
- return that.matcher(item)
1924
- })
1925
-
1926
- items = this.sorter(items)
1927
-
1928
- if (!items.length) {
1929
- return this.shown ? this.hide() : this
1930
- }
1931
-
1932
- return this.render(items.slice(0, this.options.items)).show()
1933
- }
2024
+ if ($this.parent('li').hasClass('active')) return
1934
2025
 
1935
- , matcher: function (item) {
1936
- return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1937
- }
2026
+ var $previous = $ul.find('.active:last a')
2027
+ var hideEvent = $.Event('hide.bs.tab', {
2028
+ relatedTarget: $this[0]
2029
+ })
2030
+ var showEvent = $.Event('show.bs.tab', {
2031
+ relatedTarget: $previous[0]
2032
+ })
1938
2033
 
1939
- , sorter: function (items) {
1940
- var beginswith = []
1941
- , caseSensitive = []
1942
- , caseInsensitive = []
1943
- , item
2034
+ $previous.trigger(hideEvent)
2035
+ $this.trigger(showEvent)
1944
2036
 
1945
- while (item = items.shift()) {
1946
- if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1947
- else if (~item.indexOf(this.query)) caseSensitive.push(item)
1948
- else caseInsensitive.push(item)
1949
- }
2037
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
1950
2038
 
1951
- return beginswith.concat(caseSensitive, caseInsensitive)
1952
- }
2039
+ var $target = $(selector)
1953
2040
 
1954
- , highlighter: function (item) {
1955
- var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1956
- return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1957
- return '<strong>' + match + '</strong>'
2041
+ this.activate($this.closest('li'), $ul)
2042
+ this.activate($target, $target.parent(), function () {
2043
+ $previous.trigger({
2044
+ type: 'hidden.bs.tab',
2045
+ relatedTarget: $this[0]
1958
2046
  })
1959
- }
1960
-
1961
- , render: function (items) {
1962
- var that = this
1963
-
1964
- items = $(items).map(function (i, item) {
1965
- i = $(that.options.item).attr('data-value', item)
1966
- i.find('a').html(that.highlighter(item))
1967
- return i[0]
2047
+ $this.trigger({
2048
+ type: 'shown.bs.tab',
2049
+ relatedTarget: $previous[0]
1968
2050
  })
2051
+ })
2052
+ }
1969
2053
 
1970
- items.first().addClass('active')
1971
- this.$menu.html(items)
1972
- return this
1973
- }
2054
+ Tab.prototype.activate = function (element, container, callback) {
2055
+ var $active = container.find('> .active')
2056
+ var transition = callback
2057
+ && $.support.transition
2058
+ && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
1974
2059
 
1975
- , next: function (event) {
1976
- var active = this.$menu.find('.active').removeClass('active')
1977
- , next = active.next()
2060
+ function next() {
2061
+ $active
2062
+ .removeClass('active')
2063
+ .find('> .dropdown-menu > .active')
2064
+ .removeClass('active')
2065
+ .end()
2066
+ .find('[data-toggle="tab"]')
2067
+ .attr('aria-expanded', false)
2068
+
2069
+ element
2070
+ .addClass('active')
2071
+ .find('[data-toggle="tab"]')
2072
+ .attr('aria-expanded', true)
2073
+
2074
+ if (transition) {
2075
+ element[0].offsetWidth // reflow for transition
2076
+ element.addClass('in')
2077
+ } else {
2078
+ element.removeClass('fade')
2079
+ }
1978
2080
 
1979
- if (!next.length) {
1980
- next = $(this.$menu.find('li')[0])
2081
+ if (element.parent('.dropdown-menu')) {
2082
+ element
2083
+ .closest('li.dropdown')
2084
+ .addClass('active')
2085
+ .end()
2086
+ .find('[data-toggle="tab"]')
2087
+ .attr('aria-expanded', true)
1981
2088
  }
1982
2089
 
1983
- next.addClass('active')
2090
+ callback && callback()
1984
2091
  }
1985
2092
 
1986
- , prev: function (event) {
1987
- var active = this.$menu.find('.active').removeClass('active')
1988
- , prev = active.prev()
2093
+ $active.length && transition ?
2094
+ $active
2095
+ .one('bsTransitionEnd', next)
2096
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
2097
+ next()
1989
2098
 
1990
- if (!prev.length) {
1991
- prev = this.$menu.find('li').last()
1992
- }
2099
+ $active.removeClass('in')
2100
+ }
1993
2101
 
1994
- prev.addClass('active')
1995
- }
1996
2102
 
1997
- , listen: function () {
1998
- this.$element
1999
- .on('focus', $.proxy(this.focus, this))
2000
- .on('blur', $.proxy(this.blur, this))
2001
- .on('keypress', $.proxy(this.keypress, this))
2002
- .on('keyup', $.proxy(this.keyup, this))
2103
+ // TAB PLUGIN DEFINITION
2104
+ // =====================
2003
2105
 
2004
- if (this.eventSupported('keydown')) {
2005
- this.$element.on('keydown', $.proxy(this.keydown, this))
2006
- }
2106
+ function Plugin(option) {
2107
+ return this.each(function () {
2108
+ var $this = $(this)
2109
+ var data = $this.data('bs.tab')
2007
2110
 
2008
- this.$menu
2009
- .on('click', $.proxy(this.click, this))
2010
- .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
2011
- .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
2012
- }
2111
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
2112
+ if (typeof option == 'string') data[option]()
2113
+ })
2114
+ }
2013
2115
 
2014
- , eventSupported: function(eventName) {
2015
- var isSupported = eventName in this.$element
2016
- if (!isSupported) {
2017
- this.$element.setAttribute(eventName, 'return;')
2018
- isSupported = typeof this.$element[eventName] === 'function'
2019
- }
2020
- return isSupported
2021
- }
2116
+ var old = $.fn.tab
2022
2117
 
2023
- , move: function (e) {
2024
- if (!this.shown) return
2025
-
2026
- switch(e.keyCode) {
2027
- case 9: // tab
2028
- case 13: // enter
2029
- case 27: // escape
2030
- e.preventDefault()
2031
- break
2032
-
2033
- case 38: // up arrow
2034
- e.preventDefault()
2035
- this.prev()
2036
- break
2037
-
2038
- case 40: // down arrow
2039
- e.preventDefault()
2040
- this.next()
2041
- break
2042
- }
2118
+ $.fn.tab = Plugin
2119
+ $.fn.tab.Constructor = Tab
2043
2120
 
2044
- e.stopPropagation()
2045
- }
2046
2121
 
2047
- , keydown: function (e) {
2048
- this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
2049
- this.move(e)
2050
- }
2122
+ // TAB NO CONFLICT
2123
+ // ===============
2051
2124
 
2052
- , keypress: function (e) {
2053
- if (this.suppressKeyPressRepeat) return
2054
- this.move(e)
2055
- }
2125
+ $.fn.tab.noConflict = function () {
2126
+ $.fn.tab = old
2127
+ return this
2128
+ }
2056
2129
 
2057
- , keyup: function (e) {
2058
- switch(e.keyCode) {
2059
- case 40: // down arrow
2060
- case 38: // up arrow
2061
- case 16: // shift
2062
- case 17: // ctrl
2063
- case 18: // alt
2064
- break
2065
-
2066
- case 9: // tab
2067
- case 13: // enter
2068
- if (!this.shown) return
2069
- this.select()
2070
- break
2071
-
2072
- case 27: // escape
2073
- if (!this.shown) return
2074
- this.hide()
2075
- break
2076
-
2077
- default:
2078
- this.lookup()
2079
- }
2080
2130
 
2081
- e.stopPropagation()
2082
- e.preventDefault()
2131
+ // TAB DATA-API
2132
+ // ============
2133
+
2134
+ var clickHandler = function (e) {
2135
+ e.preventDefault()
2136
+ Plugin.call($(this), 'show')
2083
2137
  }
2084
2138
 
2085
- , focus: function (e) {
2086
- this.focused = true
2087
- }
2139
+ $(document)
2140
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
2141
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
2088
2142
 
2089
- , blur: function (e) {
2090
- this.focused = false
2091
- if (!this.mousedover && this.shown) this.hide()
2092
- }
2143
+ }(jQuery);
2093
2144
 
2094
- , click: function (e) {
2095
- e.stopPropagation()
2096
- e.preventDefault()
2097
- this.select()
2098
- this.$element.focus()
2099
- }
2145
+ /* ========================================================================
2146
+ * Bootstrap: affix.js v3.3.2
2147
+ * http://getbootstrap.com/javascript/#affix
2148
+ * ========================================================================
2149
+ * Copyright 2011-2015 Twitter, Inc.
2150
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2151
+ * ======================================================================== */
2100
2152
 
2101
- , mouseenter: function (e) {
2102
- this.mousedover = true
2103
- this.$menu.find('.active').removeClass('active')
2104
- $(e.currentTarget).addClass('active')
2105
- }
2106
2153
 
2107
- , mouseleave: function (e) {
2108
- this.mousedover = false
2109
- if (!this.focused && this.shown) this.hide()
2110
- }
2111
-
2112
- }
2154
+ +function ($) {
2155
+ 'use strict';
2113
2156
 
2157
+ // AFFIX CLASS DEFINITION
2158
+ // ======================
2114
2159
 
2115
- /* TYPEAHEAD PLUGIN DEFINITION
2116
- * =========================== */
2160
+ var Affix = function (element, options) {
2161
+ this.options = $.extend({}, Affix.DEFAULTS, options)
2117
2162
 
2118
- var old = $.fn.typeahead
2163
+ this.$target = $(this.options.target)
2164
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
2165
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
2119
2166
 
2120
- $.fn.typeahead = function (option) {
2121
- return this.each(function () {
2122
- var $this = $(this)
2123
- , data = $this.data('typeahead')
2124
- , options = typeof option == 'object' && option
2125
- if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
2126
- if (typeof option == 'string') data[option]()
2127
- })
2128
- }
2167
+ this.$element = $(element)
2168
+ this.affixed =
2169
+ this.unpin =
2170
+ this.pinnedOffset = null
2129
2171
 
2130
- $.fn.typeahead.defaults = {
2131
- source: []
2132
- , items: 8
2133
- , menu: '<ul class="typeahead dropdown-menu"></ul>'
2134
- , item: '<li><a href="#"></a></li>'
2135
- , minLength: 1
2172
+ this.checkPosition()
2136
2173
  }
2137
2174
 
2138
- $.fn.typeahead.Constructor = Typeahead
2139
-
2175
+ Affix.VERSION = '3.3.2'
2140
2176
 
2141
- /* TYPEAHEAD NO CONFLICT
2142
- * =================== */
2177
+ Affix.RESET = 'affix affix-top affix-bottom'
2143
2178
 
2144
- $.fn.typeahead.noConflict = function () {
2145
- $.fn.typeahead = old
2146
- return this
2179
+ Affix.DEFAULTS = {
2180
+ offset: 0,
2181
+ target: window
2147
2182
  }
2148
2183
 
2184
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
2185
+ var scrollTop = this.$target.scrollTop()
2186
+ var position = this.$element.offset()
2187
+ var targetHeight = this.$target.height()
2149
2188
 
2150
- /* TYPEAHEAD DATA-API
2151
- * ================== */
2152
-
2153
- $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
2154
- var $this = $(this)
2155
- if ($this.data('typeahead')) return
2156
- $this.typeahead($this.data())
2157
- })
2158
-
2159
- }(window.jQuery);
2160
- /* ==========================================================
2161
- * bootstrap-affix.js v2.3.1
2162
- * http://twitter.github.com/bootstrap/javascript.html#affix
2163
- * ==========================================================
2164
- * Copyright 2012 Twitter, Inc.
2165
- *
2166
- * Licensed under the Apache License, Version 2.0 (the "License");
2167
- * you may not use this file except in compliance with the License.
2168
- * You may obtain a copy of the License at
2169
- *
2170
- * http://www.apache.org/licenses/LICENSE-2.0
2171
- *
2172
- * Unless required by applicable law or agreed to in writing, software
2173
- * distributed under the License is distributed on an "AS IS" BASIS,
2174
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2175
- * See the License for the specific language governing permissions and
2176
- * limitations under the License.
2177
- * ========================================================== */
2189
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
2178
2190
 
2191
+ if (this.affixed == 'bottom') {
2192
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
2193
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
2194
+ }
2179
2195
 
2180
- !function ($) {
2196
+ var initializing = this.affixed == null
2197
+ var colliderTop = initializing ? scrollTop : position.top
2198
+ var colliderHeight = initializing ? targetHeight : height
2181
2199
 
2182
- "use strict"; // jshint ;_;
2200
+ if (offsetTop != null && scrollTop <= offsetTop) return 'top'
2201
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
2183
2202
 
2203
+ return false
2204
+ }
2184
2205
 
2185
- /* AFFIX CLASS DEFINITION
2186
- * ====================== */
2206
+ Affix.prototype.getPinnedOffset = function () {
2207
+ if (this.pinnedOffset) return this.pinnedOffset
2208
+ this.$element.removeClass(Affix.RESET).addClass('affix')
2209
+ var scrollTop = this.$target.scrollTop()
2210
+ var position = this.$element.offset()
2211
+ return (this.pinnedOffset = position.top - scrollTop)
2212
+ }
2187
2213
 
2188
- var Affix = function (element, options) {
2189
- this.options = $.extend({}, $.fn.affix.defaults, options)
2190
- this.$window = $(window)
2191
- .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
2192
- .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
2193
- this.$element = $(element)
2194
- this.checkPosition()
2214
+ Affix.prototype.checkPositionWithEventLoop = function () {
2215
+ setTimeout($.proxy(this.checkPosition, this), 1)
2195
2216
  }
2196
2217
 
2197
2218
  Affix.prototype.checkPosition = function () {
2198
2219
  if (!this.$element.is(':visible')) return
2199
2220
 
2200
- var scrollHeight = $(document).height()
2201
- , scrollTop = this.$window.scrollTop()
2202
- , position = this.$element.offset()
2203
- , offset = this.options.offset
2204
- , offsetBottom = offset.bottom
2205
- , offsetTop = offset.top
2206
- , reset = 'affix affix-top affix-bottom'
2207
- , affix
2221
+ var height = this.$element.height()
2222
+ var offset = this.options.offset
2223
+ var offsetTop = offset.top
2224
+ var offsetBottom = offset.bottom
2225
+ var scrollHeight = $('body').height()
2208
2226
 
2209
- if (typeof offset != 'object') offsetBottom = offsetTop = offset
2210
- if (typeof offsetTop == 'function') offsetTop = offset.top()
2211
- if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
2227
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
2228
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
2229
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
2212
2230
 
2213
- affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
2214
- false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
2215
- 'bottom' : offsetTop != null && scrollTop <= offsetTop ?
2216
- 'top' : false
2231
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
2217
2232
 
2218
- if (this.affixed === affix) return
2233
+ if (this.affixed != affix) {
2234
+ if (this.unpin != null) this.$element.css('top', '')
2219
2235
 
2220
- this.affixed = affix
2221
- this.unpin = affix == 'bottom' ? position.top - scrollTop : null
2236
+ var affixType = 'affix' + (affix ? '-' + affix : '')
2237
+ var e = $.Event(affixType + '.bs.affix')
2222
2238
 
2223
- this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
2224
- }
2239
+ this.$element.trigger(e)
2225
2240
 
2241
+ if (e.isDefaultPrevented()) return
2226
2242
 
2227
- /* AFFIX PLUGIN DEFINITION
2228
- * ======================= */
2243
+ this.affixed = affix
2244
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
2229
2245
 
2230
- var old = $.fn.affix
2246
+ this.$element
2247
+ .removeClass(Affix.RESET)
2248
+ .addClass(affixType)
2249
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
2250
+ }
2251
+
2252
+ if (affix == 'bottom') {
2253
+ this.$element.offset({
2254
+ top: scrollHeight - height - offsetBottom
2255
+ })
2256
+ }
2257
+ }
2231
2258
 
2232
- $.fn.affix = function (option) {
2259
+
2260
+ // AFFIX PLUGIN DEFINITION
2261
+ // =======================
2262
+
2263
+ function Plugin(option) {
2233
2264
  return this.each(function () {
2234
- var $this = $(this)
2235
- , data = $this.data('affix')
2236
- , options = typeof option == 'object' && option
2237
- if (!data) $this.data('affix', (data = new Affix(this, options)))
2265
+ var $this = $(this)
2266
+ var data = $this.data('bs.affix')
2267
+ var options = typeof option == 'object' && option
2268
+
2269
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
2238
2270
  if (typeof option == 'string') data[option]()
2239
2271
  })
2240
2272
  }
2241
2273
 
2242
- $.fn.affix.Constructor = Affix
2274
+ var old = $.fn.affix
2243
2275
 
2244
- $.fn.affix.defaults = {
2245
- offset: 0
2246
- }
2276
+ $.fn.affix = Plugin
2277
+ $.fn.affix.Constructor = Affix
2247
2278
 
2248
2279
 
2249
- /* AFFIX NO CONFLICT
2250
- * ================= */
2280
+ // AFFIX NO CONFLICT
2281
+ // =================
2251
2282
 
2252
2283
  $.fn.affix.noConflict = function () {
2253
2284
  $.fn.affix = old
@@ -2255,22 +2286,21 @@
2255
2286
  }
2256
2287
 
2257
2288
 
2258
- /* AFFIX DATA-API
2259
- * ============== */
2289
+ // AFFIX DATA-API
2290
+ // ==============
2260
2291
 
2261
2292
  $(window).on('load', function () {
2262
2293
  $('[data-spy="affix"]').each(function () {
2263
2294
  var $spy = $(this)
2264
- , data = $spy.data()
2295
+ var data = $spy.data()
2265
2296
 
2266
2297
  data.offset = data.offset || {}
2267
2298
 
2268
- data.offsetBottom && (data.offset.bottom = data.offsetBottom)
2269
- data.offsetTop && (data.offset.top = data.offsetTop)
2299
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
2300
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
2270
2301
 
2271
- $spy.affix(data)
2302
+ Plugin.call($spy, data)
2272
2303
  })
2273
2304
  })
2274
2305
 
2275
-
2276
- }(window.jQuery);
2306
+ }(jQuery);