rails_admin-lbgraham 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (416) hide show
  1. data/Gemfile +51 -0
  2. data/LICENSE.md +20 -0
  3. data/README.md +175 -0
  4. data/Rakefile +19 -0
  5. data/app/assets/images/rails_admin/aristo/images/bg_fallback.png +0 -0
  6. data/app/assets/images/rails_admin/aristo/images/icon_sprite.png +0 -0
  7. data/app/assets/images/rails_admin/aristo/images/progress_bar.gif +0 -0
  8. data/app/assets/images/rails_admin/aristo/images/slider_handles.png +0 -0
  9. data/app/assets/images/rails_admin/aristo/images/ui-icons_222222_256x240.png +0 -0
  10. data/app/assets/images/rails_admin/aristo/images/ui-icons_454545_256x240.png +0 -0
  11. data/app/assets/images/rails_admin/bullet_black.png +0 -0
  12. data/app/assets/images/rails_admin/bullet_white.png +0 -0
  13. data/app/assets/images/rails_admin/calendar.png +0 -0
  14. data/app/assets/images/rails_admin/clock.png +0 -0
  15. data/app/assets/images/rails_admin/colorpicker/colorpicker_background.png +0 -0
  16. data/app/assets/images/rails_admin/colorpicker/colorpicker_hex.png +0 -0
  17. data/app/assets/images/rails_admin/colorpicker/colorpicker_hsb_b.png +0 -0
  18. data/app/assets/images/rails_admin/colorpicker/colorpicker_hsb_h.png +0 -0
  19. data/app/assets/images/rails_admin/colorpicker/colorpicker_hsb_s.png +0 -0
  20. data/app/assets/images/rails_admin/colorpicker/colorpicker_indic.gif +0 -0
  21. data/app/assets/images/rails_admin/colorpicker/colorpicker_overlay.png +0 -0
  22. data/app/assets/images/rails_admin/colorpicker/colorpicker_rgb_b.png +0 -0
  23. data/app/assets/images/rails_admin/colorpicker/colorpicker_rgb_g.png +0 -0
  24. data/app/assets/images/rails_admin/colorpicker/colorpicker_rgb_r.png +0 -0
  25. data/app/assets/images/rails_admin/colorpicker/colorpicker_select.gif +0 -0
  26. data/app/assets/images/rails_admin/colorpicker/colorpicker_submit.png +0 -0
  27. data/app/assets/images/rails_admin/colorpicker/custom_background.png +0 -0
  28. data/app/assets/images/rails_admin/colorpicker/custom_hex.png +0 -0
  29. data/app/assets/images/rails_admin/colorpicker/custom_hsb_b.png +0 -0
  30. data/app/assets/images/rails_admin/colorpicker/custom_hsb_h.png +0 -0
  31. data/app/assets/images/rails_admin/colorpicker/custom_hsb_s.png +0 -0
  32. data/app/assets/images/rails_admin/colorpicker/custom_indic.gif +0 -0
  33. data/app/assets/images/rails_admin/colorpicker/custom_rgb_b.png +0 -0
  34. data/app/assets/images/rails_admin/colorpicker/custom_rgb_g.png +0 -0
  35. data/app/assets/images/rails_admin/colorpicker/custom_rgb_r.png +0 -0
  36. data/app/assets/images/rails_admin/colorpicker/custom_submit.png +0 -0
  37. data/app/assets/images/rails_admin/colorpicker/select.png +0 -0
  38. data/app/assets/images/rails_admin/colorpicker/select2.png +0 -0
  39. data/app/assets/images/rails_admin/colorpicker/slider.png +0 -0
  40. data/app/assets/images/rails_admin/logo.png +0 -0
  41. data/app/assets/images/rails_admin/magnifier.png +0 -0
  42. data/app/assets/images/rails_admin/multiselect/icon_sprite.png +0 -0
  43. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-n-dark.png +0 -0
  44. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-n-light.png +0 -0
  45. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-s-dark.png +0 -0
  46. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-s-light.png +0 -0
  47. data/app/assets/javascripts/rails_admin/custom/ui.js +12 -0
  48. data/app/assets/javascripts/rails_admin/jquery.colorpicker.js +484 -0
  49. data/app/assets/javascripts/rails_admin/jquery.pjax.js +743 -0
  50. data/app/assets/javascripts/rails_admin/jquery.ui.timepicker.js +1371 -0
  51. data/app/assets/javascripts/rails_admin/ra.datetimepicker.js +67 -0
  52. data/app/assets/javascripts/rails_admin/ra.filter-box.js +142 -0
  53. data/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +292 -0
  54. data/app/assets/javascripts/rails_admin/ra.filtering-select.js +190 -0
  55. data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.coffee +41 -0
  56. data/app/assets/javascripts/rails_admin/ra.remote-form.js +151 -0
  57. data/app/assets/javascripts/rails_admin/ra.widgets.coffee +210 -0
  58. data/app/assets/javascripts/rails_admin/rails_admin.js.erb +28 -0
  59. data/app/assets/javascripts/rails_admin/themes/cerulean/ui.js +0 -0
  60. data/app/assets/javascripts/rails_admin/themes/default/ui.js +12 -0
  61. data/app/assets/javascripts/rails_admin/ui.js.coffee +66 -0
  62. data/app/assets/stylesheets/rails_admin/aristo/images/bg_fallback.png +0 -0
  63. data/app/assets/stylesheets/rails_admin/aristo/images/icon_sprite.png +0 -0
  64. data/app/assets/stylesheets/rails_admin/aristo/images/progress_bar.gif +0 -0
  65. data/app/assets/stylesheets/rails_admin/aristo/images/slider_handles.png +0 -0
  66. data/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_222222_256x240.png +0 -0
  67. data/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_454545_256x240.png +0 -0
  68. data/app/assets/stylesheets/rails_admin/aristo/jquery-ui-1.8.7.custom.css.scss +733 -0
  69. data/app/assets/stylesheets/rails_admin/base/README.txt +2 -0
  70. data/app/assets/stylesheets/rails_admin/base/mixins.css.scss +1 -0
  71. data/app/assets/stylesheets/rails_admin/base/theming.css.scss +270 -0
  72. data/app/assets/stylesheets/rails_admin/base/variables.css.scss +1 -0
  73. data/app/assets/stylesheets/rails_admin/custom/mixins.css.scss +12 -0
  74. data/app/assets/stylesheets/rails_admin/custom/theming.css.scss +13 -0
  75. data/app/assets/stylesheets/rails_admin/custom/variables.css.scss +15 -0
  76. data/app/assets/stylesheets/rails_admin/imports.css.scss.erb +82 -0
  77. data/app/assets/stylesheets/rails_admin/jquery.colorpicker.css.scss +182 -0
  78. data/app/assets/stylesheets/rails_admin/jquery.ui.timepicker.css.scss +69 -0
  79. data/app/assets/stylesheets/rails_admin/ra.calendar-additions.css.scss +25 -0
  80. data/app/assets/stylesheets/rails_admin/ra.filtering-multiselect.css.scss +90 -0
  81. data/app/assets/stylesheets/rails_admin/ra.widgets.css.scss +8 -0
  82. data/app/assets/stylesheets/rails_admin/rails_admin.css +4 -0
  83. data/app/assets/stylesheets/rails_admin/themes/cerulean/mixins.css.scss +0 -0
  84. data/app/assets/stylesheets/rails_admin/themes/cerulean/theming.css.scss +97 -0
  85. data/app/assets/stylesheets/rails_admin/themes/cerulean/variables.css.scss +168 -0
  86. data/app/assets/stylesheets/rails_admin/themes/default/mixins.css.scss +8 -0
  87. data/app/assets/stylesheets/rails_admin/themes/default/theming.css.scss +11 -0
  88. data/app/assets/stylesheets/rails_admin/themes/default/variables.css.scss +12 -0
  89. data/app/controllers/rails_admin/application_controller.rb +84 -0
  90. data/app/controllers/rails_admin/main_controller.rb +153 -0
  91. data/app/helpers/rails_admin/application_helper.rb +147 -0
  92. data/app/helpers/rails_admin/form_builder.rb +117 -0
  93. data/app/helpers/rails_admin/main_helper.rb +36 -0
  94. data/app/views/kaminari/twitter-bootstrap/_gap.html.haml +2 -0
  95. data/app/views/kaminari/twitter-bootstrap/_next_page.html.haml +4 -0
  96. data/app/views/kaminari/twitter-bootstrap/_page.html.haml +4 -0
  97. data/app/views/kaminari/twitter-bootstrap/_paginator.html.haml +10 -0
  98. data/app/views/kaminari/twitter-bootstrap/_prev_page.html.haml +4 -0
  99. data/app/views/layouts/rails_admin/_secondary_navigation.html.haml +12 -0
  100. data/app/views/layouts/rails_admin/application.html.haml +27 -0
  101. data/app/views/layouts/rails_admin/pjax.html.haml +16 -0
  102. data/app/views/rails_admin/main/_dashboard_history.html.haml +20 -0
  103. data/app/views/rails_admin/main/_delete_notice.html.haml +19 -0
  104. data/app/views/rails_admin/main/_form_colorpicker.html.haml +1 -0
  105. data/app/views/rails_admin/main/_form_datetime.html.haml +1 -0
  106. data/app/views/rails_admin/main/_form_enumeration.html.haml +18 -0
  107. data/app/views/rails_admin/main/_form_field.html.haml +1 -0
  108. data/app/views/rails_admin/main/_form_file_upload.html.haml +13 -0
  109. data/app/views/rails_admin/main/_form_filtering_multiselect.html.haml +47 -0
  110. data/app/views/rails_admin/main/_form_filtering_select.html.haml +37 -0
  111. data/app/views/rails_admin/main/_form_nested_many.html.haml +14 -0
  112. data/app/views/rails_admin/main/_form_nested_one.html.haml +10 -0
  113. data/app/views/rails_admin/main/_form_polymorphic_association.html.haml +10 -0
  114. data/app/views/rails_admin/main/_form_text.html.haml +31 -0
  115. data/app/views/rails_admin/main/_submit_buttons.html.haml +15 -0
  116. data/app/views/rails_admin/main/bulk_delete.html.haml +11 -0
  117. data/app/views/rails_admin/main/dashboard.html.haml +35 -0
  118. data/app/views/rails_admin/main/delete.html.haml +18 -0
  119. data/app/views/rails_admin/main/edit.html.haml +2 -0
  120. data/app/views/rails_admin/main/export.html.haml +75 -0
  121. data/app/views/rails_admin/main/history.html.haml +49 -0
  122. data/app/views/rails_admin/main/index.html.haml +140 -0
  123. data/app/views/rails_admin/main/new.html.haml +2 -0
  124. data/app/views/rails_admin/main/show.html.haml +16 -0
  125. data/config/initializers/active_record_extensions.rb +19 -0
  126. data/config/initializers/devise_patch.rb +9 -0
  127. data/config/initializers/haml.rb +2 -0
  128. data/config/initializers/mongoid_extensions.rb +4 -0
  129. data/config/locales/rails_admin.en.yml +130 -0
  130. data/config/routes.rb +12 -0
  131. data/lib/generators/rails_admin/install_generator.rb +85 -0
  132. data/lib/generators/rails_admin/templates/drop.rb +18 -0
  133. data/lib/generators/rails_admin/templates/initializer.erb +100 -0
  134. data/lib/generators/rails_admin/templates/migration.rb +18 -0
  135. data/lib/generators/rails_admin/uninstall_generator.rb +22 -0
  136. data/lib/generators/rails_admin/utils.rb +30 -0
  137. data/lib/rails_admin.rb +34 -0
  138. data/lib/rails_admin/abstract_model.rb +128 -0
  139. data/lib/rails_admin/adapters/active_record.rb +296 -0
  140. data/lib/rails_admin/adapters/active_record/abstract_object.rb +32 -0
  141. data/lib/rails_admin/adapters/mongoid.rb +430 -0
  142. data/lib/rails_admin/adapters/mongoid/abstract_object.rb +43 -0
  143. data/lib/rails_admin/adapters/mongoid/extension.rb +45 -0
  144. data/lib/rails_admin/config.rb +333 -0
  145. data/lib/rails_admin/config/actions.rb +121 -0
  146. data/lib/rails_admin/config/actions/base.rb +132 -0
  147. data/lib/rails_admin/config/actions/bulk_delete.rb +55 -0
  148. data/lib/rails_admin/config/actions/dashboard.rb +52 -0
  149. data/lib/rails_admin/config/actions/delete.rb +56 -0
  150. data/lib/rails_admin/config/actions/edit.rb +55 -0
  151. data/lib/rails_admin/config/actions/export.rb +40 -0
  152. data/lib/rails_admin/config/actions/history_index.rb +38 -0
  153. data/lib/rails_admin/config/actions/history_show.rb +38 -0
  154. data/lib/rails_admin/config/actions/index.rb +85 -0
  155. data/lib/rails_admin/config/actions/new.rb +65 -0
  156. data/lib/rails_admin/config/actions/show.rb +34 -0
  157. data/lib/rails_admin/config/actions/show_in_app.rb +27 -0
  158. data/lib/rails_admin/config/configurable.rb +92 -0
  159. data/lib/rails_admin/config/fields.rb +87 -0
  160. data/lib/rails_admin/config/fields/association.rb +107 -0
  161. data/lib/rails_admin/config/fields/base.rb +320 -0
  162. data/lib/rails_admin/config/fields/factories/association.rb +32 -0
  163. data/lib/rails_admin/config/fields/factories/carrierwave.rb +31 -0
  164. data/lib/rails_admin/config/fields/factories/devise.rb +27 -0
  165. data/lib/rails_admin/config/fields/factories/dragonfly.rb +27 -0
  166. data/lib/rails_admin/config/fields/factories/enum.rb +11 -0
  167. data/lib/rails_admin/config/fields/factories/paperclip.rb +26 -0
  168. data/lib/rails_admin/config/fields/factories/password.rb +17 -0
  169. data/lib/rails_admin/config/fields/group.rb +78 -0
  170. data/lib/rails_admin/config/fields/types.rb +27 -0
  171. data/lib/rails_admin/config/fields/types/all.rb +25 -0
  172. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +41 -0
  173. data/lib/rails_admin/config/fields/types/boolean.rb +38 -0
  174. data/lib/rails_admin/config/fields/types/bson_object_id.rb +45 -0
  175. data/lib/rails_admin/config/fields/types/carrierwave.rb +31 -0
  176. data/lib/rails_admin/config/fields/types/color.rb +37 -0
  177. data/lib/rails_admin/config/fields/types/date.rb +24 -0
  178. data/lib/rails_admin/config/fields/types/datetime.rb +164 -0
  179. data/lib/rails_admin/config/fields/types/decimal.rb +14 -0
  180. data/lib/rails_admin/config/fields/types/dragonfly.rb +41 -0
  181. data/lib/rails_admin/config/fields/types/enum.rb +39 -0
  182. data/lib/rails_admin/config/fields/types/file_upload.rb +65 -0
  183. data/lib/rails_admin/config/fields/types/float.rb +14 -0
  184. data/lib/rails_admin/config/fields/types/has_and_belongs_to_many_association.rb +14 -0
  185. data/lib/rails_admin/config/fields/types/has_many_association.rb +32 -0
  186. data/lib/rails_admin/config/fields/types/has_one_association.rb +39 -0
  187. data/lib/rails_admin/config/fields/types/hidden.rb +27 -0
  188. data/lib/rails_admin/config/fields/types/integer.rb +22 -0
  189. data/lib/rails_admin/config/fields/types/paperclip.rb +28 -0
  190. data/lib/rails_admin/config/fields/types/password.rb +39 -0
  191. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +80 -0
  192. data/lib/rails_admin/config/fields/types/serialized.rb +22 -0
  193. data/lib/rails_admin/config/fields/types/string.rb +43 -0
  194. data/lib/rails_admin/config/fields/types/text.rb +97 -0
  195. data/lib/rails_admin/config/fields/types/time.rb +36 -0
  196. data/lib/rails_admin/config/fields/types/timestamp.rb +18 -0
  197. data/lib/rails_admin/config/groupable.rb +18 -0
  198. data/lib/rails_admin/config/has_fields.rb +136 -0
  199. data/lib/rails_admin/config/has_groups.rb +23 -0
  200. data/lib/rails_admin/config/hideable.rb +28 -0
  201. data/lib/rails_admin/config/lazy_model.rb +21 -0
  202. data/lib/rails_admin/config/model.rb +109 -0
  203. data/lib/rails_admin/config/proxyable.rb +12 -0
  204. data/lib/rails_admin/config/proxyable/proxy.rb +43 -0
  205. data/lib/rails_admin/config/sections.rb +39 -0
  206. data/lib/rails_admin/config/sections/base.rb +46 -0
  207. data/lib/rails_admin/config/sections/create.rb +11 -0
  208. data/lib/rails_admin/config/sections/edit.rb +11 -0
  209. data/lib/rails_admin/config/sections/export.rb +11 -0
  210. data/lib/rails_admin/config/sections/list.rb +27 -0
  211. data/lib/rails_admin/config/sections/modal.rb +10 -0
  212. data/lib/rails_admin/config/sections/nested.rb +10 -0
  213. data/lib/rails_admin/config/sections/show.rb +10 -0
  214. data/lib/rails_admin/config/sections/update.rb +10 -0
  215. data/lib/rails_admin/engine.rb +27 -0
  216. data/lib/rails_admin/extension.rb +29 -0
  217. data/lib/rails_admin/extensions/cancan.rb +5 -0
  218. data/lib/rails_admin/extensions/cancan/authorization_adapter.rb +59 -0
  219. data/lib/rails_admin/extensions/history.rb +5 -0
  220. data/lib/rails_admin/extensions/history/auditing_adapter.rb +37 -0
  221. data/lib/rails_admin/extensions/history/history.rb +36 -0
  222. data/lib/rails_admin/extensions/paper_trail.rb +5 -0
  223. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +93 -0
  224. data/lib/rails_admin/i18n_support.rb +43 -0
  225. data/lib/rails_admin/support/core_extensions.rb +44 -0
  226. data/lib/rails_admin/support/csv_converter.rb +105 -0
  227. data/lib/rails_admin/version.rb +18 -0
  228. data/lib/tasks/rails_admin.rake +48 -0
  229. data/spec/ci.sh +2 -0
  230. data/spec/controllers/rails_admin/application_controller_spec.rb +30 -0
  231. data/spec/controllers/rails_admin/main_controller_spec.rb +337 -0
  232. data/spec/dummy_app/Gemfile +48 -0
  233. data/spec/dummy_app/Rakefile +7 -0
  234. data/spec/dummy_app/app/active_record/abstract.rb +5 -0
  235. data/spec/dummy_app/app/active_record/another_field_test.rb +4 -0
  236. data/spec/dummy_app/app/active_record/ball.rb +9 -0
  237. data/spec/dummy_app/app/active_record/carrierwave_uploader.rb +53 -0
  238. data/spec/dummy_app/app/active_record/category.rb +5 -0
  239. data/spec/dummy_app/app/active_record/cms.rb +5 -0
  240. data/spec/dummy_app/app/active_record/cms/basic_page.rb +9 -0
  241. data/spec/dummy_app/app/active_record/cms/unscoped_page.rb +3 -0
  242. data/spec/dummy_app/app/active_record/comment.rb +5 -0
  243. data/spec/dummy_app/app/active_record/comment/confirmed.rb +3 -0
  244. data/spec/dummy_app/app/active_record/division.rb +15 -0
  245. data/spec/dummy_app/app/active_record/draft.rb +13 -0
  246. data/spec/dummy_app/app/active_record/fan.rb +7 -0
  247. data/spec/dummy_app/app/active_record/field_test.rb +19 -0
  248. data/spec/dummy_app/app/active_record/hardball.rb +2 -0
  249. data/spec/dummy_app/app/active_record/image.rb +6 -0
  250. data/spec/dummy_app/app/active_record/league.rb +12 -0
  251. data/spec/dummy_app/app/active_record/nested_field_test.rb +8 -0
  252. data/spec/dummy_app/app/active_record/player.rb +27 -0
  253. data/spec/dummy_app/app/active_record/team.rb +28 -0
  254. data/spec/dummy_app/app/active_record/user.rb +25 -0
  255. data/spec/dummy_app/app/assets/images/rails.png +0 -0
  256. data/spec/dummy_app/app/assets/javascripts/application.js +15 -0
  257. data/spec/dummy_app/app/assets/stylesheets/application.css +13 -0
  258. data/spec/dummy_app/app/controllers/application_controller.rb +3 -0
  259. data/spec/dummy_app/app/controllers/players_controller.rb +5 -0
  260. data/spec/dummy_app/app/locales/models.en.yml +20 -0
  261. data/spec/dummy_app/app/mongoid/another_field_test.rb +6 -0
  262. data/spec/dummy_app/app/mongoid/ball.rb +14 -0
  263. data/spec/dummy_app/app/mongoid/carrierwave_uploader.rb +53 -0
  264. data/spec/dummy_app/app/mongoid/category.rb +7 -0
  265. data/spec/dummy_app/app/mongoid/cms.rb +5 -0
  266. data/spec/dummy_app/app/mongoid/cms/basic_page.rb +12 -0
  267. data/spec/dummy_app/app/mongoid/cms/unscoped_page.rb +5 -0
  268. data/spec/dummy_app/app/mongoid/comment.rb +9 -0
  269. data/spec/dummy_app/app/mongoid/comment/confirmed.rb +3 -0
  270. data/spec/dummy_app/app/mongoid/division.rb +14 -0
  271. data/spec/dummy_app/app/mongoid/draft.rb +22 -0
  272. data/spec/dummy_app/app/mongoid/embed.rb +6 -0
  273. data/spec/dummy_app/app/mongoid/fan.rb +12 -0
  274. data/spec/dummy_app/app/mongoid/field_test.rb +57 -0
  275. data/spec/dummy_app/app/mongoid/hardball.rb +2 -0
  276. data/spec/dummy_app/app/mongoid/image.rb +9 -0
  277. data/spec/dummy_app/app/mongoid/league.rb +16 -0
  278. data/spec/dummy_app/app/mongoid/nested_field_test.rb +13 -0
  279. data/spec/dummy_app/app/mongoid/player.rb +41 -0
  280. data/spec/dummy_app/app/mongoid/team.rb +47 -0
  281. data/spec/dummy_app/app/mongoid/user.rb +61 -0
  282. data/spec/dummy_app/app/views/layouts/application.html.erb +14 -0
  283. data/spec/dummy_app/app/views/players/show.html.haml +1 -0
  284. data/spec/dummy_app/config.ru +4 -0
  285. data/spec/dummy_app/config/application.rb +69 -0
  286. data/spec/dummy_app/config/boot.rb +9 -0
  287. data/spec/dummy_app/config/database.yml +25 -0
  288. data/spec/dummy_app/config/environment.rb +5 -0
  289. data/spec/dummy_app/config/environments/development.rb +37 -0
  290. data/spec/dummy_app/config/environments/production.rb +67 -0
  291. data/spec/dummy_app/config/environments/test.rb +37 -0
  292. data/spec/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
  293. data/spec/dummy_app/config/initializers/devise.rb +216 -0
  294. data/spec/dummy_app/config/initializers/dragonfly.rb +11 -0
  295. data/spec/dummy_app/config/initializers/inflections.rb +15 -0
  296. data/spec/dummy_app/config/initializers/mime_types.rb +5 -0
  297. data/spec/dummy_app/config/initializers/rails_admin.rb +8 -0
  298. data/spec/dummy_app/config/initializers/secret_token.rb +7 -0
  299. data/spec/dummy_app/config/initializers/session_patch.rb +16 -0
  300. data/spec/dummy_app/config/initializers/session_store.rb +8 -0
  301. data/spec/dummy_app/config/initializers/strong_parameters.rb +2 -0
  302. data/spec/dummy_app/config/initializers/wrap_parameters.rb +14 -0
  303. data/spec/dummy_app/config/locales/fr.yml +24 -0
  304. data/spec/dummy_app/config/mongoid.yml +22 -0
  305. data/spec/dummy_app/config/routes.rb +10 -0
  306. data/spec/dummy_app/db/migrate/00000000000001_create_divisions_migration.rb +13 -0
  307. data/spec/dummy_app/db/migrate/00000000000002_create_drafts_migration.rb +19 -0
  308. data/spec/dummy_app/db/migrate/00000000000003_create_leagues_migration.rb +12 -0
  309. data/spec/dummy_app/db/migrate/00000000000004_create_players_migration.rb +20 -0
  310. data/spec/dummy_app/db/migrate/00000000000005_create_teams_migration.rb +22 -0
  311. data/spec/dummy_app/db/migrate/00000000000006_devise_create_users.rb +49 -0
  312. data/spec/dummy_app/db/migrate/00000000000007_create_histories_table.rb +16 -0
  313. data/spec/dummy_app/db/migrate/00000000000008_create_fans_migration.rb +12 -0
  314. data/spec/dummy_app/db/migrate/00000000000009_create_fans_teams_migration.rb +11 -0
  315. data/spec/dummy_app/db/migrate/00000000000010_add_revenue_to_team_migration.rb +9 -0
  316. data/spec/dummy_app/db/migrate/00000000000011_add_suspended_to_player_migration.rb +9 -0
  317. data/spec/dummy_app/db/migrate/00000000000012_add_avatar_columns_to_user.rb +16 -0
  318. data/spec/dummy_app/db/migrate/00000000000013_add_roles_to_user.rb +9 -0
  319. data/spec/dummy_app/db/migrate/00000000000014_add_color_to_team_migration.rb +9 -0
  320. data/spec/dummy_app/db/migrate/20101223222233_create_rel_tests.rb +15 -0
  321. data/spec/dummy_app/db/migrate/20110103205808_create_comments.rb +15 -0
  322. data/spec/dummy_app/db/migrate/20110123042530_rename_histories_to_rails_admin_histories.rb +9 -0
  323. data/spec/dummy_app/db/migrate/20110224184303_create_field_tests.rb +22 -0
  324. data/spec/dummy_app/db/migrate/20110328193014_create_cms_basic_pages.rb +14 -0
  325. data/spec/dummy_app/db/migrate/20110329183136_remove_league_id_from_teams.rb +9 -0
  326. data/spec/dummy_app/db/migrate/20110607152842_add_format_to_field_test.rb +9 -0
  327. data/spec/dummy_app/db/migrate/20110714095433_create_balls.rb +12 -0
  328. data/spec/dummy_app/db/migrate/20110831090841_add_protected_field_and_restricted_field_to_field_tests.rb +6 -0
  329. data/spec/dummy_app/db/migrate/20110901131551_change_division_primary_key.rb +19 -0
  330. data/spec/dummy_app/db/migrate/20110901142530_rename_league_id_foreign_key_on_divisions.rb +5 -0
  331. data/spec/dummy_app/db/migrate/20110901150912_set_primary_key_not_null_for_divisions.rb +21 -0
  332. data/spec/dummy_app/db/migrate/20110901154834_change_length_for_rails_admin_histories.rb +9 -0
  333. data/spec/dummy_app/db/migrate/20111103174459_create_unscoped_pages.rb +9 -0
  334. data/spec/dummy_app/db/migrate/20111108143642_add_dragonfly_and_carrierwave_to_field_tests.rb +7 -0
  335. data/spec/dummy_app/db/migrate/20111115041025_add_type_to_balls.rb +5 -0
  336. data/spec/dummy_app/db/migrate/20111123092549_create_nested_field_tests.rb +10 -0
  337. data/spec/dummy_app/db/migrate/20111130075338_add_dragonfly_asset_name_to_field_tests.rb +5 -0
  338. data/spec/dummy_app/db/migrate/20111215083258_create_foo_bars.rb +8 -0
  339. data/spec/dummy_app/db/migrate/20120117151733_add_custom_field_to_teams.rb +5 -0
  340. data/spec/dummy_app/db/migrate/20120118122004_add_categories.rb +7 -0
  341. data/spec/dummy_app/db/migrate/20120319041705_drop_rel_tests.rb +15 -0
  342. data/spec/dummy_app/db/migrate/20120720075608_create_another_field_tests.rb +8 -0
  343. data/spec/dummy_app/db/migrate/20120928075608_create_images.rb +8 -0
  344. data/spec/dummy_app/db/seeds.rb +29 -0
  345. data/spec/dummy_app/doc/README_FOR_APP +2 -0
  346. data/spec/dummy_app/public/404.html +26 -0
  347. data/spec/dummy_app/public/422.html +26 -0
  348. data/spec/dummy_app/public/500.html +25 -0
  349. data/spec/dummy_app/public/favicon.ico +0 -0
  350. data/spec/dummy_app/public/robots.txt +5 -0
  351. data/spec/dummy_app/public/system/dragonfly/development/2011/11/24/10_36_27_888_Pensive_Parakeet.jpg +0 -0
  352. data/spec/dummy_app/public/system/dragonfly/development/2011/11/24/10_36_27_888_Pensive_Parakeet.jpg.meta +1 -0
  353. data/spec/dummy_app/public/system/dragonfly/development/2011/11/30/08_54_39_906_Costa_Rican_Frog.jpg +0 -0
  354. data/spec/dummy_app/public/system/dragonfly/development/2011/11/30/08_54_39_906_Costa_Rican_Frog.jpg.meta +1 -0
  355. data/spec/dummy_app/public/system/paperclip_assets/1/original/Boston City Flow.jpg +0 -0
  356. data/spec/dummy_app/public/system/paperclip_assets/1/thumb/Boston City Flow.jpg +0 -0
  357. data/spec/dummy_app/public/system/paperclip_assets/3/original/Costa Rican Frog.jpg +0 -0
  358. data/spec/dummy_app/public/system/paperclip_assets/3/thumb/Costa Rican Frog.jpg +0 -0
  359. data/spec/dummy_app/public/system/paperclip_assets/6/original/liste-electorale.pdf +0 -0
  360. data/spec/dummy_app/public/system/paperclip_assets/6/thumb/liste-electorale.pdf +148 -0
  361. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/3/Boston_City_Flow.jpg +0 -0
  362. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/3/thumb_Boston_City_Flow.jpg +0 -0
  363. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/4/Costa_Rican_Frog.jpg +0 -0
  364. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/4/thumb_Costa_Rican_Frog.jpg +0 -0
  365. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/6/Pensive_Parakeet.jpg +0 -0
  366. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/6/thumb_Pensive_Parakeet.jpg +0 -0
  367. data/spec/dummy_app/script/rails +6 -0
  368. data/spec/factories.rb +75 -0
  369. data/spec/helpers/rails_admin/application_helper_spec.rb +353 -0
  370. data/spec/helpers/rails_admin/form_builder_spec.rb +17 -0
  371. data/spec/integration/authorization/cancan_spec.rb +366 -0
  372. data/spec/integration/basic/bulk_action/rails_admin_basic_bulk_action_spec.rb +25 -0
  373. data/spec/integration/basic/bulk_destroy/rails_admin_basic_bulk_destroy_spec.rb +53 -0
  374. data/spec/integration/basic/create/rails_admin_basic_create_spec.rb +140 -0
  375. data/spec/integration/basic/create/rails_admin_namespaced_model_create_spec.rb +16 -0
  376. data/spec/integration/basic/delete/rails_admin_basic_delete_spec.rb +64 -0
  377. data/spec/integration/basic/destroy/rails_admin_basic_destroy_spec.rb +84 -0
  378. data/spec/integration/basic/edit/rails_admin_basic_edit_spec.rb +109 -0
  379. data/spec/integration/basic/export/rails_admin_basic_export_spec.rb +106 -0
  380. data/spec/integration/basic/list/rails_admin_basic_list_spec.rb +444 -0
  381. data/spec/integration/basic/new/rails_admin_basic_new_spec.rb +73 -0
  382. data/spec/integration/basic/new/rails_admin_namespaced_model_new_spec.rb +31 -0
  383. data/spec/integration/basic/show/rails_admin_basic_show_spec.rb +82 -0
  384. data/spec/integration/basic/update/rails_admin_basic_update_spec.rb +229 -0
  385. data/spec/integration/config/edit/rails_admin_config_edit_spec.rb +1026 -0
  386. data/spec/integration/config/list/rails_admin_config_list_spec.rb +441 -0
  387. data/spec/integration/config/show/rails_admin_config_show_spec.rb +331 -0
  388. data/spec/integration/history/rails_admin_history_spec.rb +88 -0
  389. data/spec/integration/rails_admin_spec.rb +150 -0
  390. data/spec/integration/relation_spec.rb +35 -0
  391. data/spec/orm/active_record.rb +42 -0
  392. data/spec/orm/mongoid.rb +21 -0
  393. data/spec/rails_admin/abstract_model_spec.rb +75 -0
  394. data/spec/rails_admin/active_record_extension_spec.rb +16 -0
  395. data/spec/rails_admin/adapters/active_record/abstract_object_spec.rb +132 -0
  396. data/spec/rails_admin/adapters/active_record_spec.rb +409 -0
  397. data/spec/rails_admin/adapters/mongoid/abstract_object_spec.rb +31 -0
  398. data/spec/rails_admin/adapters/mongoid_spec.rb +776 -0
  399. data/spec/rails_admin/config/actions/base_spec.rb +32 -0
  400. data/spec/rails_admin/config/actions_spec.rb +180 -0
  401. data/spec/rails_admin/config/fields/base_spec.rb +421 -0
  402. data/spec/rails_admin/config/fields/date_spec.rb +74 -0
  403. data/spec/rails_admin/config/fields/datetime_spec.rb +55 -0
  404. data/spec/rails_admin/config/fields/file_upload_spec.rb +21 -0
  405. data/spec/rails_admin/config/fields/time_spec.rb +39 -0
  406. data/spec/rails_admin/config/fields/timestamp_spec.rb +20 -0
  407. data/spec/rails_admin/config/fields/types/datetime_spec.rb +18 -0
  408. data/spec/rails_admin/config/fields_spec.rb +15 -0
  409. data/spec/rails_admin/config/has_fields_spec.rb +30 -0
  410. data/spec/rails_admin/config/lazy_model_spec.rb +29 -0
  411. data/spec/rails_admin/config/model_spec.rb +75 -0
  412. data/spec/rails_admin/config/sections_spec.rb +123 -0
  413. data/spec/rails_admin/config_spec.rb +277 -0
  414. data/spec/rails_admin/support/csv_converter_spec.rb +16 -0
  415. data/spec/spec_helper.rb +84 -0
  416. metadata +868 -0
