surveillance 0.1.1

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 (276) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +42 -0
  4. data/Rakefile +23 -0
  5. data/app/assets/javascripts/surveillance.js +6 -0
  6. data/app/assets/javascripts/surveillance/admin.coffee +4 -0
  7. data/app/assets/javascripts/surveillance/admin/matrix-questions.coffee +18 -0
  8. data/app/assets/javascripts/surveillance/application.js +17 -0
  9. data/app/assets/javascripts/surveillance/collections/branch_rule_collection.coffee +2 -0
  10. data/app/assets/javascripts/surveillance/form.coffee +7 -0
  11. data/app/assets/javascripts/surveillance/manifest.coffee +7 -0
  12. data/app/assets/javascripts/surveillance/models/branch_rule.coffee +21 -0
  13. data/app/assets/javascripts/surveillance/models/question.coffee +19 -0
  14. data/app/assets/javascripts/surveillance/models/questions/choosable_question.coffee +15 -0
  15. data/app/assets/javascripts/surveillance/models/questions/matrix.coffee +19 -0
  16. data/app/assets/javascripts/surveillance/models/questions/matrix_question.coffee +7 -0
  17. data/app/assets/javascripts/surveillance/models/questions/number.coffee +17 -0
  18. data/app/assets/javascripts/surveillance/vendor/backbone.min.js +1 -0
  19. data/app/assets/javascripts/surveillance/vendor/bootstrap.js +2118 -0
  20. data/app/assets/javascripts/surveillance/vendor/jquery-ui-sortable.js +2256 -0
  21. data/app/assets/javascripts/surveillance/vendor/jquery.scrollto.js +210 -0
  22. data/app/assets/javascripts/surveillance/vendor/underscore.min.js +5 -0
  23. data/app/assets/javascripts/surveillance/views/attempt_view.coffee +74 -0
  24. data/app/assets/javascripts/surveillance/views/question_view.coffee +53 -0
  25. data/app/assets/javascripts/surveillance/views/questions/choice_view.coffee +52 -0
  26. data/app/assets/javascripts/surveillance/views/questions/matrix_question_view.coffee +26 -0
  27. data/app/assets/javascripts/surveillance/views/questions/matrix_view.coffee +21 -0
  28. data/app/assets/javascripts/surveillance/views/questions/number_view.coffee +19 -0
  29. data/app/assets/javascripts/surveillance/views/questions/order.coffee +9 -0
  30. data/app/assets/javascripts/surveillance/views/questions/select_matrix_view.coffee +31 -0
  31. data/app/assets/javascripts/surveillance/views/section_view.coffee +54 -0
  32. data/app/assets/stylesheets/surveillance/admin.sass +1 -0
  33. data/app/assets/stylesheets/surveillance/application.css +14 -0
  34. data/app/assets/stylesheets/surveillance/fonts/glyphicons-halflings-regular.eot +0 -0
  35. data/app/assets/stylesheets/surveillance/fonts/glyphicons-halflings-regular.svg +229 -0
  36. data/app/assets/stylesheets/surveillance/fonts/glyphicons-halflings-regular.ttf +0 -0
  37. data/app/assets/stylesheets/surveillance/fonts/glyphicons-halflings-regular.woff +0 -0
  38. data/app/assets/stylesheets/surveillance/overrides.sass +2 -0
  39. data/app/assets/stylesheets/surveillance/vendor/bootstrap.css +6175 -0
  40. data/app/controllers/concerns/surveillance/attempts_management_concern.rb +51 -0
  41. data/app/controllers/concerns/surveillance/base_controller_concern.rb +37 -0
  42. data/app/controllers/surveillance/admin/attempts_controller.rb +38 -0
  43. data/app/controllers/surveillance/admin/base_controller.rb +15 -0
  44. data/app/controllers/surveillance/admin/exports_controller.rb +24 -0
  45. data/app/controllers/surveillance/admin/options_controller.rb +44 -0
  46. data/app/controllers/surveillance/admin/questions_controller.rb +59 -0
  47. data/app/controllers/surveillance/admin/sections_controller.rb +46 -0
  48. data/app/controllers/surveillance/admin/surveys_controller.rb +43 -0
  49. data/app/controllers/surveillance/application_controller.rb +7 -0
  50. data/app/controllers/surveillance/response/attempts_controller.rb +50 -0
  51. data/app/controllers/surveillance/response/base_controller.rb +38 -0
  52. data/app/controllers/surveillance/response/partial_attempts_controller.rb +15 -0
  53. data/app/controllers/surveillance/surveys_controller.rb +6 -0
  54. data/app/helpers/surveillance/admin/exports_helper.rb +37 -0
  55. data/app/helpers/surveillance/application_helper.rb +84 -0
  56. data/app/models/surveillance/answer.rb +56 -0
  57. data/app/models/surveillance/answer_content.rb +7 -0
  58. data/app/models/surveillance/attempt.rb +146 -0
  59. data/app/models/surveillance/branch_rule.rb +52 -0
  60. data/app/models/surveillance/field_setting.rb +6 -0
  61. data/app/models/surveillance/option.rb +18 -0
  62. data/app/models/surveillance/question.rb +50 -0
  63. data/app/models/surveillance/section.rb +16 -0
  64. data/app/models/surveillance/survey.rb +38 -0
  65. data/app/views/layouts/surveillance/application.html.haml +11 -0
  66. data/app/views/surveillance/admin/attempts/index.html.haml +47 -0
  67. data/app/views/surveillance/admin/attempts/list.html.haml +11 -0
  68. data/app/views/surveillance/admin/attempts/overview.html.haml +6 -0
  69. data/app/views/surveillance/admin/attempts/show.html.haml +62 -0
  70. data/app/views/surveillance/admin/exports/show.rxls +39 -0
  71. data/app/views/surveillance/admin/options/_field.html.haml +11 -0
  72. data/app/views/surveillance/admin/options/_form.html.haml +8 -0
  73. data/app/views/surveillance/admin/options/_list.html.haml +10 -0
  74. data/app/views/surveillance/admin/options/_option.html.haml +13 -0
  75. data/app/views/surveillance/admin/options/edit.html.haml +7 -0
  76. data/app/views/surveillance/admin/options/new.html.haml +7 -0
  77. data/app/views/surveillance/admin/questions/_form.html.haml +35 -0
  78. data/app/views/surveillance/admin/questions/_list.html.haml +17 -0
  79. data/app/views/surveillance/admin/questions/_question.html.haml +27 -0
  80. data/app/views/surveillance/admin/questions/edit.html.haml +7 -0
  81. data/app/views/surveillance/admin/questions/new.html.haml +4 -0
  82. data/app/views/surveillance/admin/sections/_form.html.haml +16 -0
  83. data/app/views/surveillance/admin/sections/_list.html.haml +13 -0
  84. data/app/views/surveillance/admin/sections/_section.html.haml +16 -0
  85. data/app/views/surveillance/admin/sections/edit.html.haml +7 -0
  86. data/app/views/surveillance/admin/sections/new.html.haml +4 -0
  87. data/app/views/surveillance/admin/surveys/_form.html.haml +22 -0
  88. data/app/views/surveillance/admin/surveys/_list.html.haml +13 -0
  89. data/app/views/surveillance/admin/surveys/_survey.html.haml +32 -0
  90. data/app/views/surveillance/admin/surveys/edit.html.haml +7 -0
  91. data/app/views/surveillance/admin/surveys/index.html.haml +1 -0
  92. data/app/views/surveillance/admin/surveys/new.html.haml +4 -0
  93. data/app/views/surveillance/field/date/_form.html.haml +5 -0
  94. data/app/views/surveillance/field/date/_overview.html.haml +2 -0
  95. data/app/views/surveillance/field/date/_show.html.haml +10 -0
  96. data/app/views/surveillance/field/matrix/_form.html.haml +40 -0
  97. data/app/views/surveillance/field/matrix/_overview.html.haml +19 -0
  98. data/app/views/surveillance/field/matrix/_questions_fields.html.haml +11 -0
  99. data/app/views/surveillance/field/matrix/_settings.html.haml +18 -0
  100. data/app/views/surveillance/field/matrix/_show.html.haml +22 -0
  101. data/app/views/surveillance/field/multiple_choices/_form.html.haml +18 -0
  102. data/app/views/surveillance/field/multiple_choices/_settings.html.haml +21 -0
  103. data/app/views/surveillance/field/multiple_choices/_show.html.haml +21 -0
  104. data/app/views/surveillance/field/multiple_choices_matrix/_form.html.haml +33 -0
  105. data/app/views/surveillance/field/multiple_choices_matrix/_show.html.haml +1 -0
  106. data/app/views/surveillance/field/number/_form.html.haml +5 -0
  107. data/app/views/surveillance/field/number/_overview.html.haml +2 -0
  108. data/app/views/surveillance/field/number/_settings.html.haml +2 -0
  109. data/app/views/surveillance/field/number/_show.html.haml +10 -0
  110. data/app/views/surveillance/field/order/_form.html.haml +17 -0
  111. data/app/views/surveillance/field/order/_overview.html.haml +22 -0
  112. data/app/views/surveillance/field/order/_settings.html.haml +11 -0
  113. data/app/views/surveillance/field/order/_show.html.haml +8 -0
  114. data/app/views/surveillance/field/select_matrix/_form.html.haml +17 -0
  115. data/app/views/surveillance/field/shared/_rules_form.html.haml +30 -0
  116. data/app/views/surveillance/field/shared/settings/_boolean.html.haml +9 -0
  117. data/app/views/surveillance/field/shared/settings/_number.html.haml +5 -0
  118. data/app/views/surveillance/field/single_choice/_form.html.haml +16 -0
  119. data/app/views/surveillance/field/single_choice/_overview.html.haml +14 -0
  120. data/app/views/surveillance/field/single_choice/_settings.html.haml +2 -0
  121. data/app/views/surveillance/field/single_choice/_show.html.haml +21 -0
  122. data/app/views/surveillance/field/single_select/_form.html.haml +4 -0
  123. data/app/views/surveillance/field/single_select/_overview.html.haml +14 -0
  124. data/app/views/surveillance/field/single_select/_show.html.haml +13 -0
  125. data/app/views/surveillance/field/text/_form.html.haml +5 -0
  126. data/app/views/surveillance/field/text/_overview.html.haml +2 -0
  127. data/app/views/surveillance/field/text/_show.html.haml +10 -0
  128. data/app/views/surveillance/field/text_area/_form.html.haml +5 -0
  129. data/app/views/surveillance/field/text_area/_overview.html.haml +1 -0
  130. data/app/views/surveillance/field/text_area/_show.html.haml +10 -0
  131. data/app/views/surveillance/response/attempts/complete.html.haml +11 -0
  132. data/app/views/surveillance/response/attempts/edit.html.haml +15 -0
  133. data/app/views/surveillance/sections/_section.html.haml +24 -0
  134. data/app/views/surveillance/surveys/_survey.html.haml +4 -0
  135. data/app/views/surveillance/surveys/index.html.haml +8 -0
  136. data/app/views/surveillance/surveys/show.html.haml +15 -0
  137. data/config/locales/surveillance.fr.yml +165 -0
  138. data/config/routes.rb +30 -0
  139. data/db/migrate/20130626115136_create_surveillance_surveys.rb +13 -0
  140. data/db/migrate/20130626115805_create_surveillance_sections.rb +12 -0
  141. data/db/migrate/20130626130351_create_surveillance_questions.rb +14 -0
  142. data/db/migrate/20130702111125_create_surveillance_options.rb +11 -0
  143. data/db/migrate/20130703113456_create_surveillance_attempts.rb +11 -0
  144. data/db/migrate/20130703115649_create_surveillance_answers.rb +11 -0
  145. data/db/migrate/20130703115723_create_surveillance_answer_contents.rb +10 -0
  146. data/db/migrate/20130710151627_create_surveillance_field_settings.rb +11 -0
  147. data/db/migrate/20130711100032_create_surveillance_answers_options_join_table.rb +7 -0
  148. data/db/migrate/20130729143002_create_surveillance_branch_rules.rb +14 -0
  149. data/db/migrate/20140212153506_add_state_to_surveillance_attempts.rb +6 -0
  150. data/db/migrate/20140213101147_add_access_token_to_surveillance_attempts.rb +5 -0
  151. data/db/migrate/20140213133036_add_partial_to_surveillance_questions.rb +5 -0
  152. data/lib/generators/surveillance/install/install_generator.rb +34 -0
  153. data/lib/generators/surveillance/install/templates/initializer.rb +51 -0
  154. data/lib/surveillance.rb +61 -0
  155. data/lib/surveillance/branch_action.rb +5 -0
  156. data/lib/surveillance/branch_condition.rb +5 -0
  157. data/lib/surveillance/engine.rb +13 -0
  158. data/lib/surveillance/field.rb +58 -0
  159. data/lib/surveillance/field/base.rb +149 -0
  160. data/lib/surveillance/field/date.rb +17 -0
  161. data/lib/surveillance/field/matrix.rb +66 -0
  162. data/lib/surveillance/field/matrix_question.rb +13 -0
  163. data/lib/surveillance/field/multiple_choices.rb +29 -0
  164. data/lib/surveillance/field/multiple_choices_matrix.rb +13 -0
  165. data/lib/surveillance/field/number.rb +34 -0
  166. data/lib/surveillance/field/order.rb +40 -0
  167. data/lib/surveillance/field/order_question.rb +22 -0
  168. data/lib/surveillance/field/other_choice.rb +28 -0
  169. data/lib/surveillance/field/select_matrix.rb +13 -0
  170. data/lib/surveillance/field/single_choice.rb +36 -0
  171. data/lib/surveillance/field/single_select.rb +31 -0
  172. data/lib/surveillance/field/text.rb +13 -0
  173. data/lib/surveillance/field/text_area.rb +6 -0
  174. data/lib/surveillance/partials_collection.rb +7 -0
  175. data/lib/surveillance/setting.rb +24 -0
  176. data/lib/surveillance/settings_collection.rb +17 -0
  177. data/lib/surveillance/validators.rb +7 -0
  178. data/lib/surveillance/validators/answer_validator.rb +9 -0
  179. data/lib/surveillance/version.rb +3 -0
  180. data/lib/tasks/surveillance_tasks.rake +4 -0
  181. data/spec/dummy/README.rdoc +28 -0
  182. data/spec/dummy/Rakefile +6 -0
  183. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  184. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  185. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  186. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  187. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  188. data/spec/dummy/bin/bundle +3 -0
  189. data/spec/dummy/bin/rails +4 -0
  190. data/spec/dummy/bin/rake +4 -0
  191. data/spec/dummy/config.ru +4 -0
  192. data/spec/dummy/config/application.rb +28 -0
  193. data/spec/dummy/config/boot.rb +5 -0
  194. data/spec/dummy/config/database.yml +25 -0
  195. data/spec/dummy/config/environment.rb +5 -0
  196. data/spec/dummy/config/environments/development.rb +29 -0
  197. data/spec/dummy/config/environments/production.rb +80 -0
  198. data/spec/dummy/config/environments/test.rb +36 -0
  199. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  200. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  201. data/spec/dummy/config/initializers/inflections.rb +16 -0
  202. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  203. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  204. data/spec/dummy/config/initializers/session_store.rb +3 -0
  205. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  206. data/spec/dummy/config/locales/en.yml +23 -0
  207. data/spec/dummy/config/locales/rails.fr.yml +226 -0
  208. data/spec/dummy/config/routes.rb +3 -0
  209. data/spec/dummy/db/development.sqlite3 +0 -0
  210. data/spec/dummy/db/migrate/20140113224541_create_surveillance_surveys.surveillance.rb +14 -0
  211. data/spec/dummy/db/migrate/20140113224542_create_surveillance_sections.surveillance.rb +13 -0
  212. data/spec/dummy/db/migrate/20140113224543_create_surveillance_questions.surveillance.rb +15 -0
  213. data/spec/dummy/db/migrate/20140113224544_create_surveillance_options.surveillance.rb +12 -0
  214. data/spec/dummy/db/migrate/20140113224545_create_surveillance_attempts.surveillance.rb +12 -0
  215. data/spec/dummy/db/migrate/20140113224546_create_surveillance_answers.surveillance.rb +12 -0
  216. data/spec/dummy/db/migrate/20140113224547_create_surveillance_answer_contents.surveillance.rb +11 -0
  217. data/spec/dummy/db/migrate/20140113224548_create_surveillance_field_settings.surveillance.rb +12 -0
  218. data/spec/dummy/db/migrate/20140113224549_create_surveillance_answers_options_join_table.surveillance.rb +8 -0
  219. data/spec/dummy/db/migrate/20140113224550_create_surveillance_branch_rules.surveillance.rb +15 -0
  220. data/spec/dummy/db/schema.rb +103 -0
  221. data/spec/dummy/log/development.log +38066 -0
  222. data/spec/dummy/public/404.html +58 -0
  223. data/spec/dummy/public/422.html +58 -0
  224. data/spec/dummy/public/500.html +57 -0
  225. data/spec/dummy/public/favicon.ico +0 -0
  226. data/spec/dummy/spec +1 -0
  227. data/spec/dummy/tmp/cache/assets/development/sprockets/0018421aaf29044fbd13363bbdfd8f44 +0 -0
  228. data/spec/dummy/tmp/cache/assets/development/sprockets/017d7a30ec05c0fb0265fb5167c73ee9 +0 -0
  229. data/spec/dummy/tmp/cache/assets/development/sprockets/034b76adeb89d6ca63cd9eea649331f5 +0 -0
  230. data/spec/dummy/tmp/cache/assets/development/sprockets/05de8fbfacab66a0efe4f9790b2ac723 +0 -0
  231. data/spec/dummy/tmp/cache/assets/development/sprockets/0811effcff3b9107d49398bdba7488e5 +0 -0
  232. data/spec/dummy/tmp/cache/assets/development/sprockets/0d45beae32861dc508fc2db09b9d95b3 +0 -0
  233. data/spec/dummy/tmp/cache/assets/development/sprockets/0d4961f3da5a0d5234736a6abbf42226 +0 -0
  234. data/spec/dummy/tmp/cache/assets/development/sprockets/0f491ed240e1a27bbc05e5213afd48bb +0 -0
  235. data/spec/dummy/tmp/cache/assets/development/sprockets/10e2a0dbdbb68c055e8b7ccd6f2906d8 +0 -0
  236. data/spec/dummy/tmp/cache/assets/development/sprockets/1173cdef6c662a55ef590489fe26e8fe +0 -0
  237. data/spec/dummy/tmp/cache/assets/development/sprockets/1b3e93127523ec0f3c93bcd91d4390dc +0 -0
  238. data/spec/dummy/tmp/cache/assets/development/sprockets/1bb56fbf17ccbb14dcbaa4d6d639e620 +0 -0
  239. data/spec/dummy/tmp/cache/assets/development/sprockets/2bd0ba6a1598c9fa67081d8f906db6f8 +0 -0
  240. data/spec/dummy/tmp/cache/assets/development/sprockets/3fbe053f103de46cc1b320f059b99c1f +0 -0
  241. data/spec/dummy/tmp/cache/assets/development/sprockets/4144b095447efb810a548b99e41df9eb +0 -0
  242. data/spec/dummy/tmp/cache/assets/development/sprockets/421d097cb8d88f975d8ccf75c9e5e306 +0 -0
  243. data/spec/dummy/tmp/cache/assets/development/sprockets/474bc1c9055df6cc1cdff58817a6cb41 +0 -0
  244. data/spec/dummy/tmp/cache/assets/development/sprockets/4829d251eeb22cdbd05b27b6ba809538 +0 -0
  245. data/spec/dummy/tmp/cache/assets/development/sprockets/4f584ca3f0c8ec62906e6f03bc5963c2 +0 -0
  246. data/spec/dummy/tmp/cache/assets/development/sprockets/55d647d88e01b91b2a146e7db0481c09 +0 -0
  247. data/spec/dummy/tmp/cache/assets/development/sprockets/62db8b5885b79c5dc0667fab0fbf46bb +0 -0
  248. data/spec/dummy/tmp/cache/assets/development/sprockets/7080a4d265fe784c9704db71f81da832 +0 -0
  249. data/spec/dummy/tmp/cache/assets/development/sprockets/7220af243fd39e3dffd233252e4a8c17 +0 -0
  250. data/spec/dummy/tmp/cache/assets/development/sprockets/7cd0e5bfe12b86ed494d02e8e5b62bbf +0 -0
  251. data/spec/dummy/tmp/cache/assets/development/sprockets/7e37a8ae2a50653b388d57c573d12548 +0 -0
  252. data/spec/dummy/tmp/cache/assets/development/sprockets/8113790dad1da8858c82cfc3eb14ef87 +0 -0
  253. data/spec/dummy/tmp/cache/assets/development/sprockets/83997102fc04f275cd6cd8c1ddb55835 +0 -0
  254. data/spec/dummy/tmp/cache/assets/development/sprockets/8a7b047a16adbc640e03eaabe4a4fe93 +0 -0
  255. data/spec/dummy/tmp/cache/assets/development/sprockets/90b48fb4bfa22ddcd063734065d27086 +0 -0
  256. data/spec/dummy/tmp/cache/assets/development/sprockets/935886b24c90d344752d2a80e3657801 +0 -0
  257. data/spec/dummy/tmp/cache/assets/development/sprockets/9606a6d70af63ce3fea26ded0a69d5c2 +0 -0
  258. data/spec/dummy/tmp/cache/assets/development/sprockets/97db73fdf0bbab24fb92892c61ec7a9b +0 -0
  259. data/spec/dummy/tmp/cache/assets/development/sprockets/a23bb60554e715c228ae3cdfb5d81807 +0 -0
  260. data/spec/dummy/tmp/cache/assets/development/sprockets/ad17e102b9f9288a9e919b0b0a2ab05b +0 -0
  261. data/spec/dummy/tmp/cache/assets/development/sprockets/c26ae1f6640b52c232bd392a6e2f7110 +0 -0
  262. data/spec/dummy/tmp/cache/assets/development/sprockets/c6cb3deca0f08bd9569d00fca09272da +0 -0
  263. data/spec/dummy/tmp/cache/assets/development/sprockets/d39b4eebbd0042342e10497a34fd6378 +0 -0
  264. data/spec/dummy/tmp/cache/assets/development/sprockets/d5ee573b2abdcdc245a830bde2dd76f3 +0 -0
  265. data/spec/dummy/tmp/cache/assets/development/sprockets/d6487e59842ff206d84f6de5e3a7400c +0 -0
  266. data/spec/dummy/tmp/cache/assets/development/sprockets/dafa124ddd0e828d7c5c0a5c4db455ba +0 -0
  267. data/spec/dummy/tmp/cache/assets/development/sprockets/e5bbd03518f9abc3e9bc1373c74fd3f1 +0 -0
  268. data/spec/dummy/tmp/cache/assets/development/sprockets/ed5aa255edff522c2e36e6f0151ff747 +0 -0
  269. data/spec/dummy/tmp/cache/assets/development/sprockets/ee263a426f6530013f86aa860448fa91 +0 -0
  270. data/spec/dummy/tmp/cache/assets/development/sprockets/efa0c4d855d425fdf4b63ab26c45e94c +0 -0
  271. data/spec/dummy/tmp/cache/assets/development/sprockets/f2881259fd5bad1c0a5b1ab5dff97c47 +0 -0
  272. data/spec/dummy/tmp/cache/assets/development/sprockets/f34108e540cff2fbc32036da452ca6ae +0 -0
  273. data/spec/dummy/tmp/cache/assets/development/sprockets/f7e7e00ef8efc13c6a2628e453344440 +0 -0
  274. data/spec/dummy/tmp/cache/assets/development/sprockets/f9a44009076e46b0f35af5e7031a1871 +0 -0
  275. data/spec/spec_helper.rb +87 -0
  276. metadata +598 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4db1967c20eb4e00ac9c3e984de9b7d880047e23
