commonwealth-vlr-engine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (361) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +91 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +20 -0
  5. data/LICENSE +202 -0
  6. data/README.md +38 -0
  7. data/Rakefile +43 -0
  8. data/app/assets/images/commonwealth-vlr-engine/bplLoginButton.png +0 -0
  9. data/app/assets/images/commonwealth-vlr-engine/dc_audio-icon.png +0 -0
  10. data/app/assets/images/commonwealth-vlr-engine/dc_collection-icon.png +0 -0
  11. data/app/assets/images/commonwealth-vlr-engine/dc_image-icon.png +0 -0
  12. data/app/assets/images/commonwealth-vlr-engine/dc_institution-icon.png +0 -0
  13. data/app/assets/images/commonwealth-vlr-engine/dc_moving-image-icon.png +0 -0
  14. data/app/assets/images/commonwealth-vlr-engine/dc_text-icon.png +0 -0
  15. data/app/assets/images/commonwealth-vlr-engine/facebookLoginButton.png +0 -0
  16. data/app/assets/images/commonwealth-vlr-engine/loading-wdl-grid.gif +0 -0
  17. data/app/assets/images/commonwealth-vlr-engine/loading-wdl.gif +0 -0
  18. data/app/assets/images/commonwealth-vlr-engine/loading.gif +0 -0
  19. data/app/assets/images/commonwealth-vlr-engine/openseadragon/fullpage_grouphover.png +0 -0
  20. data/app/assets/images/commonwealth-vlr-engine/openseadragon/fullpage_hover.png +0 -0
  21. data/app/assets/images/commonwealth-vlr-engine/openseadragon/fullpage_pressed.png +0 -0
  22. data/app/assets/images/commonwealth-vlr-engine/openseadragon/fullpage_rest.png +0 -0
  23. data/app/assets/images/commonwealth-vlr-engine/openseadragon/home_grouphover.png +0 -0
  24. data/app/assets/images/commonwealth-vlr-engine/openseadragon/home_hover.png +0 -0
  25. data/app/assets/images/commonwealth-vlr-engine/openseadragon/home_pressed.png +0 -0
  26. data/app/assets/images/commonwealth-vlr-engine/openseadragon/home_rest.png +0 -0
  27. data/app/assets/images/commonwealth-vlr-engine/openseadragon/next_grouphover.png +0 -0
  28. data/app/assets/images/commonwealth-vlr-engine/openseadragon/next_hover.png +0 -0
  29. data/app/assets/images/commonwealth-vlr-engine/openseadragon/next_pressed.png +0 -0
  30. data/app/assets/images/commonwealth-vlr-engine/openseadragon/next_rest.png +0 -0
  31. data/app/assets/images/commonwealth-vlr-engine/openseadragon/previous_grouphover.png +0 -0
  32. data/app/assets/images/commonwealth-vlr-engine/openseadragon/previous_hover.png +0 -0
  33. data/app/assets/images/commonwealth-vlr-engine/openseadragon/previous_pressed.png +0 -0
  34. data/app/assets/images/commonwealth-vlr-engine/openseadragon/previous_rest.png +0 -0
  35. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateleft_grouphover.png +0 -0
  36. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateleft_hover.png +0 -0
  37. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateleft_pressed.png +0 -0
  38. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateleft_rest.png +0 -0
  39. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateright_grouphover.png +0 -0
  40. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateright_hover.png +0 -0
  41. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateright_pressed.png +0 -0
  42. data/app/assets/images/commonwealth-vlr-engine/openseadragon/rotateright_rest.png +0 -0
  43. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomin_grouphover.png +0 -0
  44. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomin_hover.png +0 -0
  45. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomin_pressed.png +0 -0
  46. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomin_rest.png +0 -0
  47. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomout_grouphover.png +0 -0
  48. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomout_hover.png +0 -0
  49. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomout_pressed.png +0 -0
  50. data/app/assets/images/commonwealth-vlr-engine/openseadragon/zoomout_rest.png +0 -0
  51. data/app/assets/images/commonwealth-vlr-engine/vlr_logo_img.png +0 -0
  52. data/app/assets/javascripts/blacklight_gallery.js +1 -0
  53. data/app/assets/javascripts/blacklight_google_analytics/blacklight_google_analytics.js.erb +165 -0
  54. data/app/assets/javascripts/bootstrap-accessibility-plugin/bootstrap-accessibility.js +586 -0
  55. data/app/assets/javascripts/commonwealth-vlr-engine.js +22 -0
  56. data/app/assets/javascripts/commonwealth-vlr-engine/collection_facets.js +5 -0
  57. data/app/assets/javascripts/commonwealth-vlr-engine/disable_dropdown_nav.js +21 -0
  58. data/app/assets/javascripts/commonwealth-vlr-engine/feedback_alerts.js.erb +19 -0
  59. data/app/assets/javascripts/commonwealth-vlr-engine/folder_tools.js +26 -0
  60. data/app/assets/javascripts/commonwealth-vlr-engine/multi_img_viewer.js.erb +20 -0
  61. data/app/assets/javascripts/commonwealth-vlr-engine/ocr_search_utils.js.erb +32 -0
  62. data/app/assets/javascripts/commonwealth-vlr-engine/volumes_list.js +5 -0
  63. data/app/assets/javascripts/openseadragon.js +2 -0
  64. data/app/assets/javascripts/respond/respond.min.js +6 -0
  65. data/app/assets/javascripts/wdl-viewer/fd-slider.js +1303 -0
  66. data/app/assets/javascripts/wdl-viewer/jquery-deparam.js +113 -0
  67. data/app/assets/javascripts/wdl-viewer/jquery.ba-throttle-debounce.min.js +9 -0
  68. data/app/assets/javascripts/wdl-viewer/jquery.hammer.min.js +7 -0
  69. data/app/assets/javascripts/wdl-viewer/modernizr-wdl.min.js +3 -0
  70. data/app/assets/javascripts/wdl-viewer/wdl-search.js +33 -0
  71. data/app/assets/javascripts/wdl-viewer/wdl-viewer_commonwealth.js +1147 -0
  72. data/app/assets/stylesheets/blacklight_advanced_search.css +5 -0
  73. data/app/assets/stylesheets/blacklight_gallery.css +1 -0
  74. data/app/assets/stylesheets/blacklight_maps.css +1 -0
  75. data/app/assets/stylesheets/bootstrap-accessibility-plugin/bootstrap-accessibility.css +105 -0
  76. data/app/assets/stylesheets/commonwealth-vlr-engine/advanced_search.scss +139 -0
  77. data/app/assets/stylesheets/commonwealth-vlr-engine/basic_search.scss +47 -0
  78. data/app/assets/stylesheets/commonwealth-vlr-engine/book_viewer.scss +576 -0
  79. data/app/assets/stylesheets/commonwealth-vlr-engine/carousel.scss +94 -0
  80. data/app/assets/stylesheets/commonwealth-vlr-engine/cmmnwlth_defaults.scss +45 -0
  81. data/app/assets/stylesheets/commonwealth-vlr-engine/cmmnwlth_shared.scss +75 -0
  82. data/app/assets/stylesheets/commonwealth-vlr-engine/collections.scss +563 -0
  83. data/app/assets/stylesheets/commonwealth-vlr-engine/commonwealth-vlr-engine.css +32 -0
  84. data/app/assets/stylesheets/commonwealth-vlr-engine/facets.scss +111 -0
  85. data/app/assets/stylesheets/commonwealth-vlr-engine/feedback.scss +10 -0
  86. data/app/assets/stylesheets/commonwealth-vlr-engine/folders.scss +276 -0
  87. data/app/assets/stylesheets/commonwealth-vlr-engine/footer.scss +47 -0
  88. data/app/assets/stylesheets/commonwealth-vlr-engine/header.scss +329 -0
  89. data/app/assets/stylesheets/commonwealth-vlr-engine/home.scss +269 -0
  90. data/app/assets/stylesheets/commonwealth-vlr-engine/index.scss +580 -0
  91. data/app/assets/stylesheets/commonwealth-vlr-engine/institutions.scss +246 -0
  92. data/app/assets/stylesheets/commonwealth-vlr-engine/pages.scss +31 -0
  93. data/app/assets/stylesheets/commonwealth-vlr-engine/search_inside.scss +172 -0
  94. data/app/assets/stylesheets/commonwealth-vlr-engine/searches.scss +55 -0
  95. data/app/assets/stylesheets/commonwealth-vlr-engine/show.scss +840 -0
  96. data/app/assets/stylesheets/commonwealth-vlr-engine/signin.scss +43 -0
  97. data/app/assets/stylesheets/commonwealth-vlr-engine/users.scss +18 -0
  98. data/app/assets/stylesheets/commonwealth-vlr-engine/vlr_dependencies.css +8 -0
  99. data/app/assets/stylesheets/ie_fixes.css +16 -0
  100. data/app/assets/stylesheets/openseadragon.css +1 -0
  101. data/app/assets/stylesheets/wdl-viewer/fd-slider.min.css +2 -0
  102. data/app/controllers/blacklight_advanced_search/advanced_controller.rb +66 -0
  103. data/app/controllers/bookmarks_controller.rb +38 -0
  104. data/app/controllers/collections_controller.rb +128 -0
  105. data/app/controllers/commonwealth_vlr_engine/application_controller.rb +8 -0
  106. data/app/controllers/feedback_controller.rb +39 -0
  107. data/app/controllers/folder_items_actions_controller.rb +72 -0
  108. data/app/controllers/folder_items_controller.rb +90 -0
  109. data/app/controllers/folders_controller.rb +132 -0
  110. data/app/controllers/iiif_manifest_controller.rb +74 -0
  111. data/app/controllers/image_viewer_controller.rb +34 -0
  112. data/app/controllers/institutions_controller.rb +62 -0
  113. data/app/controllers/ocr_search_controller.rb +78 -0
  114. data/app/controllers/pages_controller.rb +5 -0
  115. data/app/controllers/users/omniauth_callbacks_controller.rb +10 -0
  116. data/app/controllers/users/registrations_controller.rb +3 -0
  117. data/app/controllers/users/sessions_controller.rb +3 -0
  118. data/app/controllers/users_controller.rb +27 -0
  119. data/app/helpers/blacklight_maps_helper.rb +3 -0
  120. data/app/helpers/collections_helper.rb +3 -0
  121. data/app/helpers/commonwealth_vlr_engine/application_helper.rb +200 -0
  122. data/app/helpers/commonwealth_vlr_engine/blacklight_helper.rb +35 -0
  123. data/app/helpers/commonwealth_vlr_engine/blacklight_url_helper.rb +53 -0
  124. data/app/helpers/commonwealth_vlr_engine/catalog_helper.rb +414 -0
  125. data/app/helpers/commonwealth_vlr_engine/collections_helper_behavior.rb +19 -0
  126. data/app/helpers/commonwealth_vlr_engine/component_helper.rb +22 -0
  127. data/app/helpers/commonwealth_vlr_engine/facets_helper.rb +20 -0
  128. data/app/helpers/commonwealth_vlr_engine/feedback_helper_behavior.rb +14 -0
  129. data/app/helpers/commonwealth_vlr_engine/folders_helper_behavior.rb +9 -0
  130. data/app/helpers/commonwealth_vlr_engine/image_viewer_helper_behavior.rb +14 -0
  131. data/app/helpers/commonwealth_vlr_engine/institutions_helper_behavior.rb +31 -0
  132. data/app/helpers/commonwealth_vlr_engine/layout_helper.rb +22 -0
  133. data/app/helpers/commonwealth_vlr_engine/ocr_search_helper_behavior.rb +48 -0
  134. data/app/helpers/commonwealth_vlr_engine/pages_helper_behavior.rb +38 -0
  135. data/app/helpers/commonwealth_vlr_engine/vlr_blacklight_maps_helper_behavior.rb +59 -0
  136. data/app/helpers/feedback_helper.rb +3 -0
  137. data/app/helpers/folders_helper.rb +3 -0
  138. data/app/helpers/image_viewer_helper.rb +3 -0
  139. data/app/helpers/institutions_helper.rb +3 -0
  140. data/app/helpers/ocr_search_helper.rb +3 -0
  141. data/app/helpers/pages_helper.rb +3 -0
  142. data/app/mailers/notifier.rb +5 -0
  143. data/app/models/carousel_slide.rb +7 -0
  144. data/app/models/record_mailer.rb +18 -0
  145. data/app/models/user.rb +15 -0
  146. data/app/views/advanced/_advanced_search_date.html.erb +23 -0
  147. data/app/views/advanced/_advanced_search_facets.html.erb +5 -0
  148. data/app/views/advanced/_advanced_search_fields.html.erb +39 -0
  149. data/app/views/advanced/_advanced_search_form.html.erb +51 -0
  150. data/app/views/advanced/_advanced_search_help.html.erb +13 -0
  151. data/app/views/advanced/_facet_layout.html.erb +9 -0
  152. data/app/views/advanced/_facet_limit.html.erb +15 -0
  153. data/app/views/advanced/index.html.erb +29 -0
  154. data/app/views/blacklight_advanced_search/_facet_limit.html.erb +12 -0
  155. data/app/views/bookmarks/_tools.html.erb +25 -0
  156. data/app/views/bookmarks/index.html.erb +64 -0
  157. data/app/views/bookmarks/update.js.erb +1 -0
  158. data/app/views/bpluser/folders/_folder.html.erb +36 -0
  159. data/app/views/catalog/_add_this.html.erb +10 -0
  160. data/app/views/catalog/_az_links.html.erb +15 -0
  161. data/app/views/catalog/_basic_search.html.erb +67 -0
  162. data/app/views/catalog/_citation.html.erb +50 -0
  163. data/app/views/catalog/_constraints.html.erb +26 -0
  164. data/app/views/catalog/_document_collections_gallery.html.erb +7 -0
  165. data/app/views/catalog/_facet_limit_series.html.erb +21 -0
  166. data/app/views/catalog/_facets.html.erb +31 -0
  167. data/app/views/catalog/_facets_series.html.erb +4 -0
  168. data/app/views/catalog/_folder_item_control.html.erb +64 -0
  169. data/app/views/catalog/_index_collections_gallery.html.erb +12 -0
  170. data/app/views/catalog/_index_gallery.html.erb +11 -0
  171. data/app/views/catalog/_index_header_default.html.erb +22 -0
  172. data/app/views/catalog/_index_list_collection.html.erb +33 -0
  173. data/app/views/catalog/_index_list_default.html.erb +13 -0
  174. data/app/views/catalog/_index_map_institutions.html.erb +10 -0
  175. data/app/views/catalog/_index_masonry.html.erb +8 -0
  176. data/app/views/catalog/_index_slideshow.html.erb +18 -0
  177. data/app/views/catalog/_more_like_this.html.erb +9 -0
  178. data/app/views/catalog/_opengraph.html.erb +16 -0
  179. data/app/views/catalog/_previous_next_doc.html.erb +22 -0
  180. data/app/views/catalog/_results_pagination.html.erb +9 -0
  181. data/app/views/catalog/_search_form.html.erb +23 -0
  182. data/app/views/catalog/_search_header.html.erb +5 -0
  183. data/app/views/catalog/_show_default.html.erb +75 -0
  184. data/app/views/catalog/_show_main_content.html.erb +27 -0
  185. data/app/views/catalog/_show_more_like_this.html.erb +15 -0
  186. data/app/views/catalog/_show_partials/_show_book_viewer_link.html.erb +25 -0
  187. data/app/views/catalog/_show_partials/_show_default_img.html.erb +32 -0
  188. data/app/views/catalog/_show_partials/_show_default_metadata.html.erb +486 -0
  189. data/app/views/catalog/_show_partials/_show_default_simple_img_viewer.html.erb +45 -0
  190. data/app/views/catalog/_show_partials/_show_downloads.html.erb +14 -0
  191. data/app/views/catalog/_show_partials/_show_flagged_notice.html.erb +29 -0
  192. data/app/views/catalog/_show_partials/_show_multi_img.html.erb +42 -0
  193. data/app/views/catalog/_show_partials/_show_multi_img_pagination.html.erb +20 -0
  194. data/app/views/catalog/_show_partials/_show_oai_item_img.html.erb +5 -0
  195. data/app/views/catalog/_show_partials/_show_oai_item_link.html.erb +8 -0
  196. data/app/views/catalog/_show_partials/_show_prev_next_carousel_links.html.erb +17 -0
  197. data/app/views/catalog/_show_partials/_show_volumes.html.erb +52 -0
  198. data/app/views/catalog/_show_sidebar.html.erb +1 -0
  199. data/app/views/catalog/_show_tools.html.erb +42 -0
  200. data/app/views/catalog/_zero_results.html.erb +20 -0
  201. data/app/views/catalog/email.html.erb +6 -0
  202. data/app/views/catalog/index.html.erb +17 -0
  203. data/app/views/catalog/metadata_view.html.erb +7 -0
  204. data/app/views/catalog/show.html.erb +13 -0
  205. data/app/views/collections/_search_form_collection.html.erb +23 -0
  206. data/app/views/collections/index.html.erb +30 -0
  207. data/app/views/collections/show.html.erb +116 -0
  208. data/app/views/devise/confirmations/new.html.erb +14 -0
  209. data/app/views/devise/mailer/reset_password_instructions.html.erb +13 -0
  210. data/app/views/devise/passwords/edit.html.erb +33 -0
  211. data/app/views/devise/passwords/new.html.erb +31 -0
  212. data/app/views/devise/registrations/edit.html.erb +83 -0
  213. data/app/views/devise/registrations/new.html.erb +53 -0
  214. data/app/views/devise/sessions/new.html.erb +75 -0
  215. data/app/views/devise/shared/_links.erb +29 -0
  216. data/app/views/feedback/complete.html.erb +9 -0
  217. data/app/views/feedback/show.html.erb +61 -0
  218. data/app/views/folder_items/create.js.erb +1 -0
  219. data/app/views/folder_items/destroy.js.erb +1 -0
  220. data/app/views/folder_items/item_actions.js.erb +2 -0
  221. data/app/views/folder_items/update.js.erb +1 -0
  222. data/app/views/folders/_in_folder.html.erb +2 -0
  223. data/app/views/folders/_new_edit_form_fields.html.erb +36 -0
  224. data/app/views/folders/edit.html.erb +25 -0
  225. data/app/views/folders/index.html.erb +73 -0
  226. data/app/views/folders/new.html.erb +27 -0
  227. data/app/views/folders/public_list.html.erb +44 -0
  228. data/app/views/folders/show.html.erb +98 -0
  229. data/app/views/image_viewer/_book_viewer_help.html.erb +125 -0
  230. data/app/views/image_viewer/_render_book_viewer.html.erb +185 -0
  231. data/app/views/image_viewer/book_viewer.html.erb +57 -0
  232. data/app/views/image_viewer/show.js.erb +19 -0
  233. data/app/views/institutions/_intro_text.html.erb +1 -0
  234. data/app/views/institutions/_map_institutions_search.html.erb +9 -0
  235. data/app/views/institutions/_search_form_institution.html.erb +24 -0
  236. data/app/views/institutions/index.html.erb +31 -0
  237. data/app/views/institutions/show.html.erb +104 -0
  238. data/app/views/layouts/_google_analytics.html.erb +9 -0
  239. data/app/views/layouts/book_viewer.html.erb +37 -0
  240. data/app/views/layouts/commonwealth-vlr-engine.html.erb +59 -0
  241. data/app/views/notifier/feedback.text.erb +6 -0
  242. data/app/views/ocr_search/_index_ocr_list.html.erb +17 -0
  243. data/app/views/ocr_search/_search_form_ocr.html.erb +23 -0
  244. data/app/views/ocr_search/_snippets_more.html.erb +15 -0
  245. data/app/views/ocr_search/_zero_results_ocr.html.erb +9 -0
  246. data/app/views/ocr_search/index.html.erb +49 -0
  247. data/app/views/pages/_carousel.html.erb +46 -0
  248. data/app/views/pages/_home_partials/_banner.html.erb +23 -0
  249. data/app/views/pages/_home_partials/_browse.html.erb +55 -0
  250. data/app/views/pages/_home_partials/_context.html.erb +24 -0
  251. data/app/views/pages/_home_partials/_home_content.html.erb +14 -0
  252. data/app/views/pages/about.html.erb +10 -0
  253. data/app/views/pages/about_site.html.erb +6 -0
  254. data/app/views/pages/explore.html.erb +32 -0
  255. data/app/views/pages/home.html.erb +3 -0
  256. data/app/views/record_mailer/email_record.text.erb +7 -0
  257. data/app/views/saved_searches/index.html.erb +60 -0
  258. data/app/views/search_history/index.html.erb +59 -0
  259. data/app/views/shared/_error_messages.html.erb +9 -0
  260. data/app/views/shared/_flash_msg_maintenance.html.erb +6 -0
  261. data/app/views/shared/_folder_item_actions.html.erb +66 -0
  262. data/app/views/shared/_folder_tools.html.erb +4 -0
  263. data/app/views/shared/_footer.html.erb +14 -0
  264. data/app/views/shared/_header_navbar.html.erb +34 -0
  265. data/app/views/shared/_nav_links.html.erb +58 -0
  266. data/app/views/shared/_search_form_header.html.erb +16 -0
  267. data/app/views/shared/_tools.html.erb +14 -0
  268. data/app/views/shared/_user_util_links.html.erb +43 -0
  269. data/app/views/users/show.html.erb +33 -0
  270. data/commonwealth-vlr-engine.gemspec +47 -0
  271. data/config/initializers/patch_blacklight_advanced_search.rb +74 -0
  272. data/config/initializers/patch_blacklight_maps.rb +20 -0
  273. data/config/jetty.yml +7 -0
  274. data/config/locales/commonwealth-vlr-engine.en.yml +463 -0
  275. data/config/routes.rb +92 -0
  276. data/lib/commonwealth-vlr-engine.rb +55 -0
  277. data/lib/commonwealth-vlr-engine/commonwealth_search_builder.rb +66 -0
  278. data/lib/commonwealth-vlr-engine/controller.rb +69 -0
  279. data/lib/commonwealth-vlr-engine/controller_override.rb +238 -0
  280. data/lib/commonwealth-vlr-engine/engine.rb +40 -0
  281. data/lib/commonwealth-vlr-engine/finder.rb +285 -0
  282. data/lib/commonwealth-vlr-engine/iiif_manifest.rb +189 -0
  283. data/lib/commonwealth-vlr-engine/notifier.rb +33 -0
  284. data/lib/commonwealth-vlr-engine/pages.rb +33 -0
  285. data/lib/commonwealth-vlr-engine/render_constraints_override.rb +57 -0
  286. data/lib/commonwealth-vlr-engine/route_sets.rb +49 -0
  287. data/lib/commonwealth-vlr-engine/routes.rb +21 -0
  288. data/lib/commonwealth-vlr-engine/version.rb +3 -0
  289. data/lib/generators/commonwealth_vlr_engine/controller_generator.rb +92 -0
  290. data/lib/generators/commonwealth_vlr_engine/environment_generator.rb +49 -0
  291. data/lib/generators/commonwealth_vlr_engine/install_generator.rb +57 -0
  292. data/lib/generators/commonwealth_vlr_engine/localassets_generator.rb +29 -0
  293. data/lib/generators/commonwealth_vlr_engine/model_generator.rb +65 -0
  294. data/lib/generators/commonwealth_vlr_engine/routes_generator.rb +39 -0
  295. data/lib/generators/commonwealth_vlr_engine/templates/commonwealth_vlr_engine.css.scss +4 -0
  296. data/lib/generators/commonwealth_vlr_engine/templates/config/contact_emails.yml.sample +13 -0
  297. data/lib/generators/commonwealth_vlr_engine/templates/config/fedora.yml.sample +6 -0
  298. data/lib/generators/commonwealth_vlr_engine/templates/config/geojson_static_file.yml.sample +11 -0
  299. data/lib/generators/commonwealth_vlr_engine/templates/config/google_analytics.yml.sample +10 -0
  300. data/lib/generators/commonwealth_vlr_engine/templates/config/iiif_server.yml.sample +10 -0
  301. data/lib/generators/commonwealth_vlr_engine/templates/config/initializers/a_load_commonwealth_vlr_configs.rb +14 -0
  302. data/lib/generators/commonwealth_vlr_engine/templates/config/initializers/devise.rb +269 -0
  303. data/lib/generators/commonwealth_vlr_engine/templates/config/initializers/secret_token.rb +8 -0
  304. data/lib/generators/commonwealth_vlr_engine/templates/config/locales/blacklight.en.yml +44 -0
  305. data/lib/generators/commonwealth_vlr_engine/templates/config/locales/devise.en.yml +12 -0
  306. data/lib/generators/commonwealth_vlr_engine/templates/config/omniauth-facebook.yml.sample +14 -0
  307. data/lib/generators/commonwealth_vlr_engine/templates/config/omniauth-polaris.yml.sample +20 -0
  308. data/lib/generators/commonwealth_vlr_engine/templates/config/vlr.yml +13 -0
  309. data/lib/generators/commonwealth_vlr_engine/yml_generator.rb +29 -0
  310. data/lib/railties/commonwealth_vlr_engine.rake +6 -0
  311. data/solr_conf/conf/schema.xml +476 -0
  312. data/solr_conf/conf/solrconfig.xml +286 -0
  313. data/spec/controllers/catalog_controller_spec.rb +67 -0
  314. data/spec/controllers/collections_controller_spec.rb +127 -0
  315. data/spec/controllers/feedback_controller_spec.rb +51 -0
  316. data/spec/controllers/folder_items_actions_controller_spec.rb +99 -0
  317. data/spec/controllers/folder_items_controller_spec.rb +90 -0
  318. data/spec/controllers/folders_controller_spec.rb +368 -0
  319. data/spec/controllers/iiif_manifest_controller_spec.rb +85 -0
  320. data/spec/controllers/image_viewer_controller_spec.rb +50 -0
  321. data/spec/controllers/institutions_controller_spec.rb +64 -0
  322. data/spec/controllers/ocr_search_controller_spec.rb +71 -0
  323. data/spec/controllers/pages_controller_spec.rb +58 -0
  324. data/spec/controllers/users_controller_spec.rb +62 -0
  325. data/spec/features/catalog/_az_links_spec.rb +27 -0
  326. data/spec/features/catalog/_show_partials/_show_book_viewer_link_spec.rb +47 -0
  327. data/spec/features/catalog/_show_partials/_show_default_simple_img_viewer_spec.rb +19 -0
  328. data/spec/features/catalog/_show_partials/_show_flagged_notice_spec.rb +23 -0
  329. data/spec/features/catalog/_show_partials/_show_multi_img_spec.rb +18 -0
  330. data/spec/features/catalog/_show_partials/_show_volumes_spec.rb +24 -0
  331. data/spec/features/collections/index_spec.rb +35 -0
  332. data/spec/features/feedback/show_spec.rb +47 -0
  333. data/spec/features/image_viewer/book_viewer_spec.rb +67 -0
  334. data/spec/features/institutions/index_spec.rb +31 -0
  335. data/spec/features/institutions/map_view_spec.rb +37 -0
  336. data/spec/features/more_like_this_search_spec.rb +23 -0
  337. data/spec/features/ocr_search/index_spec.rb +89 -0
  338. data/spec/fixtures/sample_rss_feed.xml +56 -0
  339. data/spec/fixtures/sample_solr_documents.yml +2748 -0
  340. data/spec/helpers/application_helper_spec.rb +114 -0
  341. data/spec/helpers/catalog_helper_spec.rb +386 -0
  342. data/spec/helpers/collections_helper_spec.rb +28 -0
  343. data/spec/helpers/component_helper_spec.rb +34 -0
  344. data/spec/helpers/folders_helper_spec.rb +31 -0
  345. data/spec/helpers/image_viewer_helper_spec.rb +15 -0
  346. data/spec/helpers/institutions_helper_spec.rb +53 -0
  347. data/spec/helpers/ocr_search_helper_spec.rb +70 -0
  348. data/spec/helpers/pages_helper_spec.rb +21 -0
  349. data/spec/lib/commonwealth-vlr-engine/commonwealth_search_builder_spec.rb +101 -0
  350. data/spec/lib/commonwealth-vlr-engine/controller_override_spec.rb +41 -0
  351. data/spec/lib/commonwealth-vlr-engine/controller_spec.rb +33 -0
  352. data/spec/lib/commonwealth-vlr-engine/finder_spec.rb +140 -0
  353. data/spec/lib/commonwealth-vlr-engine/iiif_manifest_spec.rb +157 -0
  354. data/spec/lib/commonwealth-vlr-engine/render_constraints_override_spec.rb +97 -0
  355. data/spec/mailers/notifier_spec.rb +31 -0
  356. data/spec/models/carousel_slide_spec.rb +38 -0
  357. data/spec/spec_helper.rb +40 -0
  358. data/spec/tasks/vlr_engine_rake_spec.rb +28 -0
  359. data/spec/test_app_templates/lib/generators/test_app_generator.rb +23 -0
  360. data/tasks/vlr_engine.rake +46 -0
  361. metadata +788 -0
