commonwealth-vlr-engine 0.0.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 (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
+ })();