@@ -0,0 +1,1371 @@
1
+ /*
2
+ * jQuery UI Timepicker 0.2.9
3
+ *
4
+ * Copyright 2010-2011, Francois Gelinas
5
+ * Dual licensed under the MIT or GPL Version 2 licenses.
6
+ * http://jquery.org/license
7
+ *
8
+ * http://fgelinas.com/code/timepicker
9
+ *
10
+ * Depends:
11
+ * jquery.ui.core.js
12
+ * jquery.ui.position.js (only if position settngs are used)
13
+ *
14
+ * Change version 0.1.0 - moved the t-rex up here
15
+ *
16
+ ____
17
+ ___ .-~. /_"-._
18
+ `-._~-. / /_ "~o\ :Y
19
+ \ \ / : \~x. ` ')
20
+ ] Y / | Y< ~-.__j
21
+ / ! _.--~T : l l< /.-~
22
+ / / ____.--~ . ` l /~\ \<|Y
23
+ / / .-~~" /| . ',-~\ \L|
24
+ / / / .^ \ Y~Y \.^>/l_ "--'
25
+ / Y .-"( . l__ j_j l_/ /~_.-~ .
26
+ Y l / \ ) ~~~." / `/"~ / \.__/l_
27
+ | \ _.-" ~-{__ l : l._Z~-.___.--~
28
+ | ~---~ / ~~"---\_ ' __[>
29
+ l . _.^ ___ _>-y~
30
+ \ \ . .-~ .-~ ~>--" /
31
+ \ ~---" / ./ _.-'
32
+ "-.,_____.,_ _.--~\ _.-~
33
+ ~~ ( _} -Row
34
+ `. ~(
35
+ ) \
36
+ /,`--'~\--'~\
37
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38
+ ->T-Rex<-
39
+ */
40
+
41
+ (function ($, undefined) {
42
+
43
+ $.extend($.ui, { timepicker: { version: "0.2.9"} });
44
+
45
+ var PROP_NAME = 'timepicker';
46
+ var tpuuid = new Date().getTime();
47
+
48
+ /* Time picker manager.
49
+ Use the singleton instance of this class, $.timepicker, to interact with the time picker.
50
+ Settings for (groups of) time pickers are maintained in an instance object,
51
+ allowing multiple different settings on the same page. */
52
+
53
+ function Timepicker() {
54
+ this.debug = true; // Change this to true to start debugging
55
+ this._curInst = null; // The current instance in use
56
+ this._isInline = false; // true if the instance is displayed inline
57
+ this._disabledInputs = []; // List of time picker inputs that have been disabled
58
+ this._timepickerShowing = false; // True if the popup picker is showing , false if not
59
+ this._inDialog = false; // True if showing within a "dialog", false if not
60
+ this._dialogClass = 'ui-timepicker-dialog'; // The name of the dialog marker class
61
+ this._mainDivId = 'ui-timepicker-div'; // The ID of the main timepicker division
62
+ this._inlineClass = 'ui-timepicker-inline'; // The name of the inline marker class
63
+ this._currentClass = 'ui-timepicker-current'; // The name of the current hour / minutes marker class
64
+ this._dayOverClass = 'ui-timepicker-days-cell-over'; // The name of the day hover marker class
65
+
66
+ this.regional = []; // Available regional settings, indexed by language code
67
+ this.regional[''] = { // Default regional settings
68
+ hourText: 'Hour', // Display text for hours section
69
+ minuteText: 'Minute', // Display text for minutes link
70
+ amPmText: ['AM', 'PM'], // Display text for AM PM
71
+ closeButtonText: 'Done', // Text for the confirmation button (ok button)
72
+ nowButtonText: 'Now', // Text for the now button
73
+ deselectButtonText: 'Deselect' // Text for the deselect button
74
+ };
75
+ this._defaults = { // Global defaults for all the time picker instances
76
+ showOn: 'focus', // 'focus' for popup on focus,
77
+ // 'button' for trigger button, or 'both' for either (not yet implemented)
78
+ button: null, // 'button' element that will trigger the timepicker
79
+ showAnim: 'fadeIn', // Name of jQuery animation for popup
80
+ showOptions: {}, // Options for enhanced animations
81
+ appendText: '', // Display text following the input box, e.g. showing the format
82
+
83
+ beforeShow: null, // Define a callback function executed before the timepicker is shown
84
+ onSelect: null, // Define a callback function when a hour / minutes is selected
85
+ onClose: null, // Define a callback function when the timepicker is closed
86
+
87
+ timeSeparator: ':', // The character to use to separate hours and minutes.
88
+ periodSeparator: ' ', // The character to use to separate the time from the time period.
89
+ showPeriod: false, // Define whether or not to show AM/PM with selected time
90
+ showPeriodLabels: true, // Show the AM/PM labels on the left of the time picker
91
+ showLeadingZero: true, // Define whether or not to show a leading zero for hours < 10. [true/false]
92
+ showMinutesLeadingZero: true, // Define whether or not to show a leading zero for minutes < 10.
93
+ altField: '', // Selector for an alternate field to store selected time into
94
+ defaultTime: 'now', // Used as default time when input field is empty or for inline timePicker
95
+ // (set to 'now' for the current time, '' for no highlighted time)
96
+ myPosition: 'left top', // Position of the dialog relative to the input.
97
+ // see the position utility for more info : http://jqueryui.com/demos/position/
98
+ atPosition: 'left bottom', // Position of the input element to match
99
+ // Note : if the position utility is not loaded, the timepicker will attach left top to left bottom
100
+ //NEW: 2011-02-03
101
+ onHourShow: null, // callback for enabling / disabling on selectable hours ex : function(hour) { return true; }
102
+ onMinuteShow: null, // callback for enabling / disabling on time selection ex : function(hour,minute) { return true; }
103
+
104
+ hours: {
105
+ starts: 0, // first displayed hour
106
+ ends: 23 // last displayed hour
107
+ },
108
+ minutes: {
109
+ starts: 0, // first displayed minute
110
+ ends: 55, // last displayed minute
111
+ interval: 5 // interval of displayed minutes
112
+ },
113
+ rows: 4, // number of rows for the input tables, minimum 2, makes more sense if you use multiple of 2
114
+ // 2011-08-05 0.2.4
115
+ showHours: true, // display the hours section of the dialog
116
+ showMinutes: true, // display the minute section of the dialog
117
+ optionalMinutes: false, // optionally parse inputs of whole hours with minutes omitted
118
+
119
+ // buttons
120
+ showCloseButton: false, // shows an OK button to confirm the edit
121
+ showNowButton: false, // Shows the 'now' button
122
+ showDeselectButton: false // Shows the deselect time button
123
+
124
+ };
125
+ $.extend(this._defaults, this.regional['']);
126
+
127
+ this.tpDiv = $('<div id="' + this._mainDivId + '" class="ui-timepicker ui-widget ui-helper-clearfix ui-corner-all " style="display: none"></div>');
128
+ }
129
+
130
+ $.extend(Timepicker.prototype, {
131
+ /* Class name added to elements to indicate already configured with a time picker. */
132
+ markerClassName: 'hasTimepicker',
133
+
134
+ /* Debug logging (if enabled). */
135
+ log: function () {
136
+ if (this.debug)
137
+ console.log.apply('', arguments);
138
+ },
139
+
140
+ _widgetTimepicker: function () {
141
+ return this.tpDiv;
142
+ },
143
+
144
+ /* Override the default settings for all instances of the time picker.
145
+ @param settings object - the new settings to use as defaults (anonymous object)
146
+ @return the manager object */
147
+ setDefaults: function (settings) {
148
+ extendRemove(this._defaults, settings || {});
149
+ return this;
150
+ },
151
+
152
+ /* Attach the time picker to a jQuery selection.
153
+ @param target element - the target input field or division or span
154
+ @param settings object - the new settings to use for this time picker instance (anonymous) */
155
+ _attachTimepicker: function (target, settings) {
156
+ // check for settings on the control itself - in namespace 'time:'
157
+ var inlineSettings = null;
158
+ for (var attrName in this._defaults) {
159
+ var attrValue = target.getAttribute('time:' + attrName);
160
+ if (attrValue) {
161
+ inlineSettings = inlineSettings || {};
162
+ try {
163
+ inlineSettings[attrName] = eval(attrValue);
164
+ } catch (err) {
165
+ inlineSettings[attrName] = attrValue;
166
+ }
167
+ }
168
+ }
169
+ var nodeName = target.nodeName.toLowerCase();
170
+ var inline = (nodeName == 'div' || nodeName == 'span');
171
+
172
+ if (!target.id) {
173
+ this.uuid += 1;
174
+ target.id = 'tp' + this.uuid;
175
+ }
176
+ var inst = this._newInst($(target), inline);
177
+ inst.settings = $.extend({}, settings || {}, inlineSettings || {});
178
+ if (nodeName == 'input') {
179
+ this._connectTimepicker(target, inst);
180
+ // init inst.hours and inst.minutes from the input value
181
+ this._setTimeFromField(inst);
182
+ } else if (inline) {
183
+ this._inlineTimepicker(target, inst);
184
+ }
185
+
186
+
187
+ },
188
+
189
+ /* Create a new instance object. */
190
+ _newInst: function (target, inline) {
191
+ var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
192
+ return {
193
+ id: id, input: target, // associated target
194
+ inline: inline, // is timepicker inline or not :
195
+ tpDiv: (!inline ? this.tpDiv : // presentation div
196
+ $('<div class="' + this._inlineClass + ' ui-timepicker ui-widget ui-helper-clearfix"></div>'))
197
+ };
198
+ },
199
+
200
+ /* Attach the time picker to an input field. */
201
+ _connectTimepicker: function (target, inst) {
202
+ var input = $(target);
203
+ inst.append = $([]);
204
+ inst.trigger = $([]);
205
+ if (input.hasClass(this.markerClassName)) { return; }
206
+ this._attachments(input, inst);
207
+ input.addClass(this.markerClassName).
208
+ keydown(this._doKeyDown).
209
+ keyup(this._doKeyUp).
210
+ bind("setData.timepicker", function (event, key, value) {
211
+ inst.settings[key] = value;
212
+ }).
213
+ bind("getData.timepicker", function (event, key) {
214
+ return this._get(inst, key);
215
+ });
216
+ $.data(target, PROP_NAME, inst);
217
+ },
218
+
219
+ /* Handle keystrokes. */
220
+ _doKeyDown: function (event) {
221
+ var inst = $.timepicker._getInst(event.target);
222
+ var handled = true;
223
+ inst._keyEvent = true;
224
+ if ($.timepicker._timepickerShowing) {
225
+ switch (event.keyCode) {
226
+ case 9: $.timepicker._hideTimepicker();
227
+ handled = false;
228
+ break; // hide on tab out
229
+ case 13:
230
+ $.timepicker._updateSelectedValue(inst);
231
+ $.timepicker._hideTimepicker();
232
+
233
+ return false; // don't submit the form
234
+ break; // select the value on enter
235
+ case 27: $.timepicker._hideTimepicker();
236
+ break; // hide on escape
237
+ default: handled = false;
238
+ }
239
+ }
240
+ else if (event.keyCode == 36 && event.ctrlKey) { // display the time picker on ctrl+home
241
+ $.timepicker._showTimepicker(this);
242
+ }
243
+ else {
244
+ handled = false;
245
+ }
246
+ if (handled) {
247
+ event.preventDefault();
248
+ event.stopPropagation();
249
+ }
250
+ },
251
+
252
+ /* Update selected time on keyUp */
253
+ /* Added verion 0.0.5 */
254
+ _doKeyUp: function (event) {
255
+ var inst = $.timepicker._getInst(event.target);
256
+ $.timepicker._setTimeFromField(inst);
257
+ $.timepicker._updateTimepicker(inst);
258
+ },
259
+
260
+ /* Make attachments based on settings. */
261
+ _attachments: function (input, inst) {
262
+ var appendText = this._get(inst, 'appendText');
263
+ var isRTL = this._get(inst, 'isRTL');
264
+ if (inst.append) { inst.append.remove(); }
265
+ if (appendText) {
266
+ inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
267
+ input[isRTL ? 'before' : 'after'](inst.append);
268
+ }
269
+ input.unbind('focus.timepicker', this._showTimepicker);
270
+ input.unbind('click.timepicker', this._adjustZIndex);
271
+
272
+ if (inst.trigger) { inst.trigger.remove(); }
273
+
274
+ var showOn = this._get(inst, 'showOn');
275
+ if (showOn == 'focus' || showOn == 'both') { // pop-up time picker when in the marked field
276
+ input.bind("focus.timepicker", this._showTimepicker);
277
+ input.bind("click.timepicker", this._adjustZIndex);
278
+ }
279
+ if (showOn == 'button' || showOn == 'both') { // pop-up time picker when 'button' element is clicked
280
+ var button = this._get(inst, 'button');
281
+ $(button).bind("click.timepicker", function () {
282
+ if ($.timepicker._timepickerShowing && $.timepicker._lastInput == input[0]) {
283
+ $.timepicker._hideTimepicker();
284
+ } else if (!inst.input.is(':disabled')) {
285
+ $.timepicker._showTimepicker(input[0]);
286
+ }
287
+ return false;
288
+ });
289
+
290
+ }
291
+ },
292
+
293
+
294
+ /* Attach an inline time picker to a div. */
295
+ _inlineTimepicker: function(target, inst) {
296
+ var divSpan = $(target);
297
+ if (divSpan.hasClass(this.markerClassName))
298
+ return;
299
+ divSpan.addClass(this.markerClassName).append(inst.tpDiv).
300
+ bind("setData.timepicker", function(event, key, value){
301
+ inst.settings[key] = value;
302
+ }).bind("getData.timepicker", function(event, key){
303
+ return this._get(inst, key);
304
+ });
305
+ $.data(target, PROP_NAME, inst);
306
+
307
+ this._setTimeFromField(inst);
308
+ this._updateTimepicker(inst);
309
+ inst.tpDiv.show();
310
+ },
311
+
312
+ _adjustZIndex: function(input) {
313
+ input = input.target || input;
314
+ var inst = $.timepicker._getInst(input);
315
+ inst.tpDiv.css('zIndex', $.timepicker._getZIndex(input) +1);
316
+ },
317
+
318
+ /* Pop-up the time picker for a given input field.
319
+ @param input element - the input field attached to the time picker or
320
+ event - if triggered by focus */
321
+ _showTimepicker: function (input) {
322
+ input = input.target || input;
323
+ if (input.nodeName.toLowerCase() != 'input') { input = $('input', input.parentNode)[0]; } // find from button/image trigger
324
+
325
+ if ($.timepicker._isDisabledTimepicker(input) || $.timepicker._lastInput == input) { return; } // already here
326
+
327
+ // fix v 0.0.8 - close current timepicker before showing another one
328
+ $.timepicker._hideTimepicker();
329
+
330
+ var inst = $.timepicker._getInst(input);
331
+ if ($.timepicker._curInst && $.timepicker._curInst != inst) {
332
+ $.timepicker._curInst.tpDiv.stop(true, true);
333
+ }
334
+ var beforeShow = $.timepicker._get(inst, 'beforeShow');
335
+ extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
336
+ inst.lastVal = null;
337
+ $.timepicker._lastInput = input;
338
+
339
+ $.timepicker._setTimeFromField(inst);
340
+
341
+ // calculate default position
342
+ if ($.timepicker._inDialog) { input.value = ''; } // hide cursor
343
+ if (!$.timepicker._pos) { // position below input
344
+ $.timepicker._pos = $.timepicker._findPos(input);
345
+ $.timepicker._pos[1] += input.offsetHeight; // add the height
346
+ }
347
+ var isFixed = false;
348
+ $(input).parents().each(function () {
349
+ isFixed |= $(this).css('position') == 'fixed';
350
+ return !isFixed;
351
+ });
352
+ if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
353
+ $.timepicker._pos[0] -= document.documentElement.scrollLeft;
354
+ $.timepicker._pos[1] -= document.documentElement.scrollTop;
355
+ }
356
+
357
+ var offset = { left: $.timepicker._pos[0], top: $.timepicker._pos[1] };
358
+
359
+ $.timepicker._pos = null;
360
+ // determine sizing offscreen
361
+ inst.tpDiv.css({ position: 'absolute', display: 'block', top: '-1000px' });
362
+ $.timepicker._updateTimepicker(inst);
363
+
364
+
365
+ // position with the ui position utility, if loaded
366
+ if ( ( ! inst.inline ) && ( typeof $.ui.position == 'object' ) ) {
367
+ inst.tpDiv.position({
368
+ of: inst.input,
369
+ my: $.timepicker._get( inst, 'myPosition' ),
370
+ at: $.timepicker._get( inst, 'atPosition' ),
371
+ // offset: $( "#offset" ).val(),
372
+ // using: using,
373
+ collision: 'flip'
374
+ });
375
+ var offset = inst.tpDiv.offset();
376
+ $.timepicker._pos = [offset.top, offset.left];
377
+ }
378
+
379
+
380
+ // reset clicked state
381
+ inst._hoursClicked = false;
382
+ inst._minutesClicked = false;
383
+
384
+ // fix width for dynamic number of time pickers
385
+ // and adjust position before showing
386
+ offset = $.timepicker._checkOffset(inst, offset, isFixed);
387
+ inst.tpDiv.css({ position: ($.timepicker._inDialog && $.blockUI ?
388
+ 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
389
+ left: offset.left + 'px', top: offset.top + 'px'
390
+ });
391
+ if ( ! inst.inline ) {
392
+ var showAnim = $.timepicker._get(inst, 'showAnim');
393
+ var duration = $.timepicker._get(inst, 'duration');
394
+
395
+ var postProcess = function () {
396
+ $.timepicker._timepickerShowing = true;
397
+ var borders = $.timepicker._getBorders(inst.tpDiv);
398
+ inst.tpDiv.find('iframe.ui-timepicker-cover'). // IE6- only
399
+ css({ left: -borders[0], top: -borders[1],
400
+ width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight()
401
+ });
402
+ };
403
+
404
+ // Fixed the zIndex problem for real (I hope) - FG - v 0.2.9
405
+ $.timepicker._adjustZIndex(input);
406
+ //inst.tpDiv.css('zIndex', $.timepicker._getZIndex(input) +1);
407
+
408
+ if ($.effects && $.effects[showAnim]) {
409
+ inst.tpDiv.show(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess);
410
+ }
411
+ else {
412
+ inst.tpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
413
+ }
414
+ if (!showAnim || !duration) { postProcess(); }
415
+ if (inst.input.is(':visible') && !inst.input.is(':disabled')) { inst.input.focus(); }
416
+ $.timepicker._curInst = inst;
417
+ }
418
+ },
419
+
420
+ // This is a copy of the zIndex function of UI core 1.8.??
421
+ // Copied in the timepicker to stay backward compatible.
422
+ _getZIndex: function (target) {
423
+ var elem = $( target ), position, value;
424
+ while ( elem.length && elem[ 0 ] !== document ) {
425
+ position = elem.css( "position" );
426
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
427
+ value = parseInt( elem.css( "zIndex" ), 10 );
428
+ if ( !isNaN( value ) && value !== 0 ) {
429
+ return value;
430
+ }
431
+ }
432
+ elem = elem.parent();
433
+ }
434
+ },
435
+
436
+ /* Generate the time picker content. */
437
+ _updateTimepicker: function (inst) {
438
+ inst.tpDiv.empty().append(this._generateHTML(inst));
439
+ this._rebindDialogEvents(inst);
440
+
441
+ },
442
+
443
+ _rebindDialogEvents: function (inst) {
444
+ var borders = $.timepicker._getBorders(inst.tpDiv),
445
+ self = this;
446
+ inst.tpDiv
447
+ .find('iframe.ui-timepicker-cover') // IE6- only
448
+ .css({ left: -borders[0], top: -borders[1],
449
+ width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight()
450
+ })
451
+ .end()
452
+ // after the picker html is appended bind the click & double click events (faster in IE this way
453
+ // then letting the browser interpret the inline events)
454
+ // the binding for the minute cells also exists in _updateMinuteDisplay
455
+ .find('.ui-timepicker-minute-cell')
456
+ .unbind()
457
+ .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this))
458
+ .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this))
459
+ .end()
460
+ .find('.ui-timepicker-hour-cell')
461
+ .unbind()
462
+ .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectHours, this))
463
+ .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectHours, this))
464
+ .end()
465
+ .find('.ui-timepicker td a')
466
+ .unbind()
467
+ .bind('mouseout', function () {
468
+ $(this).removeClass('ui-state-hover');
469
+ if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).removeClass('ui-timepicker-prev-hover');
470
+ if (this.className.indexOf('ui-timepicker-next') != -1) $(this).removeClass('ui-timepicker-next-hover');
471
+ })
472
+ .bind('mouseover', function () {
473
+ if ( ! self._isDisabledTimepicker(inst.inline ? inst.tpDiv.parent()[0] : inst.input[0])) {
474
+ $(this).parents('.ui-timepicker-calendar').find('a').removeClass('ui-state-hover');
475
+ $(this).addClass('ui-state-hover');
476
+ if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).addClass('ui-timepicker-prev-hover');
477
+ if (this.className.indexOf('ui-timepicker-next') != -1) $(this).addClass('ui-timepicker-next-hover');
478
+ }
479
+ })
480
+ .end()
481
+ .find('.' + this._dayOverClass + ' a')
482
+ .trigger('mouseover')
483
+ .end()
484
+ .find('.ui-timepicker-now').bind("click",function(e) {
485
+ $.timepicker.selectNow(e);
486
+ }).end()
487
+ .find('.ui-timepicker-deselect').bind("click",function(e) {
488
+ $.timepicker.deselectTime(e);
489
+ }).end()
490
+ .find('.ui-timepicker-close').bind("click",function(e) {
491
+ $.timepicker._hideTimepicker();
492
+ }).end();
493
+ },
494
+
495
+ /* Generate the HTML for the current state of the time picker. */
496
+ _generateHTML: function (inst) {
497
+
498
+ var h, m, row, col, html, hoursHtml, minutesHtml = '',
499
+ showPeriod = (this._get(inst, 'showPeriod') == true),
500
+ showPeriodLabels = (this._get(inst, 'showPeriodLabels') == true),
501
+ showLeadingZero = (this._get(inst, 'showLeadingZero') == true),
502
+ showHours = (this._get(inst, 'showHours') == true),
503
+ showMinutes = (this._get(inst, 'showMinutes') == true),
504
+ amPmText = this._get(inst, 'amPmText'),
505
+ rows = this._get(inst, 'rows'),
506
+ amRows = 0,
507
+ pmRows = 0,
508
+ amItems = 0,
509
+ pmItems = 0,
510
+ amFirstRow = 0,
511
+ pmFirstRow = 0,
512
+ hours = Array(),
513
+ hours_options = this._get(inst, 'hours'),
514
+ hoursPerRow = null,
515
+ hourCounter = 0,
516
+ hourLabel = this._get(inst, 'hourText'),
517
+ showCloseButton = this._get(inst, 'showCloseButton'),
518
+ closeButtonText = this._get(inst, 'closeButtonText'),
519
+ showNowButton = this._get(inst, 'showNowButton'),
520
+ nowButtonText = this._get(inst, 'nowButtonText'),
521
+ showDeselectButton = this._get(inst, 'showDeselectButton'),
522
+ deselectButtonText = this._get(inst, 'deselectButtonText'),
523
+ showButtonPanel = showCloseButton || showNowButton || showDeselectButton;
524
+
525
+
526
+
527
+ // prepare all hours and minutes, makes it easier to distribute by rows
528
+ for (h = hours_options.starts; h <= hours_options.ends; h++) {
529
+ hours.push (h);
530
+ }
531
+ hoursPerRow = Math.ceil(hours.length / rows); // always round up
532
+
533
+ if (showPeriodLabels) {
534
+ for (hourCounter = 0; hourCounter < hours.length; hourCounter++) {
535
+ if (hours[hourCounter] < 12) {
536
+ amItems++;
537
+ }
538
+ else {
539
+ pmItems++;
540
+ }
541
+ }
542
+ hourCounter = 0;
543
+
544
+ amRows = Math.floor(amItems / hours.length * rows);
545
+ pmRows = Math.floor(pmItems / hours.length * rows);
546
+
547
+ // assign the extra row to the period that is more densly populated
548
+ if (rows != amRows + pmRows) {
549
+ // Make sure: AM Has Items and either PM Does Not, AM has no rows yet, or AM is more dense
550
+ if (amItems && (!pmItems || !amRows || (pmRows && amItems / amRows >= pmItems / pmRows))) {
551
+ amRows++;
552
+ } else {
553
+ pmRows++;
554
+ }
555
+ }
556
+ amFirstRow = Math.min(amRows, 1);
557
+ pmFirstRow = amRows + 1;
558
+ hoursPerRow = Math.ceil(Math.max(amItems / amRows, pmItems / pmRows));
559
+ }
560
+
561
+
562
+ html = '<table class="ui-timepicker-table ui-widget-content ui-corner-all"><tr>';
563
+
564
+ if (showHours) {
565
+
566
+ html += '<td class="ui-timepicker-hours">' +
567
+ '<div class="ui-timepicker-title ui-widget-header ui-helper-clearfix ui-corner-all">' +
568
+ hourLabel +
569
+ '</div>' +
570
+ '<table class="ui-timepicker">';
571
+
572
+ for (row = 1; row <= rows; row++) {
573
+ html += '<tr>';
574
+ // AM
575
+ if (row == amFirstRow && showPeriodLabels) {
576
+ html += '<th rowspan="' + amRows.toString() + '" class="periods" scope="row">' + amPmText[0] + '</th>';
577
+ }
578
+ // PM
579
+ if (row == pmFirstRow && showPeriodLabels) {
580
+ html += '<th rowspan="' + pmRows.toString() + '" class="periods" scope="row">' + amPmText[1] + '</th>';
581
+ }
582
+ for (col = 1; col <= hoursPerRow; col++) {
583
+ if (showPeriodLabels && row < pmFirstRow && hours[hourCounter] >= 12) {
584
+ html += this._generateHTMLHourCell(inst, undefined, showPeriod, showLeadingZero);
585
+ } else {
586
+ html += this._generateHTMLHourCell(inst, hours[hourCounter], showPeriod, showLeadingZero);
587
+ hourCounter++;
588
+ }
589
+ }
590
+ html += '</tr>';
591
+ }
592
+ html += '</tr></table>' + // Close the hours cells table
593
+ '</td>'; // Close the Hour td
594
+ }
595
+
596
+ if (showMinutes) {
597
+ html += '<td class="ui-timepicker-minutes">';
598
+ html += this._generateHTMLMinutes(inst);
599
+ html += '</td>';
600
+ }
601
+
602
+ html += '</tr>';
603
+
604
+
605
+ if (showButtonPanel) {
606
+ var buttonPanel = '<tr><td colspan="3"><div class="ui-timepicker-buttonpane ui-widget-content">';
607
+ if (showNowButton) {
608
+ buttonPanel += '<button type="button" class="ui-timepicker-now ui-state-default ui-corner-all" '
609
+ + ' data-timepicker-instance-id="#' + inst.id.replace(/\\\\/g,"\\") + '" >'
610
+ + nowButtonText + '</button>';
611
+ }
612
+ if (showDeselectButton) {
613
+ buttonPanel += '<button type="button" class="ui-timepicker-deselect ui-state-default ui-corner-all" '
614
+ + ' data-timepicker-instance-id="#' + inst.id.replace(/\\\\/g,"\\") + '" >'
615
+ + deselectButtonText + '</button>';
616
+ }
617
+ if (showCloseButton) {
618
+ buttonPanel += '<button type="button" class="ui-timepicker-close ui-state-default ui-corner-all" '
619
+ + ' data-timepicker-instance-id="#' + inst.id.replace(/\\\\/g,"\\") + '" >'
620
+ + closeButtonText + '</button>';
621
+ }
622
+
623
+ html += buttonPanel + '</div></td></tr>';
624
+ }
625
+ html += '</table>';
626
+
627
+ /* IE6 IFRAME FIX (taken from datepicker 1.5.3, fixed in 0.1.2 */
628
+ html += ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
629
+ '<iframe src="javascript:false;" class="ui-timepicker-cover" frameborder="0"></iframe>' : '');
630
+
631
+ return html;
632
+ },
633
+
634
+ /* Special function that update the minutes selection in currently visible timepicker
635
+ * called on hour selection when onMinuteShow is defined */
636
+ _updateMinuteDisplay: function (inst) {
637
+ var newHtml = this._generateHTMLMinutes(inst);
638
+ inst.tpDiv.find('td.ui-timepicker-minutes').html(newHtml);
639
+ this._rebindDialogEvents(inst);
640
+ // after the picker html is appended bind the click & double click events (faster in IE this way
641
+ // then letting the browser interpret the inline events)
642
+ // yes I know, duplicate code, sorry
643
+ /* .find('.ui-timepicker-minute-cell')
644
+ .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this))
645
+ .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this));
646
+ */
647
+
648
+ },
649
+
650
+ /*
651
+ * Generate the minutes table
652
+ * This is separated from the _generateHTML function because is can be called separately (when hours changes)
653
+ */
654
+ _generateHTMLMinutes: function (inst) {
655
+
656
+ var m, row, html = '',
657
+ rows = this._get(inst, 'rows'),
658
+ minutes = Array(),
659
+ minutes_options = this._get(inst, 'minutes'),
660
+ minutesPerRow = null,
661
+ minuteCounter = 0,
662
+ showMinutesLeadingZero = (this._get(inst, 'showMinutesLeadingZero') == true),
663
+ onMinuteShow = this._get(inst, 'onMinuteShow'),
664
+ minuteLabel = this._get(inst, 'minuteText');
665
+
666
+ if ( ! minutes_options.starts) {
667
+ minutes_options.starts = 0;
668
+ }
669
+ if ( ! minutes_options.ends) {
670
+ minutes_options.ends = 59;
671
+ }
672
+ for (m = minutes_options.starts; m <= minutes_options.ends; m += minutes_options.interval) {
673
+ minutes.push(m);
674
+ }
675
+ minutesPerRow = Math.round(minutes.length / rows + 0.49); // always round up
676
+
677
+ /*
678
+ * The minutes table
679
+ */
680
+ // if currently selected minute is not enabled, we have a problem and need to select a new minute.
681
+ if (onMinuteShow &&
682
+ (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours , inst.minutes]) == false) ) {
683
+ // loop minutes and select first available
684
+ for (minuteCounter = 0; minuteCounter < minutes.length; minuteCounter += 1) {
685
+ m = minutes[minuteCounter];
686
+ if (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours, m])) {
687
+ inst.minutes = m;
688
+ break;
689
+ }
690
+ }
691
+ }
692
+
693
+
694
+
695
+ html += '<div class="ui-timepicker-title ui-widget-header ui-helper-clearfix ui-corner-all">' +
696
+ minuteLabel +
697
+ '</div>' +
698
+ '<table class="ui-timepicker">';
699
+
700
+ minuteCounter = 0;
701
+ for (row = 1; row <= rows; row++) {
702
+ html += '<tr>';
703
+ while (minuteCounter < row * minutesPerRow) {
704
+ var m = minutes[minuteCounter];
705
+ var displayText = '';
706
+ if (m !== undefined ) {
707
+ displayText = (m < 10) && showMinutesLeadingZero ? "0" + m.toString() : m.toString();
708
+ }
709
+ html += this._generateHTMLMinuteCell(inst, m, displayText);
710
+ minuteCounter++;
711
+ }
712
+ html += '</tr>';
713
+ }
714
+
715
+ html += '</table>';
716
+
717
+ return html;
718
+ },
719
+
720
+ /* Generate the content of a "Hour" cell */
721
+ _generateHTMLHourCell: function (inst, hour, showPeriod, showLeadingZero) {
722
+
723
+ var displayHour = hour;
724
+ if ((hour > 12) && showPeriod) {
725
+ displayHour = hour - 12;
726
+ }
727
+ if ((displayHour == 0) && showPeriod) {
728
+ displayHour = 12;
729
+ }
730
+ if ((displayHour < 10) && showLeadingZero) {
731
+ displayHour = '0' + displayHour;
732
+ }
733
+
734
+ var html = "";
735
+ var enabled = true;
736
+ var onHourShow = this._get(inst, 'onHourShow'); //custom callback
737
+
738
+ if (hour == undefined) {
739
+ html = '<td><span class="ui-state-default ui-state-disabled">&nbsp;</span></td>';
740
+ return html;
741
+ }
742
+
743
+ if (onHourShow) {
744
+ enabled = onHourShow.apply((inst.input ? inst.input[0] : null), [hour]);
745
+ }
746
+
747
+ if (enabled) {
748
+ html = '<td class="ui-timepicker-hour-cell" data-timepicker-instance-id="#' + inst.id.replace(/\\\\/g,"\\") + '" data-hour="' + hour.toString() + '">' +
749
+ '<a class="ui-state-default ' +
750
+ (hour == inst.hours ? 'ui-state-active' : '') +
751
+ '">' +
752
+ displayHour.toString() +
753
+ '</a></td>';
754
+ }
755
+ else {
756
+ html =
757
+ '<td>' +
758
+ '<span class="ui-state-default ui-state-disabled ' +
759
+ (hour == inst.hours ? ' ui-state-active ' : ' ') +
760
+ '">' +
761
+ displayHour.toString() +
762
+ '</span>' +
763
+ '</td>';
764
+ }
765
+ return html;
766
+ },
767
+
768
+ /* Generate the content of a "Hour" cell */
769
+ _generateHTMLMinuteCell: function (inst, minute, displayText) {
770
+ var html = "";
771
+ var enabled = true;
772
+ var onMinuteShow = this._get(inst, 'onMinuteShow'); //custom callback
773
+ if (onMinuteShow) {
774
+ //NEW: 2011-02-03 we should give the hour as a parameter as well!
775
+ enabled = onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours,minute]); //trigger callback
776
+ }
777
+
778
+ if (minute == undefined) {
779
+ html = '<td><span class="ui-state-default ui-state-disabled">&nbsp;</span></td>';
780
+ return html;
781
+ }
782
+
783
+ if (enabled) {
784
+ html = '<td class="ui-timepicker-minute-cell" data-timepicker-instance-id="#' + inst.id.replace(/\\\\/g,"\\") + '" data-minute="' + minute.toString() + '" >' +
785
+ '<a class="ui-state-default ' +
786
+ (minute == inst.minutes ? 'ui-state-active' : '') +
787
+ '" >' +
788
+ displayText +
789
+ '</a></td>';
790
+ }
791
+ else {
792
+
793
+ html = '<td>' +
794
+ '<span class="ui-state-default ui-state-disabled" >' +
795
+ displayText +
796
+ '</span>' +
797
+ '</td>';
798
+ }
799
+ return html;
800
+ },
801
+
802
+
803
+ /* Enable the date picker to a jQuery selection.
804
+ @param target element - the target input field or division or span */
805
+ _enableTimepicker: function(target) {
806
+ var $target = $(target),
807
+ target_id = $target.attr('id'),
808
+ inst = $.data(target, PROP_NAME);
809
+
810
+ if (!$target.hasClass(this.markerClassName)) {
811
+ return;
812
+ }
813
+ var nodeName = target.nodeName.toLowerCase();
814
+ if (nodeName == 'input') {
815
+ target.disabled = false;
816
+ var button = this._get(inst, 'button');
817
+ $(button).removeClass('ui-state-disabled').disabled = false;
818
+ inst.trigger.filter('button').
819
+ each(function() { this.disabled = false; }).end();
820
+ }
821
+ else if (nodeName == 'div' || nodeName == 'span') {
822
+ var inline = $target.children('.' + this._inlineClass);
823
+ inline.children().removeClass('ui-state-disabled');
824
+ inline.find('button').each(
825
+ function() { this.disabled = false }
826
+ )
827
+ }
828
+ this._disabledInputs = $.map(this._disabledInputs,
829
+ function(value) { return (value == target_id ? null : value); }); // delete entry
830
+ },
831
+
832
+ /* Disable the time picker to a jQuery selection.
833
+ @param target element - the target input field or division or span */
834
+ _disableTimepicker: function(target) {
835
+ var $target = $(target);
836
+ var inst = $.data(target, PROP_NAME);
837
+ if (!$target.hasClass(this.markerClassName)) {
838
+ return;
839
+ }
840
+ var nodeName = target.nodeName.toLowerCase();
841
+ if (nodeName == 'input') {
842
+ var button = this._get(inst, 'button');
843
+
844
+ $(button).addClass('ui-state-disabled').disabled = true;
845
+ target.disabled = true;
846
+
847
+ inst.trigger.filter('button').
848
+ each(function() { this.disabled = true; }).end();
849
+
850
+ }
851
+ else if (nodeName == 'div' || nodeName == 'span') {
852
+ var inline = $target.children('.' + this._inlineClass);
853
+ inline.children().addClass('ui-state-disabled');
854
+ inline.find('button').each(
855
+ function() { this.disabled = true }
856
+ )
857
+
858
+ }
859
+ this._disabledInputs = $.map(this._disabledInputs,
860
+ function(value) { return (value == target ? null : value); }); // delete entry
861
+ this._disabledInputs[this._disabledInputs.length] = $target.attr('id');
862
+ },
863
+
864
+ /* Is the first field in a jQuery collection disabled as a timepicker?
865
+ @param target_id element - the target input field or division or span
866
+ @return boolean - true if disabled, false if enabled */
867
+ _isDisabledTimepicker: function (target_id) {
868
+ if ( ! target_id) { return false; }
869
+ for (var i = 0; i < this._disabledInputs.length; i++) {
870
+ if (this._disabledInputs[i] == target_id) { return true; }
871
+ }
872
+ return false;
873
+ },
874
+
875
+ /* Check positioning to remain on screen. */
876
+ _checkOffset: function (inst, offset, isFixed) {
877
+ var tpWidth = inst.tpDiv.outerWidth();
878
+ var tpHeight = inst.tpDiv.outerHeight();
879
+ var inputWidth = inst.input ? inst.input.outerWidth() : 0;
880
+ var inputHeight = inst.input ? inst.input.outerHeight() : 0;
881
+ var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
882
+ var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();
883
+
884
+ offset.left -= (this._get(inst, 'isRTL') ? (tpWidth - inputWidth) : 0);
885
+ offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
886
+ offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
887
+
888
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
889
+ offset.left -= Math.min(offset.left, (offset.left + tpWidth > viewWidth && viewWidth > tpWidth) ?
890
+ Math.abs(offset.left + tpWidth - viewWidth) : 0);
891
+ offset.top -= Math.min(offset.top, (offset.top + tpHeight > viewHeight && viewHeight > tpHeight) ?
892
+ Math.abs(tpHeight + inputHeight) : 0);
893
+
894
+ return offset;
895
+ },
896
+
897
+ /* Find an object's position on the screen. */
898
+ _findPos: function (obj) {
899
+ var inst = this._getInst(obj);
900
+ var isRTL = this._get(inst, 'isRTL');
901
+ while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
902
+ obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
903
+ }
904
+ var position = $(obj).offset();
905
+ return [position.left, position.top];
906
+ },
907
+
908
+ /* Retrieve the size of left and top borders for an element.
909
+ @param elem (jQuery object) the element of interest
910
+ @return (number[2]) the left and top borders */
911
+ _getBorders: function (elem) {
912
+ var convert = function (value) {
913
+ return { thin: 1, medium: 2, thick: 3}[value] || value;
914
+ };
915
+ return [parseFloat(convert(elem.css('border-left-width'))),
916
+ parseFloat(convert(elem.css('border-top-width')))];
917
+ },
918
+
919
+
920
+ /* Close time picker if clicked elsewhere. */
921
+ _checkExternalClick: function (event) {
922
+ if (!$.timepicker._curInst) { return; }
923
+ var $target = $(event.target);
924
+ if ($target[0].id != $.timepicker._mainDivId &&
925
+ $target.parents('#' + $.timepicker._mainDivId).length == 0 &&
926
+ !$target.hasClass($.timepicker.markerClassName) &&
927
+ !$target.hasClass($.timepicker._triggerClass) &&
928
+ $.timepicker._timepickerShowing && !($.timepicker._inDialog && $.blockUI))
929
+ $.timepicker._hideTimepicker();
930
+ },
931
+
932
+ /* Hide the time picker from view.
933
+ @param input element - the input field attached to the time picker */
934
+ _hideTimepicker: function (input) {
935
+ var inst = this._curInst;
936
+ if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; }
937
+ if (this._timepickerShowing) {
938
+ var showAnim = this._get(inst, 'showAnim');
939
+ var duration = this._get(inst, 'duration');
940
+ var postProcess = function () {
941
+ $.timepicker._tidyDialog(inst);
942
+ this._curInst = null;
943
+ };
944
+ if ($.effects && $.effects[showAnim]) {
945
+ inst.tpDiv.hide(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess);
946
+ }
947
+ else {
948
+ inst.tpDiv[(showAnim == 'slideDown' ? 'slideUp' :
949
+ (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
950
+ }
951
+ if (!showAnim) { postProcess(); }
952
+ var onClose = this._get(inst, 'onClose');
953
+ if (onClose) {
954
+ onClose.apply(
955
+ (inst.input ? inst.input[0] : null),
956
+ [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback
957
+ }
958
+ this._timepickerShowing = false;
959
+ this._lastInput = null;
960
+ if (this._inDialog) {
961
+ this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
962
+ if ($.blockUI) {
963
+ $.unblockUI();
964
+ $('body').append(this.tpDiv);
965
+ }
966
+ }
967
+ this._inDialog = false;
968
+ }
969
+ },
970
+
971
+
972
+
973
+ /* Tidy up after a dialog display. */
974
+ _tidyDialog: function (inst) {
975
+ inst.tpDiv.removeClass(this._dialogClass).unbind('.ui-timepicker');
976
+ },
977
+
978
+ /* Retrieve the instance data for the target control.
979
+ @param target element - the target input field or division or span
980
+ @return object - the associated instance data
981
+ @throws error if a jQuery problem getting data */
982
+ _getInst: function (target) {
983
+ try {
984
+ return $.data(target, PROP_NAME);
985
+ }
986
+ catch (err) {
987
+ throw 'Missing instance data for this timepicker';
988
+ }
989
+ },
990
+
991
+ /* Get a setting value, defaulting if necessary. */
992
+ _get: function (inst, name) {
993
+ return inst.settings[name] !== undefined ?
994
+ inst.settings[name] : this._defaults[name];
995
+ },
996
+
997
+ /* Parse existing time and initialise time picker. */
998
+ _setTimeFromField: function (inst) {
999
+ if (inst.input.val() == inst.lastVal) { return; }
1000
+ var defaultTime = this._get(inst, 'defaultTime');
1001
+
1002
+ var timeToParse = defaultTime == 'now' ? this._getCurrentTimeRounded(inst) : defaultTime;
1003
+ if ((inst.inline == false) && (inst.input.val() != '')) { timeToParse = inst.input.val() }
1004
+
1005
+ if (timeToParse instanceof Date) {
1006
+ inst.hours = timeToParse.getHours();
1007
+ inst.minutes = timeToParse.getMinutes();
1008
+ } else {
1009
+ var timeVal = inst.lastVal = timeToParse;
1010
+ if (timeToParse == '') {
1011
+ inst.hours = -1;
1012
+ inst.minutes = -1;
1013
+ } else {
1014
+ var time = this.parseTime(inst, timeVal);
1015
+ inst.hours = time.hours;
1016
+ inst.minutes = time.minutes;
1017
+ }
1018
+ }
1019
+
1020
+
1021
+ $.timepicker._updateTimepicker(inst);
1022
+ },
1023
+
1024
+ /* Update or retrieve the settings for an existing time picker.
1025
+ @param target element - the target input field or division or span
1026
+ @param name object - the new settings to update or
1027
+ string - the name of the setting to change or retrieve,
1028
+ when retrieving also 'all' for all instance settings or
1029
+ 'defaults' for all global defaults
1030
+ @param value any - the new value for the setting
1031
+ (omit if above is an object or to retrieve a value) */
1032
+ _optionTimepicker: function(target, name, value) {
1033
+ var inst = this._getInst(target);
1034
+ if (arguments.length == 2 && typeof name == 'string') {
1035
+ return (name == 'defaults' ? $.extend({}, $.timepicker._defaults) :
1036
+ (inst ? (name == 'all' ? $.extend({}, inst.settings) :
1037
+ this._get(inst, name)) : null));
1038
+ }
1039
+ var settings = name || {};
1040
+ if (typeof name == 'string') {
1041
+ settings = {};
1042
+ settings[name] = value;
1043
+ }
1044
+ if (inst) {
1045
+ if (this._curInst == inst) {
1046
+ this._hideTimepicker();
1047
+ }
1048
+ extendRemove(inst.settings, settings);
1049
+ this._updateTimepicker(inst);
1050
+ }
1051
+ },
1052
+
1053
+
1054
+ /* Set the time for a jQuery selection.
1055
+ @param target element - the target input field or division or span
1056
+ @param time String - the new time */
1057
+ _setTimeTimepicker: function(target, time) {
1058
+ var inst = this._getInst(target);
1059
+ if (inst) {
1060
+ this._setTime(inst, time);
1061
+ this._updateTimepicker(inst);
1062
+ this._updateAlternate(inst, time);
1063
+ }
1064
+ },
1065
+
1066
+ /* Set the time directly. */
1067
+ _setTime: function(inst, time, noChange) {
1068
+ var origHours = inst.hours;
1069
+ var origMinutes = inst.minutes;
1070
+ var time = this.parseTime(inst, time);
1071
+ inst.hours = time.hours;
1072
+ inst.minutes = time.minutes;
1073
+
1074
+ if ((origHours != inst.hours || origMinutes != inst.minuts) && !noChange) {
1075
+ inst.input.trigger('change');
1076
+ }
1077
+ this._updateTimepicker(inst);
1078
+ this._updateSelectedValue(inst);
1079
+ },
1080
+
1081
+ /* Return the current time, ready to be parsed, rounded to the closest 5 minute */
1082
+ _getCurrentTimeRounded: function (inst) {
1083
+ var currentTime = new Date(),
1084
+ currentMinutes = currentTime.getMinutes(),
1085
+ // round to closest 5
1086
+ adjustedMinutes = Math.round( currentMinutes / 5 ) * 5;
1087
+ currentTime.setMinutes(adjustedMinutes);
1088
+ return currentTime;
1089
+ },
1090
+
1091
+ /*
1092
+ * Parse a time string into hours and minutes
1093
+ */
1094
+ parseTime: function (inst, timeVal) {
1095
+ var retVal = new Object();
1096
+ retVal.hours = -1;
1097
+ retVal.minutes = -1;
1098
+
1099
+ var timeSeparator = this._get(inst, 'timeSeparator'),
1100
+ amPmText = this._get(inst, 'amPmText'),
1101
+ showHours = this._get(inst, 'showHours'),
1102
+ showMinutes = this._get(inst, 'showMinutes'),
1103
+ optionalMinutes = this._get(inst, 'optionalMinutes'),
1104
+ showPeriod = (this._get(inst, 'showPeriod') == true),
1105
+ p = timeVal.indexOf(timeSeparator);
1106
+
1107
+ // check if time separator found
1108
+ if (p != -1) {
1109
+ retVal.hours = parseInt(timeVal.substr(0, p), 10);
1110
+ retVal.minutes = parseInt(timeVal.substr(p + 1), 10);
1111
+ }
1112
+ // check for hours only
1113
+ else if ( (showHours) && ( !showMinutes || optionalMinutes ) ) {
1114
+ retVal.hours = parseInt(timeVal, 10);
1115
+ }
1116
+ // check for minutes only
1117
+ else if ( ( ! showHours) && (showMinutes) ) {
1118
+ retVal.minutes = parseInt(timeVal, 10);
1119
+ }
1120
+
1121
+ if (showHours) {
1122
+ var timeValUpper = timeVal.toUpperCase();
1123
+ if ((retVal.hours < 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[1].toUpperCase()) != -1)) {
1124
+ retVal.hours += 12;
1125
+ }
1126
+ // fix for 12 AM
1127
+ if ((retVal.hours == 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[0].toUpperCase()) != -1)) {
1128
+ retVal.hours = 0;
1129
+ }
1130
+ }
1131
+
1132
+ return retVal;
1133
+ },
1134
+
1135
+ selectNow: function(e) {
1136
+
1137
+ var id = $(e.target).attr("data-timepicker-instance-id"),
1138
+ $target = $(id),
1139
+ inst = this._getInst($target[0]);
1140
+
1141
+ //if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; }
1142
+ var currentTime = new Date();
1143
+ inst.hours = currentTime.getHours();
1144
+ inst.minutes = currentTime.getMinutes();
1145
+ this._updateSelectedValue(inst);
1146
+ this._updateTimepicker(inst);
1147
+ this._hideTimepicker();
1148
+ },
1149
+
1150
+ deselectTime: function(e) {
1151
+ var id = $(e.target).attr("data-timepicker-instance-id"),
1152
+ $target = $(id),
1153
+ inst = this._getInst($target[0]);
1154
+ inst.hours = -1;
1155
+ inst.minutes = -1;
1156
+ this._updateSelectedValue(inst);
1157
+ this._hideTimepicker();
1158
+ },
1159
+
1160
+
1161
+ selectHours: function (event) {
1162
+ var $td = $(event.currentTarget),
1163
+ id = $td.attr("data-timepicker-instance-id"),
1164
+ newHours = parseInt($td.attr("data-hour")),
1165
+ fromDoubleClick = event.data.fromDoubleClick,
1166
+ $target = $(id),
1167
+ inst = this._getInst($target[0]),
1168
+ showMinutes = (this._get(inst, 'showMinutes') == true);
1169
+
1170
+ // don't select if disabled
1171
+ if ( $.timepicker._isDisabledTimepicker($target.attr('id')) ) { return false }
1172
+
1173
+ $td.parents('.ui-timepicker-hours:first').find('a').removeClass('ui-state-active');
1174
+ $td.children('a').addClass('ui-state-active');
1175
+ inst.hours = newHours;
1176
+
1177
+ // added for onMinuteShow callback
1178
+ var onMinuteShow = this._get(inst, 'onMinuteShow');
1179
+ if (onMinuteShow) {
1180
+ // this will trigger a callback on selected hour to make sure selected minute is allowed.
1181
+ this._updateMinuteDisplay(inst);
1182
+ }
1183
+
1184
+ this._updateSelectedValue(inst);
1185
+
1186
+ inst._hoursClicked = true;
1187
+ if ((inst._minutesClicked) || (fromDoubleClick) || (showMinutes == false)) {
1188
+ $.timepicker._hideTimepicker();
1189
+ }
1190
+ // return false because if used inline, prevent the url to change to a hashtag
1191
+ return false;
1192
+ },
1193
+
1194
+ selectMinutes: function (event) {
1195
+ var $td = $(event.currentTarget),
1196
+ id = $td.attr("data-timepicker-instance-id"),
1197
+ newMinutes = parseInt($td.attr("data-minute")),
1198
+ fromDoubleClick = event.data.fromDoubleClick,
1199
+ $target = $(id),
1200
+ inst = this._getInst($target[0]),
1201
+ showHours = (this._get(inst, 'showHours') == true);
1202
+
1203
+ // don't select if disabled
1204
+ if ( $.timepicker._isDisabledTimepicker($target.attr('id')) ) { return false }
1205
+
1206
+ $td.parents('.ui-timepicker-minutes:first').find('a').removeClass('ui-state-active');
1207
+ $td.children('a').addClass('ui-state-active');
1208
+
1209
+ inst.minutes = newMinutes;
1210
+ this._updateSelectedValue(inst);
1211
+
1212
+ inst._minutesClicked = true;
1213
+ if ((inst._hoursClicked) || (fromDoubleClick) || (showHours == false)) {
1214
+ $.timepicker._hideTimepicker();
1215
+ // return false because if used inline, prevent the url to change to a hashtag
1216
+ return false;
1217
+ }
1218
+
1219
+ // return false because if used inline, prevent the url to change to a hashtag
1220
+ return false;
1221
+ },
1222
+
1223
+ _updateSelectedValue: function (inst) {
1224
+ var newTime = this._getParsedTime(inst);
1225
+ if (inst.input) {
1226
+ inst.input.val(newTime);
1227
+ inst.input.trigger('change');
1228
+ }
1229
+ var onSelect = this._get(inst, 'onSelect');
1230
+ if (onSelect) { onSelect.apply((inst.input ? inst.input[0] : null), [newTime, inst]); } // trigger custom callback
1231
+ this._updateAlternate(inst, newTime);
1232
+ return newTime;
1233
+ },
1234
+
1235
+ /* this function process selected time and return it parsed according to instance options */
1236
+ _getParsedTime: function(inst) {
1237
+
1238
+ if (inst.hours == -1 && inst.minutes == -1) {
1239
+ return '';
1240
+ }
1241
+
1242
+ if ((inst.hours < 0) || (inst.hours > 23)) { inst.hours = 12; }
1243
+ if ((inst.minutes < 0) || (inst.minutes > 59)) { inst.minutes = 0; }
1244
+
1245
+ var period = "",
1246
+ showPeriod = (this._get(inst, 'showPeriod') == true),
1247
+ showLeadingZero = (this._get(inst, 'showLeadingZero') == true),
1248
+ showHours = (this._get(inst, 'showHours') == true),
1249
+ showMinutes = (this._get(inst, 'showMinutes') == true),
1250
+ optionalMinutes = (this._get(inst, 'optionalMinutes') == true),
1251
+ amPmText = this._get(inst, 'amPmText'),
1252
+ selectedHours = inst.hours ? inst.hours : 0,
1253
+ selectedMinutes = inst.minutes ? inst.minutes : 0,
1254
+ displayHours = selectedHours ? selectedHours : 0,
1255
+ parsedTime = '';
1256
+
1257
+ if (showPeriod) {
1258
+ if (inst.hours == 0) {
1259
+ displayHours = 12;
1260
+ }
1261
+ if (inst.hours < 12) {
1262
+ period = amPmText[0];
1263
+ }
1264
+ else {
1265
+ period = amPmText[1];
1266
+ if (displayHours > 12) {
1267
+ displayHours -= 12;
1268
+ }
1269
+ }
1270
+ }
1271
+
1272
+ var h = displayHours.toString();
1273
+ if (showLeadingZero && (displayHours < 10)) { h = '0' + h; }
1274
+
1275
+ var m = selectedMinutes.toString();
1276
+ if (selectedMinutes < 10) { m = '0' + m; }
1277
+
1278
+ if (showHours) {
1279
+ parsedTime += h;
1280
+ }
1281
+ if (showHours && showMinutes && (!optionalMinutes || m != 0)) {
1282
+ parsedTime += this._get(inst, 'timeSeparator');
1283
+ }
1284
+ if (showMinutes && (!optionalMinutes || m != 0)) {
1285
+ parsedTime += m;
1286
+ }
1287
+ if (showHours) {
1288
+ if (period.length > 0) { parsedTime += this._get(inst, 'periodSeparator') + period; }
1289
+ }
1290
+
1291
+ return parsedTime;
1292
+ },
1293
+
1294
+ /* Update any alternate field to synchronise with the main field. */
1295
+ _updateAlternate: function(inst, newTime) {
1296
+ var altField = this._get(inst, 'altField');
1297
+ if (altField) { // update alternate field too
1298
+ $(altField).each(function(i,e) {
1299
+ $(e).val(newTime);
1300
+ });
1301
+ }
1302
+ },
1303
+
1304
+ /* This might look unused but it's called by the $.fn.timepicker function with param getTime */
1305
+ /* added v 0.2.3 - gitHub issue #5 - Thanks edanuff */
1306
+ _getTimeTimepicker : function(input) {
1307
+ var inst = this._getInst(input);
1308
+ return this._getParsedTime(inst);
1309
+ },
1310
+ _getHourTimepicker: function(input) {
1311
+ var inst = this._getInst(input);
1312
+ if ( inst == undefined) { return -1; }
1313
+ return inst.hours;
1314
+ },
1315
+ _getMinuteTimepicker: function(input) {
1316
+ var inst= this._getInst(input);
1317
+ if ( inst == undefined) { return -1; }
1318
+ return inst.minutes;
1319
+ }
1320
+
1321
+ });
1322
+
1323
+
1324
+
1325
+ /* Invoke the timepicker functionality.
1326
+ @param options string - a command, optionally followed by additional parameters or
1327
+ Object - settings for attaching new timepicker functionality
1328
+ @return jQuery object */
1329
+ $.fn.timepicker = function (options) {
1330
+
1331
+ /* Initialise the time picker. */
1332
+ if (!$.timepicker.initialized) {
1333
+ $(document).mousedown($.timepicker._checkExternalClick).
1334
+ find('body').append($.timepicker.tpDiv);
1335
+ $.timepicker.initialized = true;
1336
+ }
1337
+
1338
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
1339
+ if (typeof options == 'string' && (options == 'getTime' || options == 'getHour' || options == 'getMinute' ))
1340
+ return $.timepicker['_' + options + 'Timepicker'].
1341
+ apply($.timepicker, [this[0]].concat(otherArgs));
1342
+ if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
1343
+ return $.timepicker['_' + options + 'Timepicker'].
1344
+ apply($.timepicker, [this[0]].concat(otherArgs));
1345
+ return this.each(function () {
1346
+ typeof options == 'string' ?
1347
+ $.timepicker['_' + options + 'Timepicker'].
1348
+ apply($.timepicker, [this].concat(otherArgs)) :
1349
+ $.timepicker._attachTimepicker(this, options);
1350
+ });
1351
+ };
1352
+
1353
+ /* jQuery extend now ignores nulls! */
1354
+ function extendRemove(target, props) {
1355
+ $.extend(target, props);
1356
+ for (var name in props)
1357
+ if (props[name] == null || props[name] == undefined)
1358
+ target[name] = props[name];
1359
+ return target;
1360
+ };
1361
+
1362
+ $.timepicker = new Timepicker(); // singleton instance
1363
+ $.timepicker.initialized = false;
1364
+ $.timepicker.uuid = new Date().getTime();
1365
+ $.timepicker.version = "0.2.9";
1366
+
1367
+ // Workaround for #4055
1368
+ // Add another global to avoid noConflict issues with inline event handlers
1369
+ window['TP_jQuery_' + tpuuid] = $;
1370
+
1371
+ })(jQuery);