4
+ data.tar.gz: ff2500601aa86de50aa6d227aa9407ecc347cce7
5
+ SHA512:
6
+ metadata.gz: b8ceef7ca622f70da676b0a6784e8d1bf5b10470a86a5d06e756206cd42a18d11ab1d2b93355834209788dc6d0059b29f182b6de43624231c575966b076d78b0
7
+ data.tar.gz: 7624f52a246719e8f73c14e13be23a46c9dcd1491cfbc4ec1e8ced735db296aadffa87b92dd3830f37663dfdb600c6b0f4428adacc6b6274b1f020aac822d5f9
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ # Surveillance
2
+
3
+ Survey Rails 4 engine
4
+
5
+ ## Installation
6
+
7
+ Add to Gemfile and bundle :
8
+
9
+ ```ruby
10
+ gem 'surveillance', github: 'vala/surveillance'
11
+ ```
12
+
13
+ Execute install generator :
14
+
15
+ ```bash
16
+ rails generate surveillance:install
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ - Configure with generated initializer
22
+ - Access admin at : `/<mount_path>/admin/surveys`
23
+ - Access surveys at : `/<mount_path>/surveys`
24
+ - Require the javascript lib in your application.js : `//= require surveillance`
25
+
26
+ ### Overriding models or controllers
27
+
28
+ If you need to override a class from the system, e.g. adding a validation or
29
+ method to a model, a `before_action` to a controller or something like that,
30
+ you can use the "decorators" approach the following way :
31
+
32
+ 1. Create a file with the name of the desired class under
33
+ `lib/decorators/surveillance/`, e.g. `lib/decorators/surveillance/attempt.rb`
34
+ 2. Use `.class_eval` to reopen the class and modify it. e.g.
35
+ ```ruby
36
+ # lib/decorators/surveillance/attempt.rb
37
+ Surveillance::Attemp.class_eval do
38
+ def foo
39
+ puts 'bar'
40
+ end
41
+ end
42
+ ```
@@ -0,0 +1,23 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Surveillance'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
@@ -0,0 +1,6 @@
1
+ //= require ./surveillance/vendor/jquery-ui-sortable
2
+ //= require ./surveillance/vendor/jquery.scrollto
3
+ //= require ./surveillance/form
4
+ //= require_tree ./surveillance/models
5
+ //= require_tree ./surveillance/collections
6
+ //= require_tree ./surveillance/views
@@ -0,0 +1,4 @@
1
+ #= require jquery
2
+ #= require jquery_ujs
3
+ #= require ./vendor/bootstrap
4
+ #= require_tree ./admin
@@ -0,0 +1,18 @@
1
+ $ ->
2
+ $("body").on "click", "[data-destroy-field]", (e) ->
3
+ e.preventDefault()
4
+ $link = $(e.currentTarget)
5
+ $link.prev().val("1")
6
+ target = $link.data("parent-target") || "fieldset"
7
+ $target = $link.closest(target)
8
+ $target.fadeOut(300)
9
+
10
+ $("body").on "click", "[data-toggle='new-field']", (e) ->
11
+ e.preventDefault()
12
+ $link = $(e.currentTarget)
13
+ time = new Date().getTime()
14
+ idReplacePattern = new RegExp($link.data("id"), "g")
15
+ html = $link.data("fields").replace(idReplacePattern, time)
16
+ $link.before(html)
17
+
18
+
@@ -0,0 +1,17 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //= require jquery
13
+ //= require jquery_ujs
14
+ //= require ./vendor/underscore.min
15
+ //= require ./vendor/backbone.min
16
+ //= require ./manifest
17
+ //= require_tree ./admin
@@ -0,0 +1,2 @@
1
+ class Surveillance.BranchRuleCollection extends Backbone.Collection
2
+ model: Surveillance.BranchRule
@@ -0,0 +1,7 @@
1
+ # Create Surveillance global namespace
2
+ @Surveillance = {}
3
+
4
+ $ ->
5
+ # Initialize forms if present on page
6
+ if ($forms = $(".surveillance-attempt-form"))
7
+ $forms.each (i, el) -> new Surveillance.AttemptView(el: el)
@@ -0,0 +1,7 @@
1
+ # [DEPRECATED] Here for backwards compatibility
2
+ #
3
+ #= require ./vendor/jquery-ui-sortable
4
+ #= require ./form
5
+ #= require_tree ./models
6
+ #= require_tree ./collections
7
+ #= require_tree ./views
@@ -0,0 +1,21 @@
1
+ class Surveillance.BranchRule extends Backbone.Model
2
+ matches: (@question) ->
3
+ @[@get("condition")]()
4
+
5
+ answers: ->
6
+ @question.answered()
7
+
8
+ doesnt_answer: ->
9
+ !@answers()
10
+
11
+ answers_option: ->
12
+ optionId = @get("option_id")
13
+
14
+ if @question.get("matrix")
15
+ questionId = @get("sub_question_id")
16
+ @question.hasAnswered(questionId, optionId)
17
+ else
18
+ @question.hasAnswered(optionId)
19
+
20
+ doesnt_answer_option: ->
21
+ !@answers_option()
@@ -0,0 +1,19 @@
1
+ class Surveillance.Question extends Backbone.Model
2
+ constructor: (attrs, options) ->
3
+ @rules = new Surveillance.BranchRuleCollection(attrs.rules)
4
+ delete attrs.rules
5
+ super(attrs, options)
6
+
7
+ validate: ->
8
+ return null unless @get("required")
9
+ @processValidations()
10
+
11
+ processValidations: ->
12
+ @get("fields").length < @get("fieldsToFill")
13
+
14
+ answered: ->
15
+ @get("fields").length > 0
16
+
17
+ firstMatchingRule: ->
18
+ for rule in @rules.models
19
+ return rule if rule.matches(this)
@@ -0,0 +1,15 @@
1
+ class Surveillance.ChoosableQuestion extends Surveillance.Question
2
+ processValidations: ->
3
+ otherChoosed = _.include(@get("value"), "other")
4
+ minFieldsToFill = 1
5
+ chooseField = @get("value").length < minFieldsToFill
6
+ fillOtherField = otherChoosed && !@get("other")
7
+
8
+ if chooseField or fillOtherField
9
+ { chooseField: chooseField, fillOtherField: fillOtherField }
10
+ else
11
+ false
12
+
13
+ hasAnswered: (optionId) ->
14
+ _.include(@get("value"), optionId)
15
+
@@ -0,0 +1,19 @@
1
+ class Surveillance.Matrix extends Surveillance.Question
2
+ initialize: (options) ->
3
+ @set(matrix: true)
4
+ @subQuestions = []
5
+
6
+ processValidations: ->
7
+ errors = _.reduce(
8
+ @subQuestions
9
+ (errors, q) ->
10
+ errors.push(q.id) unless q.isValid()
11
+ errors
12
+ []
13
+ )
14
+
15
+ if errors.length then errors else false
16
+
17
+ hasAnswered: (questionId, optionId) ->
18
+ _.any @subQuestions, (subQuestion) ->
19
+ subQuestion.id == questionId and subQuestion.hasAnswered(optionId)
@@ -0,0 +1,7 @@
1
+ class Surveillance.MatrixQuestion extends Backbone.Model
2
+ validate: ->
3
+ @get("value").length == 0
4
+
5
+ hasAnswered: (optionId) ->
6
+ _.include(@get("value"), optionId)
7
+
@@ -0,0 +1,17 @@
1
+ class Surveillance.Number extends Surveillance.Question
2
+ defaults:
3
+ value: null
4
+
5
+ validate: ->
6
+ return null unless @get("required") or @get("value")
7
+ @processValidations()
8
+
9
+ processValidations: ->
10
+ value = @get("value")
11
+ belowMinimum = value and (minimum = @get("minimum")) and value < minimum
12
+ aboveMaximum = value and (maximum = @get("maximum")) and value > maximum
13
+
14
+ !value or belowMinimum or aboveMaximum
15
+
16
+
17
+
@@ -0,0 +1 @@
1
+ (function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.1.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o<u;o++){t=a[o];if(n=this._events[t]){this._events[t]=r=[];if(e||i){for(c=0,f=n.length;c<f;c++){s=n[c];if(e&&e!==s.callback&&e!==s.callback._callback||i&&i!==s.context){r.push(s)}}}if(!r.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=s.call(arguments,1);if(!l(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)c(i,e);if(r)c(r,arguments);return this},stopListening:function(t,e,i){var r=this._listeningTo;if(!r)return this;var s=!e&&!i;if(!i&&typeof e==="object")i=this;if(t)(r={})[t._listenId]=t;for(var n in r){t=r[n];t.off(e,i,this);if(s||h.isEmpty(t._events))delete this._listeningTo[n]}return this}};var u=/\s+/;var l=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(u.test(i)){var n=i.split(u);for(var a=0,h=n.length;a<h;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var c=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],h=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,h);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e)}};var f={listenTo:"on",listenToOnce:"once"};h.each(f,function(t,e){o[e]=function(e,i,r){var s=this._listeningTo||(this._listeningTo={});var n=e._listenId||(e._listenId=h.uniqueId("l"));s[n]=e;if(!r&&typeof i==="object")r=this;e[t](i,r,this);return this}});o.bind=o.on;o.unbind=o.off;h.extend(a,o);var d=a.Model=function(t,e){var i=t||{};e||(e={});this.cid=h.uniqueId("c");this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)i=this.parse(i,e)||{};i=h.defaults({},i,h.result(this,"defaults"));this.set(i,e);this.changed={};this.initialize.apply(this,arguments)};h.extend(d.prototype,o,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return h.clone(this.attributes)},sync:function(){return a.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return h.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,i){var r,s,n,a,o,u,l,c;if(t==null)return this;if(typeof t==="object"){s=t;i=e}else{(s={})[t]=e}i||(i={});if(!this._validate(s,i))return false;n=i.unset;o=i.silent;a=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=h.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in s)this.id=s[this.idAttribute];for(r in s){e=s[r];if(!h.isEqual(c[r],e))a.push(r);if(!h.isEqual(l[r],e)){this.changed[r]=e}else{delete this.changed[r]}n?delete c[r]:c[r]=e}if(!o){if(a.length)this._pending=true;for(var f=0,d=a.length;f<d;f++){this.trigger("change:"+a[f],this,c[a[f]],i)}}if(u)return this;if(!o){while(this._pending){this._pending=false;this.trigger("change",this,i)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,h.extend({},e,{unset:true}))},clear:function(t){var e={};for(var i in this.attributes)e[i]=void 0;return this.set(e,h.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!h.isEmpty(this.changed);return h.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?h.clone(this.changed):false;var e,i=false;var r=this._changing?this._previousAttributes:this.attributes;for(var s in t){if(h.isEqual(r[s],e=t[s]))continue;(i||(i={}))[s]=e}return i},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return h.clone(this._previousAttributes)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var i=t.success;t.success=function(r){if(!e.set(e.parse(r,t),t))return false;if(i)i(e,r,t);e.trigger("sync",e,r,t)};M(this,t);return this.sync("read",this,t)},save:function(t,e,i){var r,s,n,a=this.attributes;if(t==null||typeof t==="object"){r=t;i=e}else{(r={})[t]=e}i=h.extend({validate:true},i);if(r&&!i.wait){if(!this.set(r,i))return false}else{if(!this._validate(r,i))return false}if(r&&i.wait){this.attributes=h.extend({},a,r)}if(i.parse===void 0)i.parse=true;var o=this;var u=i.success;i.success=function(t){o.attributes=a;var e=o.parse(t,i);if(i.wait)e=h.extend(r||{},e);if(h.isObject(e)&&!o.set(e,i)){return false}if(u)u(o,t,i);o.trigger("sync",o,t,i)};M(this,i);s=this.isNew()?"create":i.patch?"patch":"update";if(s==="patch")i.attrs=r;n=this.sync(s,this,i);if(r&&i.wait)this.attributes=a;return n},destroy:function(t){t=t?h.clone(t):{};var e=this;var i=t.success;var r=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(s){if(t.wait||e.isNew())r();if(i)i(e,s,t);if(!e.isNew())e.trigger("sync",e,s,t)};if(this.isNew()){t.success();return false}M(this,t);var s=this.sync("delete",this,t);if(!t.wait)r();return s},url:function(){var t=h.result(this,"urlRoot")||h.result(this.collection,"url")||U();if(this.isNew())return t;return t+(t.charAt(t.length-1)==="/"?"":"/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return this.id==null},isValid:function(t){return this._validate({},h.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=h.extend({},this.attributes,t);var i=this.validationError=this.validate(t,e)||null;if(!i)return true;this.trigger("invalid",this,i,h.extend(e,{validationError:i}));return false}});var p=["keys","values","pairs","invert","pick","omit"];h.each(p,function(t){d.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.attributes);return h[t].apply(h,e)}});var v=a.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,h.extend({silent:true},e))};var g={add:true,remove:true,merge:true};var m={add:true,remove:false};h.extend(v.prototype,o,{model:d,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return a.sync.apply(this,arguments)},add:function(t,e){return this.set(t,h.extend({merge:false},e,m))},remove:function(t,e){var i=!h.isArray(t);t=i?[t]:h.clone(t);e||(e={});var r,s,n,a;for(r=0,s=t.length;r<s;r++){a=t[r]=this.get(t[r]);if(!a)continue;delete this._byId[a.id];delete this._byId[a.cid];n=this.indexOf(a);this.models.splice(n,1);this.length--;if(!e.silent){e.index=n;a.trigger("remove",a,this,e)}this._removeReference(a)}return i?t[0]:t},set:function(t,e){e=h.defaults({},e,g);if(e.parse)t=this.parse(t,e);var i=!h.isArray(t);t=i?t?[t]:[]:h.clone(t);var r,s,n,a,o,u,l;var c=e.at;var f=this.model;var p=this.comparator&&c==null&&e.sort!==false;var v=h.isString(this.comparator)?this.comparator:null;var m=[],y=[],_={};var w=e.add,b=e.merge,x=e.remove;var E=!p&&w&&x?[]:false;for(r=0,s=t.length;r<s;r++){o=t[r];if(o instanceof d){n=a=o}else{n=o[f.prototype.idAttribute]}if(u=this.get(n)){if(x)_[u.cid]=true;if(b){o=o===a?a.attributes:o;if(e.parse)o=u.parse(o,e);u.set(o,e);if(p&&!l&&u.hasChanged(v))l=true}t[r]=u}else if(w){a=t[r]=this._prepareModel(o,e);if(!a)continue;m.push(a);a.on("all",this._onModelEvent,this);this._byId[a.cid]=a;if(a.id!=null)this._byId[a.id]=a}if(E)E.push(u||a)}if(x){for(r=0,s=this.length;r<s;++r){if(!_[(a=this.models[r]).cid])y.push(a)}if(y.length)this.remove(y,e)}if(m.length||E&&E.length){if(p)l=true;this.length+=m.length;if(c!=null){for(r=0,s=m.length;r<s;r++){this.models.splice(c+r,0,m[r])}}else{if(E)this.models.length=0;var T=E||m;for(r=0,s=T.length;r<s;r++){this.models.push(T[r])}}}if(l)this.sort({silent:true});if(!e.silent){for(r=0,s=m.length;r<s;r++){(a=m[r]).trigger("add",a,this,e)}if(l||E&&E.length)this.trigger("sort",this,e)}return i?t[0]:t},reset:function(t,e){e||(e={});for(var i=0,r=this.models.length;i<r;i++){this._removeReference(this.models[i])}e.previousModels=this.models;this._reset();t=this.add(t,h.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,h.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){return this.add(t,h.extend({at:0},e))},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(){return s.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t.id]||this._byId[t.cid]||this._byId[t]},at:function(t){return this.models[t]},where:function(t,e){if(h.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(h.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(h.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return h.invoke(this.models,"get",t)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var i=this;t.success=function(r){var s=t.reset?"reset":"set";i[s](r,t);if(e)e(i,r,t);i.trigger("sync",i,r,t)};M(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?h.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var i=this;var r=e.success;e.success=function(t,e,s){if(s.wait)i.add(t,s);if(r)r(t,e,s)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof d){if(!t.collection)t.collection=this;return t}e=e?h.clone(e):{};e.collection=this;var i=new this.model(t,e);if(!i.validationError)return i;this.trigger("invalid",this,i.validationError,e);return false},_removeReference:function(t){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var y=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","difference","indexOf","shuffle","lastIndexOf","isEmpty","chain"];h.each(y,function(t){v.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.models);return h[t].apply(h,e)}});var _=["groupBy","countBy","sortBy"];h.each(_,function(t){v.prototype[t]=function(e,i){var r=h.isFunction(e)?e:function(t){return t.get(e)};return h[t](this.models,r,i)}});var w=a.View=function(t){this.cid=h.uniqueId("view");t||(t={});h.extend(this,h.pick(t,x));this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var b=/^(\S+)\s*(.*)$/;var x=["model","collection","el","id","attributes","className","tagName","events"];h.extend(w.prototype,o,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,e){if(this.$el)this.undelegateEvents();this.$el=t instanceof a.$?t:a.$(t);this.el=this.$el[0];if(e!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=h.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var i=t[e];if(!h.isFunction(i))i=this[t[e]];if(!i)continue;var r=e.match(b);var s=r[1],n=r[2];i=h.bind(i,this);s+=".delegateEvents"+this.cid;if(n===""){this.$el.on(s,i)}else{this.$el.on(s,n,i)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_ensureElement:function(){if(!this.el){var t=h.extend({},h.result(this,"attributes"));if(this.id)t.id=h.result(this,"id");if(this.className)t["class"]=h.result(this,"className");var e=a.$("<"+h.result(this,"tagName")+">").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=T[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&E){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var E=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var k=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var $=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(k.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace(S,"(?:$1)?").replace($,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/[?#].*$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=P.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(O,"/");if(r&&this._wantsHashChange){this.iframe=a.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;this.navigate(e)}if(this._hasPushState){a.$(window).on("popstate",this.checkUrl)}else if(this._wantsHashChange&&"onhashchange"in window&&!r){a.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=e;var s=this.location;var n=s.pathname.replace(/[^\/]$/,"$&/")===this.root;if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!n){this.fragment=this.getFragment(null,true);this.location.replace(this.root+this.location.search+"#"+this.fragment);return true}else if(this._hasPushState&&n&&s.hash){this.fragment=this.getHash().replace(N,"");this.history.replaceState({},document.title,this.root+this.fragment+s.search)}}if(!this.options.silent)return this.loadUrl()},stop:function(){a.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);I.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){t=this.fragment=this.getFragment(t);return h.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!I.started)return false;if(!e||e===true)e={trigger:!!e};var i=this.root+(t=this.getFragment(t||""));t=t.replace(j,"");if(this.fragment===t)return;this.fragment=t;if(t===""&&i!=="/")i=i.slice(0,-1);if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});a.history=new I;var R=function(t,e){var i=this;var r;if(t&&h.has(t,"constructor")){r=t.constructor}else{r=function(){return i.apply(this,arguments)}}h.extend(r,i,e);var s=function(){this.constructor=r};s.prototype=i.prototype;r.prototype=new s;if(t)h.extend(r.prototype,t);r.__super__=i.prototype;return r};d.extend=v.extend=k.extend=w.extend=I.extend=R;var U=function(){throw new Error('A "url" property or function must be specified')};var M=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}}}).call(this);
@@ -0,0 +1,2118 @@
1
+ /*!
2
+ * Bootstrap v3.2.0 (http://getbootstrap.com)
3
+ * Copyright 2011-2014 Twitter, Inc.
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5
+ */
6
+
7
+ /*!
8
+ * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=5fd8abcabe46be29123b)
9
+ * Config saved to config.json and https://gist.github.com/5fd8abcabe46be29123b
10
+ */
11
+ if (typeof jQuery === "undefined") { throw new Error("Bootstrap's JavaScript requires jQuery") }
12
+
13
+ /* ========================================================================
14
+ * Bootstrap: alert.js v3.2.0
15
+ * http://getbootstrap.com/javascript/#alerts
16
+ * ========================================================================
17
+ * Copyright 2011-2014 Twitter, Inc.
18
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
19
+ * ======================================================================== */
20
+
21
+
22
+ +function ($) {
23
+ 'use strict';
24
+
25
+ // ALERT CLASS DEFINITION
26
+ // ======================
27
+
28
+ var dismiss = '[data-dismiss="alert"]'
29
+ var Alert = function (el) {
30
+ $(el).on('click', dismiss, this.close)
31
+ }
32
+
33
+ Alert.VERSION = '3.2.0'
34
+
35
+ Alert.prototype.close = function (e) {
36
+ var $this = $(this)
37
+ var selector = $this.attr('data-target')
38
+
39
+ if (!selector) {
40
+ selector = $this.attr('href')
41
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
42
+ }
43
+
44
+ var $parent = $(selector)
45
+
46
+ if (e) e.preventDefault()
47
+
48
+ if (!$parent.length) {
49
+ $parent = $this.hasClass('alert') ? $this : $this.parent()
50
+ }
51
+
52
+ $parent.trigger(e = $.Event('close.bs.alert'))
53
+
54
+ if (e.isDefaultPrevented()) return
55
+
56
+ $parent.removeClass('in')
57
+
58
+ function removeElement() {
59
+ // detach from parent, fire event then clean up data
60
+ $parent.detach().trigger('closed.bs.alert').remove()
61
+ }
62
+
63
+ $.support.transition && $parent.hasClass('fade') ?
64
+ $parent
65
+ .one('bsTransitionEnd', removeElement)
66
+ .emulateTransitionEnd(150) :
67
+ removeElement()
68
+ }
69
+
70
+
71
+ // ALERT PLUGIN DEFINITION
72
+ // =======================
73
+
74
+ function Plugin(option) {
75
+ return this.each(function () {
76
+ var $this = $(this)
77
+ var data = $this.data('bs.alert')
78
+
79
+ if (!data) $this.data('bs.alert', (data = new Alert(this)))
80
+ if (typeof option == 'string') data[option].call($this)
81
+ })
82
+ }
83
+
84
+ var old = $.fn.alert
85
+
86
+ $.fn.alert = Plugin
87
+ $.fn.alert.Constructor = Alert
88
+
89
+
90
+ // ALERT NO CONFLICT
91
+ // =================
92
+
93
+ $.fn.alert.noConflict = function () {
94
+ $.fn.alert = old
95
+ return this
96
+ }
97
+
98
+
99
+ // ALERT DATA-API
100
+ // ==============
101
+
102
+ $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
103
+
104
+ }(jQuery);
105
+
106
+ /* ========================================================================
107
+ * Bootstrap: button.js v3.2.0
108
+ * http://getbootstrap.com/javascript/#buttons
109
+ * ========================================================================
110
+ * Copyright 2011-2014 Twitter, Inc.
111
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
112
+ * ======================================================================== */
113
+
114
+
115
+ +function ($) {
116
+ 'use strict';
117
+
118
+ // BUTTON PUBLIC CLASS DEFINITION
119
+ // ==============================
120
+
121
+ var Button = function (element, options) {
122
+ this.$element = $(element)
123
+ this.options = $.extend({}, Button.DEFAULTS, options)
124
+ this.isLoading = false
125
+ }
126
+
127
+ Button.VERSION = '3.2.0'
128
+
129
+ Button.DEFAULTS = {
130
+ loadingText: 'loading...'
131
+ }
132
+
133
+ Button.prototype.setState = function (state) {
134
+ var d = 'disabled'
135
+ var $el = this.$element
136
+ var val = $el.is('input') ? 'val' : 'html'
137
+ var data = $el.data()
138
+
139
+ state = state + 'Text'
140
+
141
+ if (data.resetText == null) $el.data('resetText', $el[val]())
142
+
143
+ $el[val](data[state] == null ? this.options[state] : data[state])
144
+
145
+ // push to event loop to allow forms to submit
146
+ setTimeout($.proxy(function () {
147
+ if (state == 'loadingText') {
148
+ this.isLoading = true
149
+ $el.addClass(d).attr(d, d)
150
+ } else if (this.isLoading) {
151
+ this.isLoading = false
152
+ $el.removeClass(d).removeAttr(d)
153
+ }
154
+ }, this), 0)
155
+ }
156
+
157
+ Button.prototype.toggle = function () {
158
+ var changed = true
159
+ var $parent = this.$element.closest('[data-toggle="buttons"]')
160
+
161
+ if ($parent.length) {
162
+ var $input = this.$element.find('input')
163
+ if ($input.prop('type') == 'radio') {
164
+ if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
165
+ else $parent.find('.active').removeClass('active')
166
+ }
167
+ if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
168
+ }
169
+
170
+ if (changed) this.$element.toggleClass('active')
171
+ }
172
+
173
+
174
+ // BUTTON PLUGIN DEFINITION
175
+ // ========================
176
+
177
+ function Plugin(option) {
178
+ return this.each(function () {
179
+ var $this = $(this)
180
+ var data = $this.data('bs.button')
181
+ var options = typeof option == 'object' && option
182
+
183
+ if (!data) $this.data('bs.button', (data = new Button(this, options)))
184
+
185
+ if (option == 'toggle') data.toggle()
186
+ else if (option) data.setState(option)
187
+ })
188
+ }
189
+
190
+ var old = $.fn.button
191
+
192
+ $.fn.button = Plugin
193
+ $.fn.button.Constructor = Button
194
+
195
+
196
+ // BUTTON NO CONFLICT
197
+ // ==================
198
+
199
+ $.fn.button.noConflict = function () {
200
+ $.fn.button = old
201
+ return this
202
+ }
203
+
204
+
205
+ // BUTTON DATA-API
206
+ // ===============
207
+
208
+ $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
209
+ var $btn = $(e.target)
210
+ if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
211
+ Plugin.call($btn, 'toggle')
212
+ e.preventDefault()
213
+ })
214
+
215
+ }(jQuery);
216
+
217
+ /* ========================================================================
218
+ * Bootstrap: carousel.js v3.2.0
219
+ * http://getbootstrap.com/javascript/#carousel
220
+ * ========================================================================
221
+ * Copyright 2011-2014 Twitter, Inc.
222
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
223
+ * ======================================================================== */
224
+
225
+
226
+ +function ($) {
227
+ 'use strict';
228
+
229
+ // CAROUSEL CLASS DEFINITION
230
+ // =========================
231
+
232
+ var Carousel = function (element, options) {
233
+ this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this))
234
+ this.$indicators = this.$element.find('.carousel-indicators')
235
+ this.options = options
236
+ this.paused =
237
+ this.sliding =
238
+ this.interval =
239
+ this.$active =
240
+ this.$items = null
241
+
242
+ this.options.pause == 'hover' && this.$element
243
+ .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
244
+ .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
245
+ }
246
+
247
+ Carousel.VERSION = '3.2.0'
248
+
249
+ Carousel.DEFAULTS = {
250
+ interval: 5000,
251
+ pause: 'hover',
252
+ wrap: true
253
+ }
254
+
255
+ Carousel.prototype.keydown = function (e) {
256
+ switch (e.which) {
257
+ case 37: this.prev(); break
258
+ case 39: this.next(); break
259
+ default: return
260
+ }
261
+
262
+ e.preventDefault()
263
+ }
264
+
265
+ Carousel.prototype.cycle = function (e) {
266
+ e || (this.paused = false)
267
+
268
+ this.interval && clearInterval(this.interval)
269
+
270
+ this.options.interval
271
+ && !this.paused
272
+ && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
273
+
274
+ return this
275
+ }
276
+
277
+ Carousel.prototype.getItemIndex = function (item) {
278
+ this.$items = item.parent().children('.item')
279
+ return this.$items.index(item || this.$active)
280
+ }
281
+
282
+ Carousel.prototype.to = function (pos) {
283
+ var that = this
284
+ var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
285
+
286
+ if (pos > (this.$items.length - 1) || pos < 0) return
287
+
288
+ if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
289
+ if (activeIndex == pos) return this.pause().cycle()
290
+
291
+ return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
292
+ }
293
+
294
+ Carousel.prototype.pause = function (e) {
295
+ e || (this.paused = true)
296
+
297
+ if (this.$element.find('.next, .prev').length && $.support.transition) {
298
+ this.$element.trigger($.support.transition.end)
299
+ this.cycle(true)
300
+ }
301
+
302
+ this.interval = clearInterval(this.interval)
303
+
304
+ return this
305
+ }
306
+
307
+ Carousel.prototype.next = function () {
308
+ if (this.sliding) return
309
+ return this.slide('next')
310
+ }
311
+
312
+ Carousel.prototype.prev = function () {
313
+ if (this.sliding) return
314
+ return this.slide('prev')
315
+ }
316
+
317
+ Carousel.prototype.slide = function (type, next) {
318
+ var $active = this.$element.find('.item.active')
319
+ var $next = next || $active[type]()
320
+ var isCycling = this.interval
321
+ var direction = type == 'next' ? 'left' : 'right'
322
+ var fallback = type == 'next' ? 'first' : 'last'
323
+ var that = this
324
+
325
+ if (!$next.length) {
326
+ if (!this.options.wrap) return
327
+ $next = this.$element.find('.item')[fallback]()
328
+ }
329
+
330
+ if ($next.hasClass('active')) return (this.sliding = false)
331
+
332
+ var relatedTarget = $next[0]
333
+ var slideEvent = $.Event('slide.bs.carousel', {
334
+ relatedTarget: relatedTarget,
335
+ direction: direction
336
+ })
337
+ this.$element.trigger(slideEvent)
338
+ if (slideEvent.isDefaultPrevented()) return
339
+
340
+ this.sliding = true
341
+
342
+ isCycling && this.pause()
343
+
344
+ if (this.$indicators.length) {
345
+ this.$indicators.find('.active').removeClass('active')
346
+ var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
347
+ $nextIndicator && $nextIndicator.addClass('active')
348
+ }
349
+
350
+ var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
351
+ if ($.support.transition && this.$element.hasClass('slide')) {
352
+ $next.addClass(type)
353
+ $next[0].offsetWidth // force reflow
354
+ $active.addClass(direction)
355
+ $next.addClass(direction)
356
+ $active
357
+ .one('bsTransitionEnd', function () {
358
+ $next.removeClass([type, direction].join(' ')).addClass('active')
359
+ $active.removeClass(['active', direction].join(' '))
360
+ that.sliding = false
361
+ setTimeout(function () {
362
+ that.$element.trigger(slidEvent)
363
+ }, 0)
364
+ })
365
+ .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
366
+ } else {
367
+ $active.removeClass('active')
368
+ $next.addClass('active')
369
+ this.sliding = false
370
+ this.$element.trigger(slidEvent)
371
+ }
372
+
373
+ isCycling && this.cycle()
374
+
375
+ return this
376
+ }
377
+
378
+
379
+ // CAROUSEL PLUGIN DEFINITION
380
+ // ==========================
381
+
382
+ function Plugin(option) {
383
+ return this.each(function () {
384
+ var $this = $(this)
385
+ var data = $this.data('bs.carousel')
386
+ var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
387
+ var action = typeof option == 'string' ? option : options.slide
388
+
389
+ if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
390
+ if (typeof option == 'number') data.to(option)
391
+ else if (action) data[action]()
392
+ else if (options.interval) data.pause().cycle()
393
+ })
394
+ }
395
+
396
+ var old = $.fn.carousel
397
+
398
+ $.fn.carousel = Plugin
399
+ $.fn.carousel.Constructor = Carousel
400
+
401
+
402
+ // CAROUSEL NO CONFLICT
403
+ // ====================
404
+
405
+ $.fn.carousel.noConflict = function () {
406
+ $.fn.carousel = old
407
+ return this
408
+ }
409
+
410
+
411
+ // CAROUSEL DATA-API
412
+ // =================
413
+
414
+ $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
415
+ var href
416
+ var $this = $(this)
417
+ var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
418
+ if (!$target.hasClass('carousel')) return
419
+ var options = $.extend({}, $target.data(), $this.data())
420
+ var slideIndex = $this.attr('data-slide-to')
421
+ if (slideIndex) options.interval = false
422
+
423
+ Plugin.call($target, options)
424
+
425
+ if (slideIndex) {
426
+ $target.data('bs.carousel').to(slideIndex)
427
+ }
428
+
429
+ e.preventDefault()
430
+ })
431
+
432
+ $(window).on('load', function () {
433
+ $('[data-ride="carousel"]').each(function () {
434
+ var $carousel = $(this)
435
+ Plugin.call($carousel, $carousel.data())
436
+ })
437
+ })
438
+
439
+ }(jQuery);
440
+
441
+ /* ========================================================================
442
+ * Bootstrap: dropdown.js v3.2.0
443
+ * http://getbootstrap.com/javascript/#dropdowns
444
+ * ========================================================================
445
+ * Copyright 2011-2014 Twitter, Inc.
446
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
447
+ * ======================================================================== */
448
+
449
+
450
+ +function ($) {
451
+ 'use strict';
452
+
453
+ // DROPDOWN CLASS DEFINITION
454
+ // =========================
455
+
456
+ var backdrop = '.dropdown-backdrop'
457
+ var toggle = '[data-toggle="dropdown"]'
458
+ var Dropdown = function (element) {
459
+ $(element).on('click.bs.dropdown', this.toggle)
460
+ }
461
+
462
+ Dropdown.VERSION = '3.2.0'
463
+
464
+ Dropdown.prototype.toggle = function (e) {
465
+ var $this = $(this)
466
+
467
+ if ($this.is('.disabled, :disabled')) return
468
+
469
+ var $parent = getParent($this)
470
+ var isActive = $parent.hasClass('open')
471
+
472
+ clearMenus()
473
+
474
+ if (!isActive) {
475
+ if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
476
+ // if mobile we use a backdrop because click events don't delegate
477
+ $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
478
+ }
479
+
480
+ var relatedTarget = { relatedTarget: this }
481
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
482
+
483
+ if (e.isDefaultPrevented()) return
484
+
485
+ $this.trigger('focus')
486
+
487
+ $parent
488
+ .toggleClass('open')
489
+ .trigger('shown.bs.dropdown', relatedTarget)
490
+ }
491
+
492
+ return false
493
+ }
494
+
495
+ Dropdown.prototype.keydown = function (e) {
496
+ if (!/(38|40|27)/.test(e.keyCode)) return
497
+
498
+ var $this = $(this)
499
+
500
+ e.preventDefault()
501
+ e.stopPropagation()
502
+
503
+ if ($this.is('.disabled, :disabled')) return
504
+
505
+ var $parent = getParent($this)
506
+ var isActive = $parent.hasClass('open')
507
+
508
+ if (!isActive || (isActive && e.keyCode == 27)) {
509
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
510
+ return $this.trigger('click')
511
+ }
512
+
513
+ var desc = ' li:not(.divider):visible a'
514
+ var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
515
+
516
+ if (!$items.length) return
517
+
518
+ var index = $items.index($items.filter(':focus'))
519
+
520
+ if (e.keyCode == 38 && index > 0) index-- // up
521
+ if (e.keyCode == 40 && index < $items.length - 1) index++ // down
522
+ if (!~index) index = 0
523
+
524
+ $items.eq(index).trigger('focus')
525
+ }
526
+
527
+ function clearMenus(e) {
528
+ if (e && e.which === 3) return
529
+ $(backdrop).remove()
530
+ $(toggle).each(function () {
531
+ var $parent = getParent($(this))
532
+ var relatedTarget = { relatedTarget: this }
533
+ if (!$parent.hasClass('open')) return
534
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
535
+ if (e.isDefaultPrevented()) return
536
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
537
+ })
538
+ }
539
+
540
+ function getParent($this) {
541
+ var selector = $this.attr('data-target')
542
+
543
+ if (!selector) {
544
+ selector = $this.attr('href')
545
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
546
+ }
547
+
548
+ var $parent = selector && $(selector)
549
+
550
+ return $parent && $parent.length ? $parent : $this.parent()
551
+ }
552
+
553
+
554
+ // DROPDOWN PLUGIN DEFINITION
555
+ // ==========================
556
+
557
+ function Plugin(option) {
558
+ return this.each(function () {
559
+ var $this = $(this)
560
+ var data = $this.data('bs.dropdown')
561
+
562
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
563
+ if (typeof option == 'string') data[option].call($this)
564
+ })
565
+ }
566
+
567
+ var old = $.fn.dropdown
568
+
569
+ $.fn.dropdown = Plugin
570
+ $.fn.dropdown.Constructor = Dropdown
571
+
572
+
573
+ // DROPDOWN NO CONFLICT
574
+ // ====================
575
+
576
+ $.fn.dropdown.noConflict = function () {
577
+ $.fn.dropdown = old
578
+ return this
579
+ }
580
+
581
+
582
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
583
+ // ===================================
584
+
585
+ $(document)
586
+ .on('click.bs.dropdown.data-api', clearMenus)
587
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
588
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
589
+ .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
590
+
591
+ }(jQuery);
592
+
593
+ /* ========================================================================
594
+ * Bootstrap: modal.js v3.2.0
595
+ * http://getbootstrap.com/javascript/#modals
596
+ * ========================================================================
597
+ * Copyright 2011-2014 Twitter, Inc.
598
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
599
+ * ======================================================================== */
600
+
601
+
602
+ +function ($) {
603
+ 'use strict';
604
+
605
+ // MODAL CLASS DEFINITION
606
+ // ======================
607
+
608
+ var Modal = function (element, options) {
609
+ this.options = options
610
+ this.$body = $(document.body)
611
+ this.$element = $(element)
612
+ this.$backdrop =
613
+ this.isShown = null
614
+ this.scrollbarWidth = 0
615
+
616
+ if (this.options.remote) {
617
+ this.$element
618
+ .find('.modal-content')
619
+ .load(this.options.remote, $.proxy(function () {
620
+ this.$element.trigger('loaded.bs.modal')
621
+ }, this))
622
+ }
623
+ }
624
+
625
+ Modal.VERSION = '3.2.0'
626
+
627
+ Modal.DEFAULTS = {
628
+ backdrop: true,
629
+ keyboard: true,
630
+ show: true
631
+ }
632
+
633
+ Modal.prototype.toggle = function (_relatedTarget) {
634
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
635
+ }
636
+
637
+ Modal.prototype.show = function (_relatedTarget) {
638
+ var that = this
639
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
640
+
641
+ this.$element.trigger(e)
642
+
643
+ if (this.isShown || e.isDefaultPrevented()) return
644
+
645
+ this.isShown = true
646
+
647
+ this.checkScrollbar()
648
+ this.$body.addClass('modal-open')
649
+
650
+ this.setScrollbar()
651
+ this.escape()
652
+
653
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
654
+
655
+ this.backdrop(function () {
656
+ var transition = $.support.transition && that.$element.hasClass('fade')
657
+
658
+ if (!that.$element.parent().length) {
659
+ that.$element.appendTo(that.$body) // don't move modals dom position
660
+ }
661
+
662
+ that.$element
663
+ .show()
664
+ .scrollTop(0)
665
+
666
+ if (transition) {
667
+ that.$element[0].offsetWidth // force reflow
668
+ }
669
+
670
+ that.$element
671
+ .addClass('in')
672
+ .attr('aria-hidden', false)
673
+
674
+ that.enforceFocus()
675
+
676
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
677
+
678
+ transition ?
679
+ that.$element.find('.modal-dialog') // wait for modal to slide in
680
+ .one('bsTransitionEnd', function () {
681
+ that.$element.trigger('focus').trigger(e)
682
+ })
683
+ .emulateTransitionEnd(300) :
684
+ that.$element.trigger('focus').trigger(e)
685
+ })
686
+ }
687
+
688
+ Modal.prototype.hide = function (e) {
689
+ if (e) e.preventDefault()
690
+
691
+ e = $.Event('hide.bs.modal')
692
+
693
+ this.$element.trigger(e)
694
+
695
+ if (!this.isShown || e.isDefaultPrevented()) return
696
+
697
+ this.isShown = false
698
+
699
+ this.$body.removeClass('modal-open')
700
+
701
+ this.resetScrollbar()
702
+ this.escape()
703
+
704
+ $(document).off('focusin.bs.modal')
705
+
706
+ this.$element
707
+ .removeClass('in')
708
+ .attr('aria-hidden', true)
709
+ .off('click.dismiss.bs.modal')
710
+
711
+ $.support.transition && this.$element.hasClass('fade') ?
712
+ this.$element
713
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
714
+ .emulateTransitionEnd(300) :
715
+ this.hideModal()
716
+ }
717
+
718
+ Modal.prototype.enforceFocus = function () {
719
+ $(document)
720
+ .off('focusin.bs.modal') // guard against infinite focus loop
721
+ .on('focusin.bs.modal', $.proxy(function (e) {
722
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
723
+ this.$element.trigger('focus')
724
+ }
725
+ }, this))
726
+ }
727
+
728
+ Modal.prototype.escape = function () {
729
+ if (this.isShown && this.options.keyboard) {
730
+ this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
731
+ e.which == 27 && this.hide()
732
+ }, this))
733
+ } else if (!this.isShown) {
734
+ this.$element.off('keyup.dismiss.bs.modal')
735
+ }
736
+ }
737
+
738
+ Modal.prototype.hideModal = function () {
739
+ var that = this
740
+ this.$element.hide()
741
+ this.backdrop(function () {
742
+ that.$element.trigger('hidden.bs.modal')
743
+ })
744
+ }
745
+
746
+ Modal.prototype.removeBackdrop = function () {
747
+ this.$backdrop && this.$backdrop.remove()
748
+ this.$backdrop = null
749
+ }
750
+
751
+ Modal.prototype.backdrop = function (callback) {
752
+ var that = this
753
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
754
+
755
+ if (this.isShown && this.options.backdrop) {
756
+ var doAnimate = $.support.transition && animate
757
+
758
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
759
+ .appendTo(this.$body)
760
+
761
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
762
+ if (e.target !== e.currentTarget) return
763
+ this.options.backdrop == 'static'
764
+ ? this.$element[0].focus.call(this.$element[0])
765
+ : this.hide.call(this)
766
+ }, this))
767
+
768
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
769
+
770
+ this.$backdrop.addClass('in')
771
+
772
+ if (!callback) return
773
+
774
+ doAnimate ?
775
+ this.$backdrop
776
+ .one('bsTransitionEnd', callback)
777
+ .emulateTransitionEnd(150) :
778
+ callback()
779
+
780
+ } else if (!this.isShown && this.$backdrop) {
781
+ this.$backdrop.removeClass('in')
782
+
783
+ var callbackRemove = function () {
784
+ that.removeBackdrop()
785
+ callback && callback()
786
+ }
787
+ $.support.transition && this.$element.hasClass('fade') ?
788
+ this.$backdrop
789
+ .one('bsTransitionEnd', callbackRemove)
790
+ .emulateTransitionEnd(150) :
791
+ callbackRemove()
792
+
793
+ } else if (callback) {
794
+ callback()
795
+ }
796
+ }
797
+
798
+ Modal.prototype.checkScrollbar = function () {
799
+ if (document.body.clientWidth >= window.innerWidth) return
800
+ this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
801
+ }
802
+
803
+ Modal.prototype.setScrollbar = function () {
804
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
805
+ if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
806
+ }
807
+
808
+ Modal.prototype.resetScrollbar = function () {
809
+ this.$body.css('padding-right', '')
810
+ }
811
+
812
+ Modal.prototype.measureScrollbar = function () { // thx walsh
813
+ var scrollDiv = document.createElement('div')
814
+ scrollDiv.className = 'modal-scrollbar-measure'
815
+ this.$body.append(scrollDiv)
816
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
817
+ this.$body[0].removeChild(scrollDiv)
818
+ return scrollbarWidth
819
+ }
820
+
821
+
822
+ // MODAL PLUGIN DEFINITION
823
+ // =======================
824
+
825
+ function Plugin(option, _relatedTarget) {
826
+ return this.each(function () {
827
+ var $this = $(this)
828
+ var data = $this.data('bs.modal')
829
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
830
+
831
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
832
+ if (typeof option == 'string') data[option](_relatedTarget)
833
+ else if (options.show) data.show(_relatedTarget)
834
+ })
835
+ }
836
+
837
+ var old = $.fn.modal
838
+
839
+ $.fn.modal = Plugin
840
+ $.fn.modal.Constructor = Modal
841
+
842
+
843
+ // MODAL NO CONFLICT
844
+ // =================
845
+
846
+ $.fn.modal.noConflict = function () {
847
+ $.fn.modal = old
848
+ return this
849
+ }
850
+
851
+
852
+ // MODAL DATA-API
853
+ // ==============
854
+
855
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
856
+ var $this = $(this)
857
+ var href = $this.attr('href')
858
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
859
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
860
+
861
+ if ($this.is('a')) e.preventDefault()
862
+
863
+ $target.one('show.bs.modal', function (showEvent) {
864
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
865
+ $target.one('hidden.bs.modal', function () {
866
+ $this.is(':visible') && $this.trigger('focus')
867
+ })
868
+ })
869
+ Plugin.call($target, option, this)
870
+ })
871
+
872
+ }(jQuery);
873
+
874
+ /* ========================================================================
875
+ * Bootstrap: tooltip.js v3.2.0
876
+ * http://getbootstrap.com/javascript/#tooltip
877
+ * Inspired by the original jQuery.tipsy by Jason Frame
878
+ * ========================================================================
879
+ * Copyright 2011-2014 Twitter, Inc.
880
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
881
+ * ======================================================================== */
882
+
883
+
884
+ +function ($) {
885
+ 'use strict';
886
+
887
+ // TOOLTIP PUBLIC CLASS DEFINITION
888
+ // ===============================
889
+
890
+ var Tooltip = function (element, options) {
891
+ this.type =
892
+ this.options =
893
+ this.enabled =
894
+ this.timeout =
895
+ this.hoverState =
896
+ this.$element = null
897
+
898
+ this.init('tooltip', element, options)
899
+ }
900
+
901
+ Tooltip.VERSION = '3.2.0'
902
+
903
+ Tooltip.DEFAULTS = {
904
+ animation: true,
905
+ placement: 'top',
906
+ selector: false,
907
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
908
+ trigger: 'hover focus',
909
+ title: '',
910
+ delay: 0,
911
+ html: false,
912
+ container: false,
913
+ viewport: {
914
+ selector: 'body',
915
+ padding: 0
916
+ }
917
+ }
918
+
919
+ Tooltip.prototype.init = function (type, element, options) {
920
+ this.enabled = true
921
+ this.type = type
922
+ this.$element = $(element)
923
+ this.options = this.getOptions(options)
924
+ this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
925
+
926
+ var triggers = this.options.trigger.split(' ')
927
+
928
+ for (var i = triggers.length; i--;) {
929
+ var trigger = triggers[i]
930
+
931
+ if (trigger == 'click') {
932
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
933
+ } else if (trigger != 'manual') {
934
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
935
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
936
+
937
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
938
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
939
+ }
940
+ }
941
+
942
+ this.options.selector ?
943
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
944
+ this.fixTitle()
945
+ }
946
+
947
+ Tooltip.prototype.getDefaults = function () {
948
+ return Tooltip.DEFAULTS
949
+ }
950
+
951
+ Tooltip.prototype.getOptions = function (options) {
952
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
953
+
954
+ if (options.delay && typeof options.delay == 'number') {
955
+ options.delay = {
956
+ show: options.delay,
957
+ hide: options.delay
958
+ }
959
+ }
960
+
961
+ return options
962
+ }
963
+
964
+ Tooltip.prototype.getDelegateOptions = function () {
965
+ var options = {}
966
+ var defaults = this.getDefaults()
967
+
968
+ this._options && $.each(this._options, function (key, value) {
969
+ if (defaults[key] != value) options[key] = value
970
+ })
971
+
972
+ return options
973
+ }
974
+
975
+ Tooltip.prototype.enter = function (obj) {
976
+ var self = obj instanceof this.constructor ?
977
+ obj : $(obj.currentTarget).data('bs.' + this.type)
978
+
979
+ if (!self) {
980
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
981
+ $(obj.currentTarget).data('bs.' + this.type, self)
982
+ }
983
+
984
+ clearTimeout(self.timeout)
985
+
986
+ self.hoverState = 'in'
987
+
988
+ if (!self.options.delay || !self.options.delay.show) return self.show()
989
+
990
+ self.timeout = setTimeout(function () {
991
+ if (self.hoverState == 'in') self.show()
992
+ }, self.options.delay.show)
993
+ }
994
+
995
+ Tooltip.prototype.leave = function (obj) {
996
+ var self = obj instanceof this.constructor ?
997
+ obj : $(obj.currentTarget).data('bs.' + this.type)
998
+
999
+ if (!self) {
1000
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
1001
+ $(obj.currentTarget).data('bs.' + this.type, self)
1002
+ }
1003
+
1004
+ clearTimeout(self.timeout)
1005
+
1006
+ self.hoverState = 'out'
1007
+
1008
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
1009
+
1010
+ self.timeout = setTimeout(function () {
1011
+ if (self.hoverState == 'out') self.hide()
1012
+ }, self.options.delay.hide)
1013
+ }
1014
+
1015
+ Tooltip.prototype.show = function () {
1016
+ var e = $.Event('show.bs.' + this.type)
1017
+
1018
+ if (this.hasContent() && this.enabled) {
1019
+ this.$element.trigger(e)
1020
+
1021
+ var inDom = $.contains(document.documentElement, this.$element[0])
1022
+ if (e.isDefaultPrevented() || !inDom) return
1023
+ var that = this
1024
+
1025
+ var $tip = this.tip()
1026
+
1027
+ var tipId = this.getUID(this.type)
1028
+
1029
+ this.setContent()
1030
+ $tip.attr('id', tipId)
1031
+ this.$element.attr('aria-describedby', tipId)
1032
+
1033
+ if (this.options.animation) $tip.addClass('fade')
1034
+
1035
+ var placement = typeof this.options.placement == 'function' ?
1036
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
1037
+ this.options.placement
1038
+
1039
+ var autoToken = /\s?auto?\s?/i
1040
+ var autoPlace = autoToken.test(placement)
1041
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
1042
+
1043
+ $tip
1044
+ .detach()
1045
+ .css({ top: 0, left: 0, display: 'block' })
1046
+ .addClass(placement)
1047
+ .data('bs.' + this.type, this)
1048
+
1049
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
1050
+
1051
+ var pos = this.getPosition()
1052
+ var actualWidth = $tip[0].offsetWidth
1053
+ var actualHeight = $tip[0].offsetHeight
1054
+
1055
+ if (autoPlace) {
1056
+ var orgPlacement = placement
1057
+ var $parent = this.$element.parent()
1058
+ var parentDim = this.getPosition($parent)
1059
+
1060
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
1061
+ placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
1062
+ placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
1063
+ placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
1064
+ placement
1065
+
1066
+ $tip
1067
+ .removeClass(orgPlacement)
1068
+ .addClass(placement)
1069
+ }
1070
+
1071
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
1072
+
1073
+ this.applyPlacement(calculatedOffset, placement)
1074
+
1075
+ var complete = function () {
1076
+ that.$element.trigger('shown.bs.' + that.type)
1077
+ that.hoverState = null
1078
+ }
1079
+
1080
+ $.support.transition && this.$tip.hasClass('fade') ?
1081
+ $tip
1082
+ .one('bsTransitionEnd', complete)
1083
+ .emulateTransitionEnd(150) :
1084
+ complete()
1085
+ }
1086
+ }
1087
+
1088
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
1089
+ var $tip = this.tip()
1090
+ var width = $tip[0].offsetWidth
1091
+ var height = $tip[0].offsetHeight
1092
+
1093
+ // manually read margins because getBoundingClientRect includes difference
1094
+ var marginTop = parseInt($tip.css('margin-top'), 10)
1095
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
1096
+
1097
+ // we must check for NaN for ie 8/9
1098
+ if (isNaN(marginTop)) marginTop = 0
1099
+ if (isNaN(marginLeft)) marginLeft = 0
1100
+
1101
+ offset.top = offset.top + marginTop
1102
+ offset.left = offset.left + marginLeft
1103
+
1104
+ // $.fn.offset doesn't round pixel values
1105
+ // so we use setOffset directly with our own function B-0
1106
+ $.offset.setOffset($tip[0], $.extend({
1107
+ using: function (props) {
1108
+ $tip.css({
1109
+ top: Math.round(props.top),
1110
+ left: Math.round(props.left)
1111
+ })
1112
+ }
1113
+ }, offset), 0)
1114
+
1115
+ $tip.addClass('in')
1116
+
1117
+ // check to see if placing tip in new offset caused the tip to resize itself
1118
+ var actualWidth = $tip[0].offsetWidth
1119
+ var actualHeight = $tip[0].offsetHeight
1120
+
1121
+ if (placement == 'top' && actualHeight != height) {
1122
+ offset.top = offset.top + height - actualHeight
1123
+ }
1124
+
1125
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
1126
+
1127
+ if (delta.left) offset.left += delta.left
1128
+ else offset.top += delta.top
1129
+
1130
+ var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
1131
+ var arrowPosition = delta.left ? 'left' : 'top'
1132
+ var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
1133
+
1134
+ $tip.offset(offset)
1135
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
1136
+ }
1137
+
1138
+ Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
1139
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
1140
+ }
1141
+
1142
+ Tooltip.prototype.setContent = function () {
1143
+ var $tip = this.tip()
1144
+ var title = this.getTitle()
1145
+
1146
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
1147
+ $tip.removeClass('fade in top bottom left right')
1148
+ }
1149
+
1150
+ Tooltip.prototype.hide = function () {
1151
+ var that = this
1152
+ var $tip = this.tip()
1153
+ var e = $.Event('hide.bs.' + this.type)
1154
+
1155
+ this.$element.removeAttr('aria-describedby')
1156
+
1157
+ function complete() {
1158
+ if (that.hoverState != 'in') $tip.detach()
1159
+ that.$element.trigger('hidden.bs.' + that.type)
1160
+ }
1161
+
1162
+ this.$element.trigger(e)
1163
+
1164
+ if (e.isDefaultPrevented()) return
1165
+
1166
+ $tip.removeClass('in')
1167
+
1168
+ $.support.transition && this.$tip.hasClass('fade') ?
1169
+ $tip
1170
+ .one('bsTransitionEnd', complete)
1171
+ .emulateTransitionEnd(150) :
1172
+ complete()
1173
+
1174
+ this.hoverState = null
1175
+
1176
+ return this
1177
+ }
1178
+
1179
+ Tooltip.prototype.fixTitle = function () {
1180
+ var $e = this.$element
1181
+ if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
1182
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
1183
+ }
1184
+ }
1185
+
1186
+ Tooltip.prototype.hasContent = function () {
1187
+ return this.getTitle()
1188
+ }
1189
+
1190
+ Tooltip.prototype.getPosition = function ($element) {
1191
+ $element = $element || this.$element
1192
+ var el = $element[0]
1193
+ var isBody = el.tagName == 'BODY'
1194
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
1195
+ scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
1196
+ width: isBody ? $(window).width() : $element.outerWidth(),
1197
+ height: isBody ? $(window).height() : $element.outerHeight()
1198
+ }, isBody ? { top: 0, left: 0 } : $element.offset())
1199
+ }
1200
+
1201
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
1202
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1203
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
1204
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
1205
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
1206
+
1207
+ }
1208
+
1209
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
1210
+ var delta = { top: 0, left: 0 }
1211
+ if (!this.$viewport) return delta
1212
+
1213
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
1214
+ var viewportDimensions = this.getPosition(this.$viewport)
1215
+
1216
+ if (/right|left/.test(placement)) {
1217
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
1218
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
1219
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
1220
+ delta.top = viewportDimensions.top - topEdgeOffset
1221
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
1222
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
1223
+ }
1224
+ } else {
1225
+ var leftEdgeOffset = pos.left - viewportPadding
1226
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
1227
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
1228
+ delta.left = viewportDimensions.left - leftEdgeOffset
1229
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
1230
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
1231
+ }
1232
+ }
1233
+
1234
+ return delta
1235
+ }
1236
+
1237
+ Tooltip.prototype.getTitle = function () {
1238
+ var title
1239
+ var $e = this.$element
1240
+ var o = this.options
1241
+
1242
+ title = $e.attr('data-original-title')
1243
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
1244
+
1245
+ return title
1246
+ }
1247
+
1248
+ Tooltip.prototype.getUID = function (prefix) {
1249
+ do prefix += ~~(Math.random() * 1000000)
1250
+ while (document.getElementById(prefix))
1251
+ return prefix
1252
+ }
1253
+
1254
+ Tooltip.prototype.tip = function () {
1255
+ return (this.$tip = this.$tip || $(this.options.template))
1256
+ }
1257
+
1258
+ Tooltip.prototype.arrow = function () {
1259
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
1260
+ }
1261
+
1262
+ Tooltip.prototype.validate = function () {
1263
+ if (!this.$element[0].parentNode) {
1264
+ this.hide()
1265
+ this.$element = null
1266
+ this.options = null
1267
+ }
1268
+ }
1269
+
1270
+ Tooltip.prototype.enable = function () {
1271
+ this.enabled = true
1272
+ }
1273
+
1274
+ Tooltip.prototype.disable = function () {
1275
+ this.enabled = false
1276
+ }
1277
+
1278
+ Tooltip.prototype.toggleEnabled = function () {
1279
+ this.enabled = !this.enabled
1280
+ }
1281
+
1282
+ Tooltip.prototype.toggle = function (e) {
1283
+ var self = this
1284
+ if (e) {
1285
+ self = $(e.currentTarget).data('bs.' + this.type)
1286
+ if (!self) {
1287
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
1288
+ $(e.currentTarget).data('bs.' + this.type, self)
1289
+ }
1290
+ }
1291
+
1292
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
1293
+ }
1294
+
1295
+ Tooltip.prototype.destroy = function () {
1296
+ clearTimeout(this.timeout)
1297
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
1298
+ }
1299
+
1300
+
1301
+ // TOOLTIP PLUGIN DEFINITION
1302
+ // =========================
1303
+
1304
+ function Plugin(option) {
1305
+ return this.each(function () {
1306
+ var $this = $(this)
1307
+ var data = $this.data('bs.tooltip')
1308
+ var options = typeof option == 'object' && option
1309
+
1310
+ if (!data && option == 'destroy') return
1311
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
1312
+ if (typeof option == 'string') data[option]()
1313
+ })
1314
+ }
1315
+
1316
+ var old = $.fn.tooltip
1317
+
1318
+ $.fn.tooltip = Plugin
1319
+ $.fn.tooltip.Constructor = Tooltip
1320
+
1321
+
1322
+ // TOOLTIP NO CONFLICT
1323
+ // ===================
1324
+
1325
+ $.fn.tooltip.noConflict = function () {
1326
+ $.fn.tooltip = old
1327
+ return this
1328
+ }
1329
+
1330
+ }(jQuery);
1331
+
1332
+ /* ========================================================================
1333
+ * Bootstrap: popover.js v3.2.0
1334
+ * http://getbootstrap.com/javascript/#popovers
1335
+ * ========================================================================
1336
+ * Copyright 2011-2014 Twitter, Inc.
1337
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1338
+ * ======================================================================== */
1339
+
1340
+
1341
+ +function ($) {
1342
+ 'use strict';
1343
+
1344
+ // POPOVER PUBLIC CLASS DEFINITION
1345
+ // ===============================
1346
+
1347
+ var Popover = function (element, options) {
1348
+ this.init('popover', element, options)
1349
+ }
1350
+
1351
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
1352
+
1353
+ Popover.VERSION = '3.2.0'
1354
+
1355
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
1356
+ placement: 'right',
1357
+ trigger: 'click',
1358
+ content: '',
1359
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1360
+ })
1361
+
1362
+
1363
+ // NOTE: POPOVER EXTENDS tooltip.js
1364
+ // ================================
1365
+
1366
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
1367
+
1368
+ Popover.prototype.constructor = Popover
1369
+
1370
+ Popover.prototype.getDefaults = function () {
1371
+ return Popover.DEFAULTS
1372
+ }
1373
+
1374
+ Popover.prototype.setContent = function () {
1375
+ var $tip = this.tip()
1376
+ var title = this.getTitle()
1377
+ var content = this.getContent()
1378
+
1379
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
1380
+ $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
1381
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
1382
+ ](content)
1383
+
1384
+ $tip.removeClass('fade top bottom left right in')
1385
+
1386
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
1387
+ // this manually by checking the contents.
1388
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
1389
+ }
1390
+
1391
+ Popover.prototype.hasContent = function () {
1392
+ return this.getTitle() || this.getContent()
1393
+ }
1394
+
1395
+ Popover.prototype.getContent = function () {
1396
+ var $e = this.$element
1397
+ var o = this.options
1398
+
1399
+ return $e.attr('data-content')
1400
+ || (typeof o.content == 'function' ?
1401
+ o.content.call($e[0]) :
1402
+ o.content)
1403
+ }
1404
+
1405
+ Popover.prototype.arrow = function () {
1406
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
1407
+ }
1408
+
1409
+ Popover.prototype.tip = function () {
1410
+ if (!this.$tip) this.$tip = $(this.options.template)
1411
+ return this.$tip
1412
+ }
1413
+
1414
+
1415
+ // POPOVER PLUGIN DEFINITION
1416
+ // =========================
1417
+
1418
+ function Plugin(option) {
1419
+ return this.each(function () {
1420
+ var $this = $(this)
1421
+ var data = $this.data('bs.popover')
1422
+ var options = typeof option == 'object' && option
1423
+
1424
+ if (!data && option == 'destroy') return
1425
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
1426
+ if (typeof option == 'string') data[option]()
1427
+ })
1428
+ }
1429
+
1430
+ var old = $.fn.popover
1431
+
1432
+ $.fn.popover = Plugin
1433
+ $.fn.popover.Constructor = Popover
1434
+
1435
+
1436
+ // POPOVER NO CONFLICT
1437
+ // ===================
1438
+
1439
+ $.fn.popover.noConflict = function () {
1440
+ $.fn.popover = old
1441
+ return this
1442
+ }
1443
+
1444
+ }(jQuery);
1445
+
1446
+ /* ========================================================================
1447
+ * Bootstrap: tab.js v3.2.0
1448
+ * http://getbootstrap.com/javascript/#tabs
1449
+ * ========================================================================
1450
+ * Copyright 2011-2014 Twitter, Inc.
1451
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1452
+ * ======================================================================== */
1453
+
1454
+
1455
+ +function ($) {
1456
+ 'use strict';
1457
+
1458
+ // TAB CLASS DEFINITION
1459
+ // ====================
1460
+
1461
+ var Tab = function (element) {
1462
+ this.element = $(element)
1463
+ }
1464
+
1465
+ Tab.VERSION = '3.2.0'
1466
+
1467
+ Tab.prototype.show = function () {
1468
+ var $this = this.element
1469
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
1470
+ var selector = $this.data('target')
1471
+
1472
+ if (!selector) {
1473
+ selector = $this.attr('href')
1474
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
1475
+ }
1476
+
1477
+ if ($this.parent('li').hasClass('active')) return
1478
+
1479
+ var previous = $ul.find('.active:last a')[0]
1480
+ var e = $.Event('show.bs.tab', {
1481
+ relatedTarget: previous
1482
+ })
1483
+
1484
+ $this.trigger(e)
1485
+
1486
+ if (e.isDefaultPrevented()) return
1487
+
1488
+ var $target = $(selector)
1489
+
1490
+ this.activate($this.closest('li'), $ul)
1491
+ this.activate($target, $target.parent(), function () {
1492
+ $this.trigger({
1493
+ type: 'shown.bs.tab',
1494
+ relatedTarget: previous
1495
+ })
1496
+ })
1497
+ }
1498
+
1499
+ Tab.prototype.activate = function (element, container, callback) {
1500
+ var $active = container.find('> .active')
1501
+ var transition = callback
1502
+ && $.support.transition
1503
+ && $active.hasClass('fade')
1504
+
1505
+ function next() {
1506
+ $active
1507
+ .removeClass('active')
1508
+ .find('> .dropdown-menu > .active')
1509
+ .removeClass('active')
1510
+
1511
+ element.addClass('active')
1512
+
1513
+ if (transition) {
1514
+ element[0].offsetWidth // reflow for transition
1515
+ element.addClass('in')
1516
+ } else {
1517
+ element.removeClass('fade')
1518
+ }
1519
+
1520
+ if (element.parent('.dropdown-menu')) {
1521
+ element.closest('li.dropdown').addClass('active')
1522
+ }
1523
+
1524
+ callback && callback()
1525
+ }
1526
+
1527
+ transition ?
1528
+ $active
1529
+ .one('bsTransitionEnd', next)
1530
+ .emulateTransitionEnd(150) :
1531
+ next()
1532
+
1533
+ $active.removeClass('in')
1534
+ }
1535
+
1536
+
1537
+ // TAB PLUGIN DEFINITION
1538
+ // =====================
1539
+
1540
+ function Plugin(option) {
1541
+ return this.each(function () {
1542
+ var $this = $(this)
1543
+ var data = $this.data('bs.tab')
1544
+
1545
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
1546
+ if (typeof option == 'string') data[option]()
1547
+ })
1548
+ }
1549
+
1550
+ var old = $.fn.tab
1551
+
1552
+ $.fn.tab = Plugin
1553
+ $.fn.tab.Constructor = Tab
1554
+
1555
+
1556
+ // TAB NO CONFLICT
1557
+ // ===============
1558
+
1559
+ $.fn.tab.noConflict = function () {
1560
+ $.fn.tab = old
1561
+ return this
1562
+ }
1563
+
1564
+
1565
+ // TAB DATA-API
1566
+ // ============
1567
+
1568
+ $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
1569
+ e.preventDefault()
1570
+ Plugin.call($(this), 'show')
1571
+ })
1572
+
1573
+ }(jQuery);
1574
+
1575
+ /* ========================================================================
1576
+ * Bootstrap: affix.js v3.2.0
1577
+ * http://getbootstrap.com/javascript/#affix
1578
+ * ========================================================================
1579
+ * Copyright 2011-2014 Twitter, Inc.
1580
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1581
+ * ======================================================================== */
1582
+
1583
+
1584
+ +function ($) {
1585
+ 'use strict';
1586
+
1587
+ // AFFIX CLASS DEFINITION
1588
+ // ======================
1589
+
1590
+ var Affix = function (element, options) {
1591
+ this.options = $.extend({}, Affix.DEFAULTS, options)
1592
+
1593
+ this.$target = $(this.options.target)
1594
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
1595
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
1596
+
1597
+ this.$element = $(element)
1598
+ this.affixed =
1599
+ this.unpin =
1600
+ this.pinnedOffset = null
1601
+
1602
+ this.checkPosition()
1603
+ }
1604
+
1605
+ Affix.VERSION = '3.2.0'
1606
+
1607
+ Affix.RESET = 'affix affix-top affix-bottom'
1608
+
1609
+ Affix.DEFAULTS = {
1610
+ offset: 0,
1611
+ target: window
1612
+ }
1613
+
1614
+ Affix.prototype.getPinnedOffset = function () {
1615
+ if (this.pinnedOffset) return this.pinnedOffset
1616
+ this.$element.removeClass(Affix.RESET).addClass('affix')
1617
+ var scrollTop = this.$target.scrollTop()
1618
+ var position = this.$element.offset()
1619
+ return (this.pinnedOffset = position.top - scrollTop)
1620
+ }
1621
+
1622
+ Affix.prototype.checkPositionWithEventLoop = function () {
1623
+ setTimeout($.proxy(this.checkPosition, this), 1)
1624
+ }
1625
+
1626
+ Affix.prototype.checkPosition = function () {
1627
+ if (!this.$element.is(':visible')) return
1628
+
1629
+ var scrollHeight = $(document).height()
1630
+ var scrollTop = this.$target.scrollTop()
1631
+ var position = this.$element.offset()
1632
+ var offset = this.options.offset
1633
+ var offsetTop = offset.top
1634
+ var offsetBottom = offset.bottom
1635
+
1636
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
1637
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
1638
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
1639
+
1640
+ var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
1641
+ offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
1642
+ offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
1643
+
1644
+ if (this.affixed === affix) return
1645
+ if (this.unpin != null) this.$element.css('top', '')
1646
+
1647
+ var affixType = 'affix' + (affix ? '-' + affix : '')
1648
+ var e = $.Event(affixType + '.bs.affix')
1649
+
1650
+ this.$element.trigger(e)
1651
+
1652
+ if (e.isDefaultPrevented()) return
1653
+
1654
+ this.affixed = affix
1655
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
1656
+
1657
+ this.$element
1658
+ .removeClass(Affix.RESET)
1659
+ .addClass(affixType)
1660
+ .trigger($.Event(affixType.replace('affix', 'affixed')))
1661
+
1662
+ if (affix == 'bottom') {
1663
+ this.$element.offset({
1664
+ top: scrollHeight - this.$element.height() - offsetBottom
1665
+ })
1666
+ }
1667
+ }
1668
+
1669
+
1670
+ // AFFIX PLUGIN DEFINITION
1671
+ // =======================
1672
+
1673
+ function Plugin(option) {
1674
+ return this.each(function () {
1675
+ var $this = $(this)
1676
+ var data = $this.data('bs.affix')
1677
+ var options = typeof option == 'object' && option
1678
+
1679
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
1680
+ if (typeof option == 'string') data[option]()
1681
+ })
1682
+ }
1683
+
1684
+ var old = $.fn.affix
1685
+
1686
+ $.fn.affix = Plugin
1687
+ $.fn.affix.Constructor = Affix
1688
+
1689
+
1690
+ // AFFIX NO CONFLICT
1691
+ // =================
1692
+
1693
+ $.fn.affix.noConflict = function () {
1694
+ $.fn.affix = old
1695
+ return this
1696
+ }
1697
+
1698
+
1699
+ // AFFIX DATA-API
1700
+ // ==============
1701
+
1702
+ $(window).on('load', function () {
1703
+ $('[data-spy="affix"]').each(function () {
1704
+ var $spy = $(this)
1705
+ var data = $spy.data()
1706
+
1707
+ data.offset = data.offset || {}
1708
+
1709
+ if (data.offsetBottom) data.offset.bottom = data.offsetBottom
1710
+ if (data.offsetTop) data.offset.top = data.offsetTop
1711
+
1712
+ Plugin.call($spy, data)
1713
+ })
1714
+ })
1715
+
1716
+ }(jQuery);
1717
+
1718
+ /* ========================================================================
1719
+ * Bootstrap: collapse.js v3.2.0
1720
+ * http://getbootstrap.com/javascript/#collapse
1721
+ * ========================================================================
1722
+ * Copyright 2011-2014 Twitter, Inc.
1723
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1724
+ * ======================================================================== */
1725
+
1726
+
1727
+ +function ($) {
1728
+ 'use strict';
1729
+
1730
+ // COLLAPSE PUBLIC CLASS DEFINITION
1731
+ // ================================
1732
+
1733
+ var Collapse = function (element, options) {
1734
+ this.$element = $(element)
1735
+ this.options = $.extend({}, Collapse.DEFAULTS, options)
1736
+ this.transitioning = null
1737
+
1738
+ if (this.options.parent) this.$parent = $(this.options.parent)
1739
+ if (this.options.toggle) this.toggle()
1740
+ }
1741
+
1742
+ Collapse.VERSION = '3.2.0'
1743
+
1744
+ Collapse.DEFAULTS = {
1745
+ toggle: true
1746
+ }
1747
+
1748
+ Collapse.prototype.dimension = function () {
1749
+ var hasWidth = this.$element.hasClass('width')
1750
+ return hasWidth ? 'width' : 'height'
1751
+ }
1752
+
1753
+ Collapse.prototype.show = function () {
1754
+ if (this.transitioning || this.$element.hasClass('in')) return
1755
+
1756
+ var startEvent = $.Event('show.bs.collapse')
1757
+ this.$element.trigger(startEvent)
1758
+ if (startEvent.isDefaultPrevented()) return
1759
+
1760
+ var actives = this.$parent && this.$parent.find('> .panel > .in')
1761
+
1762
+ if (actives && actives.length) {
1763
+ var hasData = actives.data('bs.collapse')
1764
+ if (hasData && hasData.transitioning) return
1765
+ Plugin.call(actives, 'hide')
1766
+ hasData || actives.data('bs.collapse', null)
1767
+ }
1768
+
1769
+ var dimension = this.dimension()
1770
+
1771
+ this.$element
1772
+ .removeClass('collapse')
1773
+ .addClass('collapsing')[dimension](0)
1774
+
1775
+ this.transitioning = 1
1776
+
1777
+ var complete = function () {
1778
+ this.$element
1779
+ .removeClass('collapsing')
1780
+ .addClass('collapse in')[dimension]('')
1781
+ this.transitioning = 0
1782
+ this.$element
1783
+ .trigger('shown.bs.collapse')
1784
+ }
1785
+
1786
+ if (!$.support.transition) return complete.call(this)
1787
+
1788
+ var scrollSize = $.camelCase(['scroll', dimension].join('-'))
1789
+
1790
+ this.$element
1791
+ .one('bsTransitionEnd', $.proxy(complete, this))
1792
+ .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
1793
+ }
1794
+
1795
+ Collapse.prototype.hide = function () {
1796
+ if (this.transitioning || !this.$element.hasClass('in')) return
1797
+
1798
+ var startEvent = $.Event('hide.bs.collapse')
1799
+ this.$element.trigger(startEvent)
1800
+ if (startEvent.isDefaultPrevented()) return
1801
+
1802
+ var dimension = this.dimension()
1803
+
1804
+ this.$element[dimension](this.$element[dimension]())[0].offsetHeight
1805
+
1806
+ this.$element
1807
+ .addClass('collapsing')
1808
+ .removeClass('collapse')
1809
+ .removeClass('in')
1810
+
1811
+ this.transitioning = 1
1812
+
1813
+ var complete = function () {
1814
+ this.transitioning = 0
1815
+ this.$element
1816
+ .trigger('hidden.bs.collapse')
1817
+ .removeClass('collapsing')
1818
+ .addClass('collapse')
1819
+ }
1820
+
1821
+ if (!$.support.transition) return complete.call(this)
1822
+
1823
+ this.$element
1824
+ [dimension](0)
1825
+ .one('bsTransitionEnd', $.proxy(complete, this))
1826
+ .emulateTransitionEnd(350)
1827
+ }
1828
+
1829
+ Collapse.prototype.toggle = function () {
1830
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
1831
+ }
1832
+
1833
+
1834
+ // COLLAPSE PLUGIN DEFINITION
1835
+ // ==========================
1836
+
1837
+ function Plugin(option) {
1838
+ return this.each(function () {
1839
+ var $this = $(this)
1840
+ var data = $this.data('bs.collapse')
1841
+ var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
1842
+
1843
+ if (!data && options.toggle && option == 'show') option = !option
1844
+ if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
1845
+ if (typeof option == 'string') data[option]()
1846
+ })
1847
+ }
1848
+
1849
+ var old = $.fn.collapse
1850
+
1851
+ $.fn.collapse = Plugin
1852
+ $.fn.collapse.Constructor = Collapse
1853
+
1854
+
1855
+ // COLLAPSE NO CONFLICT
1856
+ // ====================
1857
+
1858
+ $.fn.collapse.noConflict = function () {
1859
+ $.fn.collapse = old
1860
+ return this
1861
+ }
1862
+
1863
+
1864
+ // COLLAPSE DATA-API
1865
+ // =================
1866
+
1867
+ $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
1868
+ var href
1869
+ var $this = $(this)
1870
+ var target = $this.attr('data-target')
1871
+ || e.preventDefault()
1872
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
1873
+ var $target = $(target)
1874
+ var data = $target.data('bs.collapse')
1875
+ var option = data ? 'toggle' : $this.data()
1876
+ var parent = $this.attr('data-parent')
1877
+ var $parent = parent && $(parent)
1878
+
1879
+ if (!data || !data.transitioning) {
1880
+ if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
1881
+ $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
1882
+ }
1883
+
1884
+ Plugin.call($target, option)
1885
+ })
1886
+
1887
+ }(jQuery);
1888
+
1889
+ /* ========================================================================
1890
+ * Bootstrap: scrollspy.js v3.2.0
1891
+ * http://getbootstrap.com/javascript/#scrollspy
1892
+ * ========================================================================
1893
+ * Copyright 2011-2014 Twitter, Inc.
1894
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1895
+ * ======================================================================== */
1896
+
1897
+
1898
+ +function ($) {
1899
+ 'use strict';
1900
+
1901
+ // SCROLLSPY CLASS DEFINITION
1902
+ // ==========================
1903
+
1904
+ function ScrollSpy(element, options) {
1905
+ var process = $.proxy(this.process, this)
1906
+
1907
+ this.$body = $('body')
1908
+ this.$scrollElement = $(element).is('body') ? $(window) : $(element)
1909
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
1910
+ this.selector = (this.options.target || '') + ' .nav li > a'
1911
+ this.offsets = []
1912
+ this.targets = []
1913
+ this.activeTarget = null
1914
+ this.scrollHeight = 0
1915
+
1916
+ this.$scrollElement.on('scroll.bs.scrollspy', process)
1917
+ this.refresh()
1918
+ this.process()
1919
+ }
1920
+
1921
+ ScrollSpy.VERSION = '3.2.0'
1922
+
1923
+ ScrollSpy.DEFAULTS = {
1924
+ offset: 10
1925
+ }
1926
+
1927
+ ScrollSpy.prototype.getScrollHeight = function () {
1928
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
1929
+ }
1930
+
1931
+ ScrollSpy.prototype.refresh = function () {
1932
+ var offsetMethod = 'offset'
1933
+ var offsetBase = 0
1934
+
1935
+ if (!$.isWindow(this.$scrollElement[0])) {
1936
+ offsetMethod = 'position'
1937
+ offsetBase = this.$scrollElement.scrollTop()
1938
+ }
1939
+
1940
+ this.offsets = []
1941
+ this.targets = []
1942
+ this.scrollHeight = this.getScrollHeight()
1943
+
1944
+ var self = this
1945
+
1946
+ this.$body
1947
+ .find(this.selector)
1948
+ .map(function () {
1949
+ var $el = $(this)
1950
+ var href = $el.data('target') || $el.attr('href')
1951
+ var $href = /^#./.test(href) && $(href)
1952
+
1953
+ return ($href
1954
+ && $href.length
1955
+ && $href.is(':visible')
1956
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
1957
+ })
1958
+ .sort(function (a, b) { return a[0] - b[0] })
1959
+ .each(function () {
1960
+ self.offsets.push(this[0])
1961
+ self.targets.push(this[1])
1962
+ })
1963
+ }
1964
+
1965
+ ScrollSpy.prototype.process = function () {
1966
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
1967
+ var scrollHeight = this.getScrollHeight()
1968
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
1969
+ var offsets = this.offsets
1970
+ var targets = this.targets
1971
+ var activeTarget = this.activeTarget
1972
+ var i
1973
+
1974
+ if (this.scrollHeight != scrollHeight) {
1975
+ this.refresh()
1976
+ }
1977
+
1978
+ if (scrollTop >= maxScroll) {
1979
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
1980
+ }
1981
+
1982
+ if (activeTarget && scrollTop <= offsets[0]) {
1983
+ return activeTarget != (i = targets[0]) && this.activate(i)
1984
+ }
1985
+
1986
+ for (i = offsets.length; i--;) {
1987
+ activeTarget != targets[i]
1988
+ && scrollTop >= offsets[i]
1989
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
1990
+ && this.activate(targets[i])
1991
+ }
1992
+ }
1993
+
1994
+ ScrollSpy.prototype.activate = function (target) {
1995
+ this.activeTarget = target
1996
+
1997
+ $(this.selector)
1998
+ .parentsUntil(this.options.target, '.active')
1999
+ .removeClass('active')
2000
+
2001
+ var selector = this.selector +
2002
+ '[data-target="' + target + '"],' +
2003
+ this.selector + '[href="' + target + '"]'
2004
+
2005
+ var active = $(selector)
2006
+ .parents('li')
2007
+ .addClass('active')
2008
+
2009
+ if (active.parent('.dropdown-menu').length) {
2010
+ active = active
2011
+ .closest('li.dropdown')
2012
+ .addClass('active')
2013
+ }
2014
+
2015
+ active.trigger('activate.bs.scrollspy')
2016
+ }
2017
+
2018
+
2019
+ // SCROLLSPY PLUGIN DEFINITION
2020
+ // ===========================
2021
+
2022
+ function Plugin(option) {
2023
+ return this.each(function () {
2024
+ var $this = $(this)
2025
+ var data = $this.data('bs.scrollspy')
2026
+ var options = typeof option == 'object' && option
2027
+
2028
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
2029
+ if (typeof option == 'string') data[option]()
2030
+ })
2031
+ }
2032
+
2033
+ var old = $.fn.scrollspy
2034
+
2035
+ $.fn.scrollspy = Plugin
2036
+ $.fn.scrollspy.Constructor = ScrollSpy
2037
+
2038
+
2039
+ // SCROLLSPY NO CONFLICT
2040
+ // =====================
2041
+
2042
+ $.fn.scrollspy.noConflict = function () {
2043
+ $.fn.scrollspy = old
2044
+ return this
2045
+ }
2046
+
2047
+
2048
+ // SCROLLSPY DATA-API
2049
+ // ==================
2050
+
2051
+ $(window).on('load.bs.scrollspy.data-api', function () {
2052
+ $('[data-spy="scroll"]').each(function () {
2053
+ var $spy = $(this)
2054
+ Plugin.call($spy, $spy.data())
2055
+ })
2056
+ })
2057
+
2058
+ }(jQuery);
2059
+
2060
+ /* ========================================================================
2061
+ * Bootstrap: transition.js v3.2.0
2062
+ * http://getbootstrap.com/javascript/#transitions
2063
+ * ========================================================================
2064
+ * Copyright 2011-2014 Twitter, Inc.
2065
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
2066
+ * ======================================================================== */
2067
+
2068
+
2069
+ +function ($) {
2070
+ 'use strict';
2071
+
2072
+ // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
2073
+ // ============================================================
2074
+
2075
+ function transitionEnd() {
2076
+ var el = document.createElement('bootstrap')
2077
+
2078
+ var transEndEventNames = {
2079
+ WebkitTransition : 'webkitTransitionEnd',
2080
+ MozTransition : 'transitionend',
2081
+ OTransition : 'oTransitionEnd otransitionend',
2082
+ transition : 'transitionend'
2083
+ }
2084
+
2085
+ for (var name in transEndEventNames) {
2086
+ if (el.style[name] !== undefined) {
2087
+ return { end: transEndEventNames[name] }
2088
+ }
2089
+ }
2090
+
2091
+ return false // explicit for ie8 ( ._.)
2092
+ }
2093
+
2094
+ // http://blog.alexmaccaw.com/css-transitions
2095
+ $.fn.emulateTransitionEnd = function (duration) {
2096
+ var called = false
2097
+ var $el = this
2098
+ $(this).one('bsTransitionEnd', function () { called = true })
2099
+ var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
2100
+ setTimeout(callback, duration)
2101
+ return this
2102
+ }
2103
+
2104
+ $(function () {
2105
+ $.support.transition = transitionEnd()
2106
+
2107
+ if (!$.support.transition) return
2108
+
2109
+ $.event.special.bsTransitionEnd = {
2110
+ bindType: $.support.transition.end,
2111
+ delegateType: $.support.transition.end,
2112
+ handle: function (e) {
2113
+ if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
2114
+ }
2115
+ }
2116
+ })
2117
+
2118
+ }(jQuery);