@@ -0,0 +1,22 @@
1
+ //
2
+ // Required by Blacklight-Maps
3
+ //= require blacklight-maps
4
+
5
+ // Required by Blacklight-Gallery
6
+ //= require blacklight_gallery.js
7
+
8
+ // Blacklight-centric Google Analytics event tracking
9
+ //= require blacklight_google_analytics/blacklight_google_analytics
10
+
11
+ // disable main header dropdown menus on tablet/mobile
12
+ //= require commonwealth-vlr-engine/disable_dropdown_nav
13
+
14
+ // for IE8 responsiveness
15
+ //= require respond/respond.min
16
+
17
+ // bootstrap-accessibility-plugin
18
+ //= require bootstrap-accessibility-plugin/bootstrap-accessibility
19
+
20
+ // WARNING: require tree disabled to avoid heavy JS files such as modernizr, openseadragon, etc.
21
+ // from being automatically included on pages that don't need them
22
+ // WARNING: to require any further app-specific JS, you must use the 'require_directory' directive
@@ -0,0 +1,5 @@
1
+ $(document).ready(function() {
2
+ /* change the id of the series thumbnails facet so that collapse of */
3
+ /* series sidebar facet works in tablet/phone view */
4
+ $('#series_wrapper').find('#facet-related_item_series_ssim').attr('id','facet-related_item_series_ssim_thumb-list');
5
+ });
@@ -0,0 +1,21 @@
1
+ /* disable nav item dropdowns for navbar-collapse */
2
+ /*
3
+ function disable_dropdown_nav() {
4
+ $('#header_main_nav').find('a.dropdown-toggle').addClass('disabled');
5
+ }
6
+ */
7
+ $(document).ready(function() {
8
+ /*
9
+ var nav_collapse_link = $('#nav_collapse_button');
10
+
11
+ nav_collapse_link.click( function () {
12
+ disable_dropdown_nav();
13
+ });
14
+ */
15
+ // for iPad
16
+ $('#nav_collapse_button').on("click touchstart", function () {
17
+ //disable_dropdown_nav();
18
+ $('#header_main_nav').find('a.dropdown-toggle').addClass('disabled');
19
+ });
20
+
21
+ });
@@ -0,0 +1,19 @@
1
+ /* replaces help text depending on value selected from 'message type' drop-down */
2
+ $(document).ready (function () {
3
+ var topic_dropdown = $('#message_type_select');
4
+ var help_text_div = $('#contact_help_text');
5
+ var topic_options = JSON.parse('<%= I18n.t('blacklight.feedback.form.topic.options').to_json.html_safe %>');
6
+ var topic_options_keys = Object.keys(topic_options);
7
+ $(topic_dropdown).change(function() {
8
+ var selected_option = topic_dropdown.val();
9
+ for (var i = 0; i < topic_options_keys.length; i++) {
10
+ if (selected_option == topic_options[topic_options_keys[i]].option) {
11
+ if (topic_options[topic_options_keys[i]].help_text != '') {
12
+ help_text_div.html(topic_options[topic_options_keys[i]].help_text).toggleClass("hidden", false);
13
+ } else {
14
+ help_text_div.toggleClass("hidden", true)
15
+ }
16
+ }
17
+ }
18
+ });
19
+ });
@@ -0,0 +1,26 @@
1
+ // item actions for folders and bookmarks
2
+
3
+ $(document).ready ( function () {
4
+ // remove duplicate buttons from form
5
+ $('#cite_btn,#email_btn').remove();
6
+ // add click event for any checkbox in doc list
7
+ $(':checkbox[name="selected[]"]').click( function () {
8
+ addCheckedToURL();
9
+ });
10
+
11
+ // select/unselect all
12
+ $('#selectAllItems').click( function () {
13
+ $(':checkbox[name="selected[]"]').prop('checked', this.checked);
14
+ addCheckedToURL();
15
+ });
16
+ });
17
+
18
+
19
+ // when any checkbox is selected, append the ids of all checked items to url
20
+ function addCheckedToURL () {
21
+ var checkboxValues = $('[name="selected[]"]:checked').serialize();
22
+ checkboxValues = checkboxValues.replace(/selected/g,"id");
23
+ $('#citeLink,#emailLink,#copyLink').attr('href', function(index,previousValue) {
24
+ return previousValue.replace(/\?.*/,"?" + checkboxValues);
25
+ });
26
+ }
@@ -0,0 +1,20 @@
1
+ /* lock height of #multi_img_pane to prevent bounce on image change */
2
+ $(window).bind("load", function() {
3
+ var multi_img_pane_div = $('#multi_img_pane');
4
+ multi_img_pane_div.css('height', multi_img_pane_div.height());
5
+ });
6
+
7
+ var scrollingContainer = $('#thumbnail_list');
8
+ var scrollTarget = scrollingContainer.scrollTop();
9
+
10
+ /* show loading gif while waiting for selected image to load */
11
+ $('#multi_img_show_container').on("click", "a.prev_next", function () {
12
+ // display the loading icon
13
+ $('#img_show_canvas').html('<%= image_tag('commonwealth-vlr-engine/loading.gif',:id => 'loading', :alt => 'Loading...') %>');
14
+ // scroll the thumbnail
15
+ var selected_img = scrollingContainer.find("[data-viewer='" + $(this).data('viewer') + "']");
16
+ var position = selected_img.position().top;
17
+ scrollingContainer.animate({
18
+ scrollTop: (position + scrollTarget) - 200
19
+ }, 200);
20
+ });
@@ -0,0 +1,32 @@
1
+ /* various utilities for ocr search results display in Bootstrap modal and WDL-Viewer contexts */
2
+
3
+ /* pagination links should preserve the modal rather than reloading the page */
4
+ var top_pagination_selector = '#ocr_search_details .page_links a';
5
+ var bottom_pagination_selector = '#ocr_pagination #pagination_links a';
6
+ var relevancy_link_selector = '#sort-dropdown a';
7
+ $(top_pagination_selector + ", " + bottom_pagination_selector + ", " + relevancy_link_selector).on("click", Blacklight.ajaxModal.modalAjaxLinkClick);
8
+
9
+ /* if the window is displayed in the WDL-Viewer context, page links should trigger page changes via JS */
10
+ if ($("body.wdl-viewer").length) {
11
+ $(".book_page_link").on("click", function () {
12
+ $('#ajax-modal').modal('hide');
13
+ $viewer.trigger("goto-page-search",
14
+ [1, this.href.match(/\d+$/), this.href.match(/ocr_q=[\S]+\#/)[0].replace('ocr_q=','').slice(0, -1)]);
15
+ return false;
16
+ });
17
+ }
18
+
19
+ /* so search queries entered by user don't accidentally trigger WDL-Viewer keyboard-based controls */
20
+ $('#ocr_q').on('keydown', function (e) {
21
+ // Avoid keys bubbling up to our top-level input handler:
22
+ e.stopPropagation();
23
+ });
24
+
25
+ /* toggle the ocr snippets collapse link text */
26
+ $('.ocr_snippets_expand').on('click', function() {
27
+ if ($(this).text() === '<%= I18n.t('blacklight.ocr.search.results.snippets.more') %>') {
28
+ $(this).text('<%= I18n.t('blacklight.ocr.search.results.snippets.less') %>');
29
+ } else {
30
+ $(this).text('<%= I18n.t('blacklight.ocr.search.results.snippets.more') %>');
31
+ }
32
+ });
@@ -0,0 +1,5 @@
1
+ /* prevent the Bootstrap-collapse-triggering volume title links from going to the link target */
2
+ /* this allows links to still be clickable for users w/o JS */
3
+ $('#volumes_wrapper').find('a.volume_title').on("click", function (e) {
4
+ e.preventDefault();
5
+ });
@@ -0,0 +1,2 @@
1
+ //= require openseadragon/openseadragon
2
+ //= require openseadragon/rails
@@ -0,0 +1,6 @@
1
+ /*! Respond.js v1.4.2: min/max-width media query polyfill
2
+ * Copyright 2014 Scott Jehl
3
+ * Licensed under MIT
4
+ * http://j.mp/respondjs */
5
+
6
+ !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;b<t.length;b++){var c=t[b],e=c.href,f=c.media,g=c.rel&&"stylesheet"===c.rel.toLowerCase();e&&g&&!p[e]&&(c.styleSheet&&c.styleSheet.rawCssText?(w(c.styleSheet.rawCssText,e,f),p[e]=!0):(!/^([a-zA-Z:]*\/\/)/.test(e)&&!s||e.replace(RegExp.$1,"").split("/")[0]===a.location.host)&&("//"===e.substring(0,2)&&(e=a.location.protocol+e),d.push({href:e,media:f})))}x()};y(),c.update=y,c.getEmValue=u,a.addEventListener?a.addEventListener("resize",b,!1):a.attachEvent&&a.attachEvent("onresize",b)}}(this);
@@ -0,0 +1,1303 @@
1
+ /*! Unobtrusive Slider Control / HTML5 Input Range polyfill - MIT/GPL2 @freqdec */
2
+ /*jshint sub:true, evil:true, boss:true */
3
+ var fdSlider = (function() {
4
+ var sliders = {},
5
+ uniqueid = 0,
6
+ mouseWheelEnabled = true,
7
+ fullARIA = true,
8
+ describedBy = "fd-slider-describedby",
9
+ varSetRules = {
10
+ onfocus:true,
11
+ onvalue:true
12
+ },
13
+ noRangeBar = false,
14
+ html5Animation = "jump",
15
+ isOpera = Object.prototype.toString.call(window.opera) === "[object Opera]",
16
+ fpRegExp = /^([\-]{0,1}[0-9]+(\.[0-9]+){0,1})$/,
17
+ stepRegExp = /^([0-9]+(\.[0-9]+){0,1})$/;
18
+
19
+ var parseJSON = function(str) {
20
+ if(typeof str !== "string" || str === "") {
21
+ return {};
22
+ }
23
+ try {
24
+ // Does a JSON (native or not) Object exist
25
+ if(typeof JSON === "object" && typeof(JSON.parse) === "function") {
26
+ return JSON.parse(str);
27
+ // Genious code taken from: http://kentbrewster.com/badges/
28
+ } else if(/mousewheelenabled|fullaria|describedby|norangebar|html5animation|varsetrules/.test(str.toLowerCase())) {
29
+ var f = Function(['var document,top,self,window,parent,Number,Date,Object,Function,',
30
+ 'Array,String,Math,RegExp,Image,ActiveXObject;',
31
+ 'return (' , str.replace(/<\!--.+-->/gim,'').replace(/\bfunction\b/g,'function-') , ');'].join(''));
32
+ return f();
33
+ }
34
+ } catch (e) { }
35
+
36
+ return {"err":"Could not parse the JSON object"};
37
+ };
38
+
39
+ var affectJSON = function(json) {
40
+ if(typeof json !== "object") {
41
+ return;
42
+ }
43
+ for(var key in json) {
44
+ value = json[key];
45
+ switch(key.toLowerCase()) {
46
+ case "mousewheelenabled":
47
+ mouseWheelEnabled = !!value;
48
+ break;
49
+ case "fullaria":
50
+ fullARIA = !!value;
51
+ break;
52
+ case "describedby":
53
+ describedBy = String(value);
54
+ break;
55
+ case "norangebar":
56
+ noRangeBar = !!value;
57
+ break;
58
+ case "html5animation":
59
+ html5Animation = String(value).search(/^(jump|tween|timed)$/i) != -1 ? String(value).toLowerCase() : "jump";
60
+ break;
61
+ case "varsetrules":
62
+ if("onfocus" in value) {
63
+ varSetRules.onfocus = !!value.onfocus;
64
+ }
65
+ if("onvalue" in value) {
66
+ varSetRules.onvalue = !!value.onvalue;
67
+ }
68
+ break;
69
+ }
70
+ }
71
+ };
72
+ var addEvent = function(obj, type, fn) {
73
+ if(obj.addEventListener) {
74
+ obj.addEventListener(type, fn, true);
75
+ } else if(obj.attachEvent) {
76
+ obj.attachEvent("on"+type, fn);
77
+ }
78
+ };
79
+ var removeEvent = function(obj, type, fn) {
80
+ try {
81
+ if(obj.removeEventListener) {
82
+ obj.removeEventListener(type, fn, true);
83
+ } else if(obj.detachEvent) {
84
+ obj.detachEvent("on"+type, fn);
85
+ }
86
+ } catch(err) {}
87
+ };
88
+ var stopEvent = function(e) {
89
+ e = e || window.event;
90
+ if(e.stopPropagation) {
91
+ e.stopPropagation();
92
+ e.preventDefault();
93
+ }
94
+
95
+ /*@cc_on@*/
96
+ /*@if(@_win32)
97
+ e.cancelBubble = true;
98
+ e.returnValue = false;
99
+ /*@end@*/
100
+
101
+ return false;
102
+ };
103
+ var preventDefault = function(e) {
104
+ e = e || window.event;
105
+ if(e.preventDefault) {
106
+ e.preventDefault();
107
+ return;
108
+ }
109
+ e.returnValue = false;
110
+ };
111
+ // Add/Remove classname utility functions
112
+ var addClass = function(e,c) {
113
+ if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) {
114
+ return;
115
+ }
116
+ e.className += ( e.className ? " " : "" ) + c;
117
+ };
118
+ var removeClass = function(e,c) {
119
+ e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
120
+ };
121
+ // Returns an Object of key value pairs indicating which sliders have values
122
+ // that have been "set" by the user. Normally used within form validation code
123
+ var getValueSet = function() {
124
+ var obj = {};
125
+ for(var id in sliders) {
126
+ obj[id] = sliders[id].getValueSet();
127
+ }
128
+ return obj;
129
+ };
130
+ // Sets the valueSet variable for a specific slider
131
+ var setValueSet = function(sliderId, tf) {
132
+ sliders[sliderId].setValueSet(!!tf);
133
+ };
134
+ // Does the slider exist in memory
135
+ var sliderExists = function(slider) {
136
+ return !!(slider in sliders && sliders.hasOwnProperty(slider));
137
+ };
138
+ // Javascript instantiation of a slider (input type="text|range" or select list)
139
+ var createSlider = function(options) {
140
+ if(!options || !options.inp || !options.inp.tagName || options.inp.tagName.search(/^input|select/i) == -1) { return false; }
141
+
142
+ options.html5Shim = false;
143
+
144
+ if(options.inp.tagName.toLowerCase() == "select") {
145
+ if(options.inp.options.length < 2) {
146
+ return false;
147
+ }
148
+ options.min = 0;
149
+ options.max = options.inp.options.length - 1;
150
+ options.step = 1;
151
+ options.precision = 0;
152
+ options.scale = false;
153
+ options.forceValue = true;
154
+ } else {
155
+ if(String(options.inp.type).search(/^(text|range)$/i) == -1) {
156
+ return false;
157
+ }
158
+ options.min = options.min && String(options.min).search(fpRegExp) != -1 ? +options.min : 0;
159
+ options.max = options.max && String(options.max).search(fpRegExp) != -1 ? +options.max : 100;
160
+ options.step = options.step && String(options.step).search(stepRegExp) != -1 ? options.step : 1;
161
+ options.precision = options.precision && String(options.precision).search(/^[0-9]+$/) != -1 ? options.precision : (String(options.step).search(/\.([0-9]+)$/) != -1 ? String(options.step).match(/\.([0-9]+)$/)[1].length : 0);
162
+ options.scale = options.scale || false;
163
+ options.forceValue = ("forceValue" in options) ? !!options.forceValue : false;
164
+ options.userSnap = ("userSnap" in options) ? !!options.userSnap : false;
165
+ }
166
+ options.ariaFormat = ("ariaFormat" in options) && typeof options.ariaFormat == "function" ? options.ariaFormat : false;
167
+ options.maxStep = options.maxStep && String(options.maxStep).search(stepRegExp) != -1 ? +options.maxStep : +options.step * 2;
168
+ options.classNames = options.classNames || "";
169
+ options.callbacks = options.callbacks || false;
170
+
171
+ destroySingleSlider(options.inp.id);
172
+ sliders[options.inp.id] = new fdRange(options);
173
+ return true;
174
+ };
175
+ var getAttribute = function(elem, att) {
176
+ return elem.getAttribute(att) || "";
177
+ };
178
+ // HTML5 input type="range" shim - called onload or onDomReady
179
+ var init = function() {
180
+ var inputs = document.getElementsByTagName("input"),
181
+ options;
182
+
183
+ for(var i = 0, inp; inp = inputs[i]; i++) {
184
+
185
+ if(inp.tagName.toLowerCase() == "input" &&
186
+ inp.getAttribute("type").toLowerCase() == "range" &&
187
+ (getAttribute(inp, "min") && getAttribute(inp, "min").search(fpRegExp) != -1 ||
188
+ getAttribute(inp, "max") && getAttribute(inp, "max").search(fpRegExp) != -1 ||
189
+ getAttribute(inp, "step") && getAttribute(inp, "step").search(/^(any|([0-9]+(\.[0-9]+){0,1}))$/i) != -1
190
+ )) {
191
+
192
+ // Skip elements that have already been created are are resident in the DOM
193
+ if(inp.id && document.getElementById("fd-slider-"+inp.id)) {
194
+ continue;
195
+ // Destroy elements that have already been created but not resident in the DOM
196
+ } else if(inp.id && !document.getElementById("fd-slider-"+inp.id)) {
197
+ destroySingleSlider(inp.id);
198
+ }
199
+
200
+ // Create an id for the form element if necessary
201
+ if(!inp.id) {
202
+ inp.id = "fd-slider-form-elem-" + uniqueid++;
203
+ }
204
+
205
+ // Basic option Object
206
+ options = {
207
+ inp: inp,
208
+ callbacks: [],
209
+ animation: html5Animation,
210
+ vertical: getAttribute(inp, "data-fd-slider-vertical") ? true : (inp.offsetHeight > inp.offsetWidth),
211
+ classNames: getAttribute(inp, "data-fd-slider-vertical"),
212
+ html5Shim: true
213
+ };
214
+
215
+ if(options.vertical && !getAttribute(inp, "data-fd-slider-vertical")) {
216
+ options.inpHeight = inp.offsetHeight;
217
+ }
218
+
219
+ options.min = getAttribute(inp, "min") || 0;
220
+ options.max = getAttribute(inp, "max") || 100;
221
+ options.step = getAttribute(inp, "step").search(/^any$/i) != -1 ? options.max - options.min : getAttribute(inp, "step").search(stepRegExp) != -1 ? inp.getAttribute("step") : 1;
222
+ options.precision = String(options.step).search(/\.([0-9]+)$/) != -1 ? String(options.step).match(/\.([0-9]+)$/)[1].length : 0;
223
+ options.maxStep = options.step * 2;
224
+
225
+ destroySingleSlider(options.inp.id);
226
+ sliders[options.inp.id] = new fdRange(options);
227
+ }
228
+ }
229
+
230
+ return true;
231
+ };
232
+ var destroySingleSlider = function(id) {
233
+ if(id in sliders && sliders.hasOwnProperty(id)) {
234
+ sliders[id].destroy();
235
+ delete sliders[id];
236
+ return true;
237
+ }
238
+ return false;
239
+ };
240
+ var destroyAllsliders = function(e) {
241
+ for(var slider in sliders) {
242
+ if(sliders.hasOwnProperty(slider)) {
243
+ sliders[slider].destroy();
244
+ }
245
+ }
246
+ sliders = [];
247
+ };
248
+ var unload = function(e) {
249
+ destroyAllsliders();
250
+ sliders = null;
251
+ };
252
+ var resize = function(e) {
253
+ for(var slider in sliders) {
254
+ if(sliders.hasOwnProperty(slider)) {
255
+ sliders[slider].onResize();
256
+ }
257
+ }
258
+ };
259
+ var onDomReady = function() {
260
+ removeOnLoadEvent();
261
+ init();
262
+ };
263
+ var removeOnLoadEvent = function() {
264
+ removeEvent(window, "load", init);
265
+ };
266
+ function fdRange(options) {
267
+ var inp = options.inp,
268
+ disabled = false,
269
+ tagName = inp.tagName.toLowerCase(),
270
+ min = +options.min,
271
+ max = +options.max,
272
+ rMin = +options.min,
273
+ rMax = +options.max,
274
+ range = Math.abs(max - min),
275
+ step = tagName == "select" ? 1 : +options.step,
276
+ maxStep = options.maxStep ? +options.maxStep : step * 2,
277
+ precision = options.precision || 0,
278
+ steps = Math.ceil(range / step),
279
+ scale = options.scale || false,
280
+ hideInput = !!options.hideInput,
281
+ animation = options.animation || "",
282
+ vertical = !!options.vertical,
283
+ callbacks = options.callbacks || {},
284
+ classNames = options.classNames || "",
285
+ html5Shim = !!options.html5Shim,
286
+ defaultVal = max < min ? min : min + ((max - min) / 2),
287
+ resetDef = tagName == "select" ? inp.selectedIndex : inp.defaultValue || defaultVal,
288
+ forceValue = html5Shim || !!options.forceValue,
289
+ inpHeight = html5Shim && vertical && ("inpHeight" in options) ? options.inpHeight : false,
290
+ ariaFormat = !html5Shim && options.ariaFormat ? options.ariaFormat : false,
291
+ userSnap = !html5Shim && !(tagName == "select") && ("userSnap" in options) ? !!options.userSnap : false,
292
+ userInput = false,
293
+ timer = null,
294
+ kbEnabled = true,
295
+ initialVal = tagName == "select" ? inp.selectedIndex : inp.value,
296
+ sliderH = 0,
297
+ sliderW = 0,
298
+ tweenX = 0,
299
+ tweenB = 0,
300
+ tweenC = 0,
301
+ tweenD = 0,
302
+ frame = 0,
303
+ x = 0,
304
+ y = 0,
305
+ rMaxPx = 0,
306
+ rMinPx = 0,
307
+ handlePos = 0,
308
+ destPos = 0,
309
+ mousePos = 0,
310
+ stepPx = 0,
311
+ userSet = false,
312
+ touchEvents = false,
313
+ outerWrapper,
314
+ innerWrapper,
315
+ ieBlur,
316
+ handle,
317
+ rangeBar,
318
+ bar;
319
+
320
+ // For the reset event to work we have to set a defaultValue
321
+ if(tagName == "input" && forceValue && !inp.defaultValue) {
322
+ inp.defaultValue = getWorkingValueFromInput();
323
+ }
324
+
325
+ // Make sure we have a negative step if the max < min
326
+ if(max < min) {
327
+ step = -Math.abs(step);
328
+ maxStep = -Math.abs(maxStep);
329
+ }
330
+
331
+ // Add the 100% scale mark if needs be. This is hacky.
332
+ if(scale) {
333
+ scale[100] = max;
334
+ }
335
+
336
+ // Set the "userSet" variable programmatically for this slider
337
+ function valueSet(tf) {
338
+ tf = !!tf;
339
+ if(tf != userSet) {
340
+ userSet = tf;
341
+ valueToPixels(getWorkingValueFromInput());
342
+ }
343
+ }
344
+
345
+ function disableSlider(noCallback) {
346
+ if(disabled && !noCallback) {
347
+ return;
348
+ }
349
+
350
+ try {
351
+ setTabIndex(handle, -1);
352
+ removeEvent(handle, "focus", onFocus);
353
+ removeEvent(handle, "blur", onBlur);
354
+
355
+ if(!isOpera) {
356
+ removeEvent(handle, "keydown", onKeyDown);
357
+ removeEvent(handle, "keypress", onKeyPress);
358
+ } else {
359
+ removeEvent(handle, "keypress", onKeyDown);
360
+ }
361
+
362
+ removeEvent(outerWrapper, "mouseover", onMouseOver);
363
+ removeEvent(outerWrapper, "mouseout", onMouseOut);
364
+ removeEvent(outerWrapper, "mousedown", onMouseDown);
365
+ removeEvent(outerWrapper, "touchstart", onMouseDown);
366
+
367
+ if(mouseWheelEnabled) {
368
+ if (window.addEventListener && !window.devicePixelRatio) window.removeEventListener('DOMMouseScroll', trackMouseWheel, false);
369
+ else {
370
+ removeEvent(document, "mousewheel", trackMouseWheel);
371
+ removeEvent(window, "mousewheel", trackMouseWheel);
372
+ }
373
+ }
374
+ } catch(err) {}
375
+
376
+ removeClass(innerWrapper, "fd-slider-focused");
377
+ removeClass(innerWrapper, "fd-slider-active");
378
+
379
+ addClass(innerWrapper, "fd-slider-disabled");
380
+ outerWrapper.setAttribute("aria-disabled", true);
381
+ inp.disabled = disabled = true;
382
+ clearTimeout(timer);
383
+
384
+ if(!noCallback) {
385
+ callback("disable");
386
+ }
387
+ }
388
+
389
+ function enableSlider(noCallback) {
390
+ if(!disabled && !noCallback) {
391
+ return;
392
+ }
393
+
394
+ setTabIndex(handle, 0);
395
+ addEvent(handle, "focus", onFocus);
396
+ addEvent(handle, "blur", onBlur);
397
+
398
+ if(!isOpera) {
399
+ addEvent(handle, "keydown", onKeyDown);
400
+ addEvent(handle, "keypress", onKeyPress);
401
+ } else {
402
+ addEvent(handle, "keypress", onKeyDown);
403
+ }
404
+
405
+ addEvent(outerWrapper, "touchstart", onMouseDown);
406
+ addEvent(outerWrapper, "mousedown", onMouseDown);
407
+ addEvent(outerWrapper, "mouseover", onMouseOver);
408
+ addEvent(outerWrapper, "mouseout", onMouseOut);
409
+
410
+ removeClass(innerWrapper, "fd-slider-disabled");
411
+ outerWrapper.setAttribute("aria-disabled", false);
412
+ inp.disabled = disabled = touchEvents = false;
413
+
414
+ if(!noCallback) {
415
+ callback("enable");
416
+ }
417
+ }
418
+
419
+ // Destroys a slider
420
+ function destroySlider() {
421
+ clearTimeout(timer);
422
+ ieBlur = bar = handle = outerWrapper = innerWrapper = timer = null;
423
+ callback("destroy");
424
+ callbacks = null;
425
+ }
426
+
427
+ // Calculates the pixel increment etc
428
+ function redraw() {
429
+ locate();
430
+ // Internet Explorer requires the try catch as hidden
431
+ // elements throw errors
432
+ try {
433
+ var sW = outerWrapper.offsetWidth,
434
+ sH = outerWrapper.offsetHeight,
435
+ hW = handle.offsetWidth,
436
+ hH = handle.offsetHeight,
437
+ bH = bar.offsetHeight,
438
+ bW = bar.offsetWidth,
439
+ mPx = vertical ? sH - hH : sW - hW;
440
+
441
+ stepPx = mPx / steps;
442
+ rMinPx = Math.max(scale ? percentToPixels(valueToPercent(rMin)) : Math.abs((rMin - min) / step) * stepPx, 0);
443
+ rMaxPx = Math.min(scale ? percentToPixels(valueToPercent(rMax)) : Math.abs((rMax - min) / step) * stepPx, Math.floor(vertical ? sH - hH : sW - hW));
444
+
445
+ sliderW = sW;
446
+ sliderH = sH;
447
+
448
+ valueToPixels(forceValue ? getWorkingValueFromInput() : (tagName == "select" ? inp.selectedIndex : parseFloat(inp.value)), false);
449
+
450
+ } catch(err) {}
451
+ callback("redraw");
452
+ }
453
+
454
+ // Calls a callback function
455
+ function callback(type) {
456
+ if(!html5Shim) {
457
+ if(callbacks.hasOwnProperty(type)) {
458
+ var cbObj = {"userSet":userSet, "disabled":disabled, "elem":inp, "value":tagName == "select" ? inp.options[inp.selectedIndex].value : inp.value};
459
+
460
+ // Call all functions in sequence
461
+ for(var i = 0, func; func = callbacks[type][i]; i++) {
462
+ func.call(inp, cbObj);
463
+ }
464
+ }
465
+ } else if(type.match(/^(blur|focus|change)$/i)) {
466
+ var e;
467
+ if(typeof(document.createEvent) != 'undefined') {
468
+ e = document.createEvent('HTMLEvents');
469
+ e.initEvent(type, true, true);
470
+ inp.dispatchEvent(e);
471
+ } else if(typeof(document.createEventObject) != 'undefined') {
472
+ try {
473
+ e = document.createEventObject();
474
+ inp.fireEvent('on' + type.toLowerCase(), e);
475
+ } catch(err){ }
476
+ }
477
+ }
478
+ }
479
+
480
+ // FOCUS & BLUR events
481
+ function onFocus(e) {
482
+ addClass(innerWrapper, 'fd-slider-focused');
483
+
484
+ // Is the value said to have been set by the user onfocus
485
+ if(varSetRules.onfocus) {
486
+ userSet = true;
487
+ valueToPixels(getWorkingValueFromInput());
488
+ }
489
+
490
+ // If mousewheel events required then add them
491
+ if(mouseWheelEnabled) {
492
+ addEvent(window, 'DOMMouseScroll', trackMouseWheel);
493
+ addEvent(document, 'mousewheel', trackMouseWheel);
494
+ if(!isOpera) {
495
+ addEvent(window, 'mousewheel', trackMouseWheel);
496
+ }
497
+ }
498
+
499
+ callback("focus");
500
+ return true;
501
+ }
502
+
503
+ function onBlur(e) {
504
+ removeClass(innerWrapper, 'fd-slider-focused');
505
+
506
+ // Remove mousewheel events if necessary
507
+ if(mouseWheelEnabled) {
508
+ removeEvent(document, 'mousewheel', trackMouseWheel);
509
+ removeEvent(window, 'DOMMouseScroll', trackMouseWheel);
510
+ if(!isOpera) {
511
+ removeEvent(window, 'mousewheel', trackMouseWheel);
512
+ }
513
+ }
514
+
515
+ kbEnabled = true;
516
+ callback("blur");
517
+ }
518
+
519
+ // MOUSEWHEEL events
520
+ function trackMouseWheel(e) {
521
+ if(!kbEnabled) {
522
+ return;
523
+ }
524
+
525
+ e = e || window.event;
526
+ var delta = 0,
527
+ value;
528
+
529
+ if (e.wheelDelta) {
530
+ delta = e.wheelDelta/120;
531
+ // Older versions of Opera require a small hack to inverse the delta
532
+ if (isOpera && window.opera.version() < 9.2) {
533
+ delta = -delta;
534
+ }
535
+ } else if(e.detail) {
536
+ delta = -e.detail/3;
537
+ }
538
+
539
+ if(vertical) {
540
+ delta = -delta;
541
+ }
542
+
543
+ if(delta) {
544
+ value = getWorkingValueFromInput();
545
+ value += (delta < 0) ? -step : step;
546
+ userSet = true;
547
+ valueToPixels(getValidValue(value));
548
+ }
549
+
550
+ preventDefault(e);
551
+ }
552
+
553
+ // KEYBOARD events
554
+ function onKeyPress(e) {
555
+ e = e || window.event;
556
+ // Let all non-hijacked keyboard events pass
557
+ if((e.keyCode >= 33 && e.keyCode <= 40) || !kbEnabled || e.keyCode == 45 || e.keyCode == 46) {
558
+ return stopEvent(e);
559
+ }
560
+ return true;
561
+ }
562
+
563
+ function onKeyDown(e) {
564
+ if(!kbEnabled) {
565
+ return true;
566
+ }
567
+
568
+ e = e || window.event;
569
+ var kc = e.keyCode !== null ? e.keyCode : e.charCode,
570
+ value;
571
+
572
+ if(kc < 33 || (kc > 40 && (kc != 45 && kc != 46))) {
573
+ return true;
574
+ }
575
+
576
+ value = getWorkingValueFromInput();
577
+
578
+ if( kc == 37 || kc == 40 || kc == 46 || kc == 34) {
579
+ // left, down, ins, page down
580
+ value -= (e.ctrlKey || kc == 34 ? +maxStep : +step);
581
+ } else if( kc == 39 || kc == 38 || kc == 45 || kc == 33) {
582
+ // right, up, del, page up
583
+ value += (e.ctrlKey || kc == 33 ? +maxStep : +step);
584
+ } else if( kc == 35 ) {
585
+ // max
586
+ value = rMax;
587
+ } else if( kc == 36 ) {
588
+ // min
589
+ value = rMin;
590
+ }
591
+
592
+ userSet = true;
593
+ valueToPixels(getValidValue(value));
594
+
595
+ callback("update");
596
+
597
+ // Opera doesn't let us cancel key events so the up/down arrows and home/end buttons will scroll the screen - which sucks
598
+ preventDefault(e);
599
+ }
600
+
601
+ // MOUSE & TOUCH events
602
+
603
+ function onMouseOver(e) {
604
+ addClass(innerWrapper, 'fd-slider-hover');
605
+ }
606
+
607
+ function onMouseOut(e) {
608
+ // Should really check we are not still in the slider
609
+ removeClass(innerWrapper, 'fd-slider-hover');
610
+ }
611
+
612
+ // Mousedown on the slider
613
+ function onMouseDown(e) {
614
+ e = e || window.event;
615
+
616
+ // Stop page scrolling
617
+ preventDefault(e);
618
+
619
+ // Grab the event target
620
+ var targ;
621
+ if (e.target) {
622
+ targ = e.target;
623
+ } else if (e.srcElement) {
624
+ targ = e.srcElement;
625
+ }
626
+ if(targ && targ.nodeType == 3) {
627
+ targ = targ.parentNode;
628
+ }
629
+
630
+ // Are we using touchEvents
631
+ if(e.touches) {
632
+ // Skip gestures
633
+ if(e.targetTouches && e.targetTouches.length != 1) {
634
+ return false;
635
+ }
636
+
637
+ e = e.touches[0];
638
+ touchEvents = true;
639
+ }
640
+
641
+ // Stop any animation timers
642
+ clearTimeout(timer);
643
+ timer = null;
644
+
645
+ // Not keyboard enabled
646
+ kbEnabled = false;
647
+
648
+ // User has set a value
649
+ userSet = true;
650
+
651
+ // Handle mousedown - initiate drag
652
+ if(targ.className.search("fd-slider-handle") != -1) {
653
+ mousePos = vertical ? e.clientY : e.clientX;
654
+ handlePos = parseInt(vertical ? handle.offsetTop : handle.offsetLeft)||0;
655
+
656
+ // Set a value on first click even if no movement
657
+ trackMouse(e);
658
+
659
+ if(!touchEvents) {
660
+ addEvent(document, 'mousemove', trackMouse);
661
+ addEvent(document, 'mouseup', stopDrag);
662
+ } else {
663
+ addEvent(document, 'touchmove', trackMouse);
664
+ addEvent(document, 'touchend', stopDrag);
665
+ // Remove mouseEvents to stop them firing after the touch event
666
+ removeEvent(outerWrapper, "mousedown", onMouseDown);
667
+ }
668
+
669
+ addClass(innerWrapper, 'fd-slider-active');
670
+ addClass(document.body, "fd-slider-drag-" + (vertical ? "vertical" : "horizontal"));
671
+
672
+ callback("dragstart");
673
+
674
+ // Wrapper mousedown - initiate animation to click point
675
+ } else {
676
+ locate();
677
+
678
+ var posx = 0;
679
+
680
+ if(e.pageX || e.pageY) {
681
+ posx = vertical ? e.pageY : e.pageX;
682
+ } else if (e.clientX || e.clientY) {
683
+ posx = vertical ? e.clientY + document.body.scrollTop + document.documentElement.scrollTop : e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
684
+ }
685
+
686
+ posx -= vertical ? y + Math.round(handle.offsetHeight / 2) : x + Math.round(handle.offsetWidth / 2);
687
+ posx = snapToPxValue(posx);
688
+
689
+ // Tween animation to click point
690
+ if(animation == "tween") {
691
+ addClass(innerWrapper, 'fd-slider-active');
692
+ tweenTo(posx);
693
+ // Progressive increment to click point
694
+ } else if(animation == "timed") {
695
+ addClass(innerWrapper, 'fd-slider-active');
696
+ addEvent(document, touchEvents ? 'touchend' : 'mouseup', onDocMouseUp);
697
+ destPos = posx;
698
+ onTimer();
699
+ // Immediate jump to click point
700
+ } else {
701
+ pixelsToValue(posx);
702
+ //addEvent(document, touchEvents ? 'touchend' : 'mouseup', onMouseUp);
703
+ }
704
+ }
705
+
706
+ return false;
707
+ }
708
+
709
+ // Progressive increment to click point - clear the animation timer and remove the mouseup/touchend event
710
+ function onDocMouseUp( e ) {
711
+ e = e || window.event;
712
+
713
+ preventDefault(e);
714
+ removeEvent(document, touchEvents ? 'touchend' : 'mouseup', onDocMouseUp);
715
+ removeClass(innerWrapper, "fd-slider-active");
716
+
717
+ clearTimeout(timer);
718
+ timer = null;
719
+ kbEnabled = true;
720
+
721
+ return false;
722
+ }
723
+
724
+ // Mouseup or touchend event on the document to stop drag
725
+ function stopDrag(e) {
726
+ e = e || window.event;
727
+
728
+ preventDefault(e);
729
+
730
+ if(touchEvents) {
731
+ removeEvent(document, 'touchmove', trackMouse);
732
+ removeEvent(document, 'touchend', stopDrag);
733
+ } else {
734
+ removeEvent(document, 'mousemove', trackMouse);
735
+ removeEvent(document, 'mouseup', stopDrag);
736
+ }
737
+
738
+ kbEnabled = true;
739
+ removeClass(document.body, "fd-slider-drag-" + (vertical ? "vertical" : "horizontal"));
740
+ removeClass(innerWrapper, "fd-slider-active");
741
+
742
+ callback("dragend");
743
+
744
+ return false;
745
+ }
746
+
747
+ // Mousemove or touchmove event on the drag handle
748
+ function trackMouse(e) {
749
+ e = e || window.event;
750
+
751
+ preventDefault(e);
752
+
753
+ if(e.touches) {
754
+ // Skip gestures
755
+ if(e.targetTouches && e.targetTouches.length != 1) {
756
+ return false;
757
+ }
758
+ e = e.touches[0];
759
+ }
760
+
761
+ pixelsToValue(snapToPxValue(handlePos + (vertical ? e.clientY - mousePos : e.clientX - mousePos)));
762
+
763
+ return false;
764
+ }
765
+
766
+ // Increments the slider by "inc" steps
767
+ function increment(inc) {
768
+ var value = getWorkingValueFromInput();
769
+ userSet = true;
770
+ value += inc * step;
771
+ valueToPixels(getValidValue(value));
772
+ }
773
+
774
+ // Attempts to locate the on-screen position of the slider
775
+ function locate(){
776
+ var curleft = 0,
777
+ curtop = 0,
778
+ obj = outerWrapper;
779
+
780
+ // Try catch for IE's benefit
781
+ try {
782
+ do {
783
+ curleft += obj.offsetLeft;
784
+ curtop += obj.offsetTop;
785
+ } while(obj = obj.offsetParent);
786
+ } catch(err) {}
787
+ x = curleft;
788
+ y = curtop;
789
+ }
790
+
791
+ // Used during the progressive animation to click point
792
+ function onTimer() {
793
+ var xtmp = parseInt(vertical ? handle.offsetTop : handle.offsetLeft, 10);
794
+ xtmp = Math.round((destPos < xtmp) ? Math.max(destPos, Math.floor(xtmp - stepPx)) : Math.min(destPos, Math.ceil(xtmp + stepPx)));
795
+
796
+ pixelsToValue(snapToPxValue(xtmp));
797
+ if(xtmp != destPos) {
798
+ timer = setTimeout(onTimer, steps > 20 ? 50 : 100);
799
+ } else {
800
+ kbEnabled = true;
801
+ removeClass(innerWrapper, "fd-slider-active");
802
+ callback("finalise");
803
+ }
804
+ }
805
+
806
+ var tween = function(){
807
+ frame++;
808
+ var c = tweenC,
809
+ d = 20,
810
+ t = frame,
811
+ b = tweenB,
812
+ x = Math.ceil((t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b);
813
+
814
+ pixelsToValue(t == d ? tweenX : x);
815
+
816
+ if(t!=d) {
817
+ // Call the "move" callback on each animation increment
818
+ callback("move");
819
+ timer = setTimeout(tween, 20);
820
+ } else {
821
+ clearTimeout(timer);
822
+ timer = null;
823
+ kbEnabled = true;
824
+
825
+ removeClass(innerWrapper, "fd-slider-focused");
826
+ removeClass(innerWrapper, "fd-slider-active");
827
+
828
+ // Call the "finalise" callback whenever the animation is complete
829
+ callback("finalise");
830
+ }
831
+ };
832
+
833
+ function tweenTo(tx){
834
+ kbEnabled = false;
835
+ tweenX = parseInt(tx, 10);
836
+ tweenB = parseInt(vertical ? handle.offsetTop : handle.offsetLeft, 10);
837
+ tweenC = tweenX - tweenB;
838
+ tweenD = 20;
839
+ frame = 0;
840
+
841
+ if(!timer) {
842
+ timer = setTimeout(tween, 20);
843
+ }
844
+ }
845
+
846
+ // Returns a value within the range & sets the userSet var
847
+ // i.e. has the user entered a valid value
848
+ function checkValue(value) {
849
+ if(isNaN(value) || value === "" || typeof value == "undefined") {
850
+ userSet = false;
851
+ return defaultVal;
852
+ } else if(value < Math.min(rMin,rMax)) {
853
+ userSet = false;
854
+ return Math.min(rMin,rMax);
855
+ } else if(value > Math.max(rMin,rMax)) {
856
+ userSet = false;
857
+ return Math.max(rMin,rMax);
858
+ }
859
+ userSet = true;
860
+ return value;
861
+ }
862
+
863
+ // Returns a value within a range - uses the form element value as base
864
+ function getWorkingValueFromInput() {
865
+ return getValidValue(tagName == "input" ? parseFloat(inp.value) : inp.selectedIndex);
866
+ }
867
+
868
+ // Returns a value within the range
869
+ function getValidValue(value) {
870
+ return (isNaN(value) || value === "" || typeof value == "undefined") ? defaultVal : Math.min(Math.max(value, Math.min(rMin,rMax)), Math.max(rMin,rMax));
871
+ }
872
+
873
+ // Calculates value according to pixel position of slider handle
874
+ function pixelsToValue(px) {
875
+ var val = getValidValue(scale ? percentToValue(pixelsToPercent(px)) : vertical ? max - (Math.round(px / stepPx) * step) : min + (Math.round(px / stepPx) * step));
876
+
877
+ handle.style[vertical ? "top" : "left"] = (px || 0) + "px";
878
+ redrawRange();
879
+ setInputValue((tagName == "select" || step == 1) ? Math.round(val) : val);
880
+ }
881
+
882
+ // Calculates pixel position according to form element value
883
+ function valueToPixels(val, updateInputValue) {
884
+ var clearVal = false,
885
+ value;
886
+
887
+ // Allow empty values for non-polyfill sliders
888
+ if((typeof val === "undefined" || isNaN(val) || val === "") && tagName == "input" && !forceValue) {
889
+ value = defaultVal;
890
+ clearVal = true;
891
+ userSet = false;
892
+ } else {
893
+ value = checkValue(val);
894
+ }
895
+
896
+ handle.style[vertical ? "top" : "left"] = (scale ? percentToPixels(valueToPercent(value)) : vertical ? Math.round(((max - value) / step) * stepPx) : Math.round(((value - min) / step) * stepPx)) + "px";
897
+ redrawRange();
898
+ if(typeof updateInputValue !== false) {
899
+ setInputValue(clearVal ? "" : value);
900
+ }
901
+ }
902
+
903
+ // Rounds a pixel value to the nearest "snap" point on the slider scale
904
+ function snapToPxValue(px) {
905
+ if(scale) {
906
+ return Math.max(Math.min(rMaxPx, px), rMinPx);
907
+ } else {
908
+ var rem = px % stepPx;
909
+ if(rem && rem >= (stepPx / 2)) {
910
+ px += (stepPx - rem);
911
+ } else {
912
+ px -= rem;
913
+ }
914
+
915
+ if(px < Math.min(Math.abs(rMinPx), Math.abs(rMaxPx))) {
916
+ px = Math.min(Math.abs(rMinPx), Math.abs(rMaxPx));
917
+ } else if(px > Math.max(Math.abs(rMinPx), Math.abs(rMaxPx))) {
918
+ px = Math.max(Math.abs(rMinPx), Math.abs(rMaxPx));
919
+ }
920
+
921
+ return Math.min(Math.max(px, 0), rMaxPx);
922
+ }
923
+ }
924
+
925
+ // Calculates a value according to percentage of distance handle has travelled
926
+ function percentToValue(pct) {
927
+ var st = 0,
928
+ fr = min,
929
+ value;
930
+
931
+ for(var s in scale) {
932
+ if(!scale.hasOwnProperty(s)) {
933
+ continue;
934
+ }
935
+
936
+ if(pct >= st && pct <= +s ) {
937
+ value = fr + ((pct - st) * (+scale[s] - fr) ) / (+s - st);
938
+ }
939
+
940
+ st = +s;
941
+ fr = +scale[s];
942
+ }
943
+
944
+ return value;
945
+ }
946
+
947
+ // Calculates the percentage handle position according to form element value
948
+ function valueToPercent(value) {
949
+ var st = 0,
950
+ fr = min,
951
+ pct = 0;
952
+
953
+ for(var s in scale) {
954
+ if(!scale.hasOwnProperty(s)) {
955
+ continue;
956
+ }
957
+
958
+ if(value >= fr && value <= +scale[s]){
959
+ pct = st + (value - fr) * (+s - st) / (+scale[s] - fr);
960
+ }
961
+
962
+ st = +s;
963
+ fr = +scale[s];
964
+ }
965
+
966
+ return pct;
967
+ }
968
+
969
+ function percentToPixels(percent) {
970
+ return ((outerWrapper[vertical ? "offsetHeight" : "offsetWidth"] - handle[vertical ? "offsetHeight" : "offsetWidth"]) / 100) * percent;
971
+ }
972
+
973
+ function pixelsToPercent(pixels) {
974
+ return pixels / ((outerWrapper[vertical ? "offsetHeight" : "offsetWidth"] - outerWrapper[handle ? "offsetHeight" : "offsetWidth"]) / 100);
975
+ }
976
+
977
+ // Sets the form element with a valid value
978
+ function setInputValue(val) {
979
+ // The update callback doesn't mean the input value has changed
980
+ callback("update");
981
+
982
+ // If the user has not set this value or has entered an incorrect value then set a class
983
+ // to enable styling of the slider
984
+ if(!userSet) {
985
+ addClass(innerWrapper, "fd-slider-no-value");
986
+ } else {
987
+ removeClass(innerWrapper, "fd-slider-no-value");
988
+ }
989
+
990
+ if(tagName == "select") {
991
+ try {
992
+ val = parseInt(val, 10);
993
+ if(inp.selectedIndex === val) {
994
+ updateAriaValues();
995
+ return;
996
+ }
997
+ inp.options[val].selected = true;
998
+ } catch (err) {}
999
+ } else {
1000
+ if(val !== "" && !userInput) {
1001
+ val = (min + (Math.round((val - min) / step) * step)).toFixed(precision);
1002
+ }
1003
+ if(inp.value === val) {
1004
+ updateAriaValues();
1005
+ return;
1006
+ }
1007
+ inp.value = val;
1008
+ }
1009
+
1010
+ updateAriaValues();
1011
+ callback("change");
1012
+ }
1013
+
1014
+ function checkInputValue(value) {
1015
+ return !(isNaN(value) || value === "" || value < Math.min(rMin,rMax) || value > Math.max(rMin,rMax));
1016
+ }
1017
+
1018
+ function setSliderRange(newMin, newMax) {
1019
+ if(rMin > rMax) {
1020
+ newMin = Math.min(min, Math.max(newMin, newMax));
1021
+ newMax = Math.max(max, Math.min(newMin, newMax));
1022
+ rMin = Math.max(newMin, newMax);
1023
+ rMax = Math.min(newMin, newMax);
1024
+ } else {
1025
+ newMin = Math.max(min, Math.min(newMin, newMax));
1026
+ newMax = Math.min(max, Math.max(newMin, newMax));
1027
+ rMin = Math.min(newMin, newMax);
1028
+ rMax = Math.max(newMin, newMax);
1029
+ }
1030
+
1031
+ if(defaultVal < Math.min(rMin, rMax)) {
1032
+ defaultVal = Math.min(rMin, rMax);
1033
+ } else if(defaultVal > Math.max(rMin, rMax)) {
1034
+ defaultVal = Math.max(rMin, rMax);
1035
+ }
1036
+
1037
+ handle.setAttribute("aria-valuemin", rMin);
1038
+ handle.setAttribute("aria-valuemax", rMax);
1039
+
1040
+ checkValue(tagName == "input" ? parseFloat(inp.value) : inp.selectedIndex);
1041
+ redraw();
1042
+ }
1043
+
1044
+ function redrawRange() {
1045
+ if(noRangeBar) {
1046
+ return;
1047
+ }
1048
+ if(vertical) {
1049
+ rangeBar.style["height"] = Math.max(1, (bar.offsetHeight - handle.offsetTop)) + "px";
1050
+ } else {
1051
+ rangeBar.style["width"] = Math.max(1, handle.offsetLeft) + "px";
1052
+ }
1053
+ }
1054
+
1055
+ function findLabel() {
1056
+ var label = false,
1057
+ labelList = document.getElementsByTagName('label');
1058
+ // loop through label array attempting to match each 'for' attribute to the id of the current element
1059
+ for(var i = 0, lbl; lbl = labelList[i]; i++) {
1060
+ // Internet Explorer requires the htmlFor test
1061
+ if((lbl['htmlFor'] && lbl['htmlFor'] == inp.id) || (lbl.getAttribute('for') == inp.id)) {
1062
+ label = lbl;
1063
+ break;
1064
+ }
1065
+ }
1066
+
1067
+ if(label && !label.id) {
1068
+ label.id = inp.id + "_label";
1069
+ }
1070
+
1071
+ return label;
1072
+ }
1073
+
1074
+ function updateAriaValues() {
1075
+ var val = tagName == "select" ? inp.options[inp.selectedIndex].value : inp.value,
1076
+ valTxt = ariaFormat ? ariaFormat(val) : tagName == "select" ? (inp.options[inp.selectedIndex].text ? inp.options[inp.selectedIndex].text : val) : val;
1077
+
1078
+ handle.setAttribute("aria-valuenow", val);
1079
+ handle.setAttribute("aria-valuetext", valTxt);
1080
+ }
1081
+
1082
+ function onInputChange(e) {
1083
+ userSet = true;
1084
+ userInput = userSnap;
1085
+ valueToPixels(tagName == "input" ? parseFloat(inp.value) : inp.selectedIndex);
1086
+ updateAriaValues();
1087
+ userInput = false;
1088
+ }
1089
+
1090
+ function onInputAttributesChange(e){
1091
+ step = parseFloat(getAttribute(inp, "step"));
1092
+ min = parseFloat(getAttribute(inp, "min"));
1093
+ max = parseFloat(getAttribute(inp, "max"));
1094
+
1095
+ rMin = parseFloat(getAttribute(inp, "min"));
1096
+ rMax = parseFloat(getAttribute(inp, "max"));
1097
+
1098
+ range = Math.abs(max - min);
1099
+ steps = Math.ceil( range / step);
1100
+
1101
+ redraw();
1102
+ }
1103
+
1104
+ function onReset(e) {
1105
+ if(tagName == "input") {
1106
+ inp.value = inp.defaultValue;
1107
+ } else {
1108
+ inp.selectedIndex = resetDef;
1109
+ }
1110
+ checkValue(tagName == "select" ? inp.options[inp.selectedIndex].value : inp.value);
1111
+ redraw();
1112
+ updateAriaValues();
1113
+ }
1114
+
1115
+ function valueSet(tf) {
1116
+ userSet = !!tf;
1117
+ }
1118
+
1119
+ // Sets a tabindex attribute on an element, bends over for IE.
1120
+ function setTabIndex(e, i) {
1121
+ e.setAttribute(!/*@cc_on!@*/false ? "tabIndex" : "tabindex", i);
1122
+ e.tabIndex = i;
1123
+ }
1124
+
1125
+ (function() {
1126
+ if(html5Shim || hideInput) {
1127
+ addClass(inp, "fd-form-element-hidden");
1128
+ } else {
1129
+ addEvent(inp, 'change', onInputChange);
1130
+ }
1131
+
1132
+ addEvent(inp, "DOMAttrModified", onInputAttributesChange);
1133
+
1134
+ // Add stepUp & stepDown methods to input element if using the html5Shim
1135
+ if(html5Shim) {
1136
+ inp.stepUp = function(n) { increment(n||1); };
1137
+ inp.stepDown = function(n) { increment(n||-1); };
1138
+ }
1139
+
1140
+ outerWrapper = document.createElement('span');
1141
+ outerWrapper.className = "fd-slider" + (vertical ? "-vertical " : " ") + classNames;
1142
+ outerWrapper.id = "fd-slider-" + inp.id;
1143
+
1144
+ if(vertical && inpHeight) {
1145
+ outerWrapper.style.height = inpHeight + "px";
1146
+ }
1147
+
1148
+ innerWrapper = document.createElement('span');
1149
+ innerWrapper.className = "fd-slider-wrapper" + (!html5Shim ? " fd-slider-no-value" : "");
1150
+
1151
+ ieBlur = document.createElement('span');
1152
+ ieBlur.className = "fd-slider-inner";
1153
+
1154
+ bar = document.createElement('span');
1155
+ bar.className = "fd-slider-bar";
1156
+
1157
+ if(fullARIA) {
1158
+ handle = document.createElement('span');
1159
+ } else {
1160
+ handle = document.createElement('a');
1161
+ handle.setAttribute("href", "#");
1162
+ addEvent(handle, "click", stopEvent);
1163
+ }
1164
+
1165
+ setTabIndex(handle, 0);
1166
+
1167
+ handle.className = "fd-slider-handle";
1168
+ handle.appendChild(document.createTextNode(String.fromCharCode(160)));
1169
+
1170
+ innerWrapper.appendChild(ieBlur);
1171
+
1172
+ if(!noRangeBar) {
1173
+ rangeBar = document.createElement('span');
1174
+ rangeBar.className = "fd-slider-range";
1175
+ innerWrapper.appendChild(rangeBar);
1176
+ }
1177
+
1178
+ innerWrapper.appendChild(bar);
1179
+ innerWrapper.appendChild(handle);
1180
+ outerWrapper.appendChild(innerWrapper);
1181
+
1182
+ inp.parentNode.insertBefore(outerWrapper, inp);
1183
+
1184
+ if(isOpera || /*@cc_on!@*/!true) {
1185
+ handle.unselectable = "on";
1186
+ bar.unselectable = "on";
1187
+ ieBlur.unselectable = "on";
1188
+ outerWrapper.unselectable = "on";
1189
+ innerWrapper.unselectable = "on";
1190
+ if(!noRangeBar) {
1191
+ rangeBar.unselectable = "on";
1192
+ }
1193
+ }
1194
+
1195
+ // Add ARIA accessibility info programmatically
1196
+ outerWrapper.setAttribute("role", "application");
1197
+
1198
+ handle.setAttribute("role", "slider");
1199
+ handle.setAttribute("aria-valuemin", tagName == "select" ? inp.options[0].value : min);
1200
+ handle.setAttribute("aria-valuemax", tagName == "select" ? inp.options[inp.options.length - 1].value : max);
1201
+
1202
+ var lbl = findLabel();
1203
+ if(lbl) {
1204
+ handle.setAttribute("aria-labelledby", lbl.id);
1205
+ handle.id = "fd-slider-handle-" + inp.id;
1206
+ /*@cc_on@*/
1207
+ /*@if(@_win32)
1208
+ lbl.setAttribute("htmlFor", handle.id);
1209
+ @else @*/
1210
+ lbl.setAttribute("for", handle.id);
1211
+ /*@end@*/
1212
+ }
1213
+
1214
+ // Are there page instructions
1215
+ if(document.getElementById(describedBy)) {
1216
+ handle.setAttribute("aria-describedby", describedBy);
1217
+ }
1218
+
1219
+ // Is the form element initially disabled
1220
+ if(inp.getAttribute("disabled") == true || inp.getAttribute("disabled") == "disabled") {
1221
+ disableSlider(true);
1222
+ } else {
1223
+ enableSlider(true);
1224
+ }
1225
+
1226
+ // Does an initial form element value mean the user has set a valid value?
1227
+ // Also called onload in case browsers have automatically set the input value
1228
+ if(varSetRules.onvalue) {
1229
+ userSet = true;
1230
+ checkValue(tagName == "input" ? parseFloat(inp.value) : inp.selectedIndex);
1231
+ }
1232
+
1233
+ // Catch form reset events
1234
+ if(inp.form) {
1235
+ addEvent(inp.form, "reset", onReset);
1236
+ }
1237
+
1238
+ updateAriaValues();
1239
+ callback("create");
1240
+ redraw();
1241
+ })();
1242
+
1243
+ return {
1244
+ onResize: function(e) { if(outerWrapper.offsetHeight != sliderH || outerWrapper.offsetWidth != sliderW) { redraw(); } },
1245
+ destroy: function() { destroySlider(); },
1246
+ reset: function() { valueToPixels(tagName == "input" ? parseFloat(inp.value) : inp.selectedIndex); },
1247
+ stepUp: function(n) { increment(Math.abs(n)||1); },
1248
+ stepDown: function(n) { increment(-Math.abs(n)||-1); },
1249
+ increment: function(n) { increment(n); },
1250
+ disable: function() { disableSlider(); },
1251
+ enable: function() { enableSlider(); },
1252
+ setRange: function(mi, mx) { setSliderRange(mi, mx); },
1253
+ getValueSet: function() { return !!userSet; },
1254
+ setValueSet: function(tf) { valueSet(tf); },
1255
+ checkValue: function() { if(varSetRules.onvalue) { userSet = true; checkValue(tagName == "input" ? parseFloat(inp.value) : inp.selectedIndex); } updateAriaValues(); redraw(); }
1256
+ };
1257
+ }
1258
+
1259
+ addEvent(window, "load", init);
1260
+ addEvent(window, "load", function() { setTimeout(function() { var slider; for(slider in sliders) { sliders[slider].checkValue(); } }, 0); });
1261
+ addEvent(window, "resize", resize);
1262
+ addEvent(window, "unload", unload);
1263
+
1264
+ // Have we been passed JSON within the including script tag
1265
+ (function() {
1266
+ var scriptFiles = document.getElementsByTagName('script'),
1267
+ scriptInner = String(scriptFiles[scriptFiles.length - 1].innerHTML).replace(/[\n\r\s\t]+/g, " ").replace(/^\s+/, "").replace(/\s+$/, ""),
1268
+ json = parseJSON(scriptInner);
1269
+
1270
+ if(typeof json === "object" && !("err" in json)) {
1271
+ affectJSON(json);
1272
+ }
1273
+ })();
1274
+
1275
+ // Add oldie class if needed for IE < 9
1276
+ /*@cc_on@*/
1277
+ /*@if (@_jscript_version < 9)
1278
+ addClass(document.documentElement, "oldie");
1279
+ /*@end@*/
1280
+
1281
+ return {
1282
+ rescanDocument: init,
1283
+ createSlider: function(opts) { return createSlider(opts); },
1284
+ onDomReady: function() { onDomReady(); },
1285
+ destroyAll: function() { destroyAllsliders(); },
1286
+ destroySlider: function(id) { return destroySingleSlider(id); },
1287
+ redrawAll: function() { resize(); },
1288
+ addEvent: addEvent,
1289
+ removeEvent: removeEvent,
1290
+ stopEvent: stopEvent,
1291
+ increment: function(id, numSteps) { if(!sliderExists(id)) { return false; } sliders[id].increment(numSteps); },
1292
+ stepUp: function(id, n) { if(!sliderExists(id)) { return false; } sliders[id].stepUp(Math.abs(n)||1); },
1293
+ stepDown: function(id, n) { if(!sliderExists(id)) { return false; } sliders[id].stepDown(-Math.abs(n)||-1); },
1294
+ setRange: function(id, newMin, newMax) { if(!sliderExists(id)) { return false; } sliders[id].setRange(newMin, newMax); },
1295
+ updateSlider: function(id) { if(!sliderExists(id)) { return false; } sliders[id].onResize(); sliders[id].reset(); },
1296
+ disable: function(id) { if(!sliderExists(id)) { return false; } sliders[id].disable(); },
1297
+ enable: function(id) { if(!sliderExists(id)) { return false; } sliders[id].enable(); },
1298
+ getValueSet: function() { return getValueSet(); },
1299
+ setValueSet: function(a, tf) { if(!sliderExists(id)) { return false; } setValueSet(a, tf); },
1300
+ setGlobalVariables: function(json) { affectJSON(json); },
1301
+ removeOnload: function() { removeOnLoadEvent(); }
1302
+ };
1303
+ })();