droom 0.4.3 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (396) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/images/droom/admin_menu.png +0 -0
  3. data/app/assets/images/droom/applications_menu.png +0 -0
  4. data/app/assets/images/droom/arrows_small.png +0 -0
  5. data/app/assets/images/droom/config_menu.png +0 -0
  6. data/app/assets/images/droom/dropdown.png +0 -0
  7. data/app/assets/images/droom/menu/asterisk.png +0 -0
  8. data/app/assets/images/droom/{smalladd.png → menu/smalladd.png} +0 -0
  9. data/app/assets/images/droom/{small_asterisk.png → menu/smallasterisk.png} +0 -0
  10. data/app/assets/images/droom/{smalldelete.png → menu/smalldelete.png} +0 -0
  11. data/app/assets/images/droom/{smalldownload.png → menu/smalldownload.png} +0 -0
  12. data/app/assets/images/droom/{smalledit.png → menu/smalledit.png} +0 -0
  13. data/app/assets/images/droom/message.png +0 -0
  14. data/app/assets/images/droom/missing/scrap.jpg +0 -0
  15. data/app/assets/images/droom/missing/scrap.png +0 -0
  16. data/app/assets/images/droom/missing/thumb.png +0 -0
  17. data/app/assets/images/droom/missing/user.png +0 -0
  18. data/app/assets/images/droom/object_icons.png +0 -0
  19. data/app/assets/images/droom/panel/add.png +0 -0
  20. data/app/assets/images/droom/panel/edit.png +0 -0
  21. data/app/assets/images/droom/panel/manage.png +0 -0
  22. data/app/assets/images/droom/pointer_upwards.png +0 -0
  23. data/app/assets/images/droom/search_menu.png +0 -0
  24. data/app/assets/images/droom/setter.png +0 -0
  25. data/app/assets/images/droom/small_icons.png +0 -0
  26. data/app/assets/images/droom/stream/closer.png +0 -0
  27. data/app/assets/images/droom/stream/next.png +0 -0
  28. data/app/assets/images/droom/stream/prev.png +0 -0
  29. data/app/assets/images/droom/stream/previous.png +0 -0
  30. data/app/assets/images/droom/subscribe.png +0 -0
  31. data/app/assets/javascripts/droom.js.coffee +23 -13
  32. data/app/assets/javascripts/droom/actions.js.coffee +104 -10
  33. data/app/assets/javascripts/droom/ajax.js.coffee +36 -24
  34. data/app/assets/javascripts/droom/extensions.js.coffee +13 -0
  35. data/app/assets/javascripts/droom/lib/jquery.datepicker.js +1026 -0
  36. data/app/assets/javascripts/droom/lib/jquery.deserialize.js +142 -0
  37. data/app/assets/javascripts/droom/lib/jquery_ujs.js +416 -0
  38. data/app/assets/javascripts/droom/lib/swipe.js +568 -0
  39. data/app/assets/javascripts/droom/lib/underscore.js +1276 -0
  40. data/app/assets/javascripts/droom/popups.js.coffee +98 -37
  41. data/app/assets/javascripts/droom/stream.js.coffee +119 -77
  42. data/app/assets/javascripts/droom/utilities.js.coffee +25 -3
  43. data/app/assets/javascripts/droom/widgets.js.coffee +318 -253
  44. data/app/assets/stylesheets/droom.css.sass +482 -955
  45. data/app/assets/stylesheets/droom/_mixins.css.sass +12 -42
  46. data/app/assets/stylesheets/droom/_popups.css.sass +28 -11
  47. data/app/assets/stylesheets/droom/_stream.css.sass +375 -0
  48. data/app/assets/stylesheets/droom/_toolbar.css.sass +0 -6
  49. data/app/assets/stylesheets/droom/_variables.css.sass +4 -2
  50. data/app/controllers/droom/agenda_categories_controller.rb +6 -14
  51. data/app/controllers/droom/api/api_controller.rb +56 -0
  52. data/app/controllers/droom/api/events_controller.rb +74 -0
  53. data/app/controllers/droom/api/users_controller.rb +92 -0
  54. data/app/controllers/droom/api/venues_controller.rb +71 -0
  55. data/app/controllers/droom/calendars_controller.rb +4 -10
  56. data/app/controllers/droom/{user_confirmations_controller.rb → confirmations_controller.rb} +8 -7
  57. data/app/controllers/droom/dashboard_controller.rb +2 -19
  58. data/app/controllers/droom/documents_controller.rb +12 -60
  59. data/app/controllers/droom/dropbox_tokens_controller.rb +3 -4
  60. data/app/controllers/droom/engine_controller.rb +39 -11
  61. data/app/controllers/droom/events_controller.rb +62 -84
  62. data/app/controllers/droom/folders_controller.rb +30 -40
  63. data/app/controllers/droom/group_invitations_controller.rb +6 -23
  64. data/app/controllers/droom/group_permissions_controller.rb +26 -0
  65. data/app/controllers/droom/groups_controller.rb +10 -14
  66. data/app/controllers/droom/invitations_controller.rb +7 -25
  67. data/app/controllers/droom/memberships_controller.rb +13 -18
  68. data/app/controllers/droom/organisations_controller.rb +6 -25
  69. data/app/controllers/droom/permissions_controller.rb +50 -0
  70. data/app/controllers/droom/preferences_controller.rb +9 -10
  71. data/app/controllers/droom/scraps_controller.rb +23 -26
  72. data/app/controllers/droom/services_controller.rb +50 -0
  73. data/app/controllers/droom/suggestions_controller.rb +6 -4
  74. data/app/controllers/droom/users/confirmations_controller.rb +24 -0
  75. data/app/controllers/droom/users/passwords_controller.rb +39 -0
  76. data/app/controllers/droom/users/sessions_controller.rb +7 -0
  77. data/app/controllers/droom/users_controller.rb +60 -38
  78. data/app/controllers/droom/venues_controller.rb +8 -15
  79. data/app/controllers/droom/youtube_controller.rb +1 -1
  80. data/app/helpers/droom/droom_helper.rb +22 -17
  81. data/app/models/droom/ability.rb +81 -0
  82. data/app/models/droom/agenda_category.rb +0 -1
  83. data/app/models/droom/calendar.rb +12 -7
  84. data/app/models/droom/category.rb +4 -10
  85. data/app/models/droom/concerns/slugged.rb +21 -0
  86. data/app/models/droom/document.rb +15 -17
  87. data/app/models/droom/dropbox_document.rb +3 -6
  88. data/app/models/droom/dropbox_token.rb +2 -3
  89. data/app/models/droom/event.rb +117 -163
  90. data/app/models/droom/event_type.rb +25 -0
  91. data/app/models/droom/folder.rb +36 -48
  92. data/app/models/droom/group.rb +35 -27
  93. data/app/models/droom/group_invitation.rb +7 -10
  94. data/app/models/droom/group_permission.rb +29 -0
  95. data/app/models/droom/invitation.rb +14 -23
  96. data/app/models/droom/mailing_list_membership.rb +0 -1
  97. data/app/models/droom/membership.rb +32 -31
  98. data/app/models/droom/organisation.rb +6 -3
  99. data/app/models/droom/permission.rb +19 -0
  100. data/app/models/droom/personal_folder.rb +9 -21
  101. data/app/models/droom/preference.rb +1 -2
  102. data/app/models/droom/scrap.rb +31 -26
  103. data/app/models/droom/service.rb +31 -0
  104. data/app/models/droom/tag.rb +10 -9
  105. data/app/models/droom/tagging.rb +1 -1
  106. data/app/models/droom/user.rb +453 -130
  107. data/app/models/droom/user_permission.rb +8 -0
  108. data/app/models/droom/venue.rb +21 -32
  109. data/app/serializers/droom/user_serializer.rb +45 -0
  110. data/app/serializers/droom/venue_serializer.rb +5 -0
  111. data/app/views/droom/dashboard/_documents.html.haml +1 -1
  112. data/app/views/droom/dashboard/_folders.html.haml +1 -1
  113. data/app/views/droom/dashboard/_future_events.html.haml +10 -8
  114. data/app/views/droom/dashboard/_groups.html.haml +1 -1
  115. data/app/views/droom/dashboard/_past_events.haml +19 -12
  116. data/app/views/droom/dashboard/_stream.html.haml +2 -2
  117. data/app/views/droom/{users/_extra_columns.html.haml → dashboard/_welcome.html.haml} +0 -0
  118. data/app/views/droom/dashboard/index.html.haml +3 -0
  119. data/app/views/droom/documents/_document.html.haml +0 -2
  120. data/app/views/droom/documents/_documents.html.haml +1 -1
  121. data/app/views/droom/documents/_documents_list.html.haml +1 -1
  122. data/app/views/droom/documents/_documents_table.html.haml +1 -1
  123. data/app/views/droom/documents/_form.html.haml +8 -5
  124. data/app/views/droom/documents/_listing.html.haml +4 -2
  125. data/app/views/droom/documents/index.html.haml +13 -7
  126. data/app/views/droom/documents/new.html.haml +1 -4
  127. data/app/views/droom/events/_action_menu.html.haml +2 -2
  128. data/app/views/droom/events/_attachments.html.haml +8 -0
  129. data/app/views/droom/events/_calendar.html.haml +4 -8
  130. data/app/views/droom/events/_event.html.haml +44 -63
  131. data/app/views/droom/events/_event_line.html.haml +1 -1
  132. data/app/views/droom/events/_events.html.haml +18 -2
  133. data/app/views/droom/events/_form.html.haml +26 -19
  134. data/app/views/droom/events/_invitations.html.haml +7 -3
  135. data/app/views/droom/events/_scrap_events.html.haml +8 -0
  136. data/app/views/droom/events/_suggested.html.haml +4 -1
  137. data/app/views/droom/events/calendar.html.haml +8 -0
  138. data/app/views/droom/events/index.html.haml +24 -26
  139. data/app/views/droom/events/show.html.haml +6 -6
  140. data/app/views/droom/folders/_contents.html.haml +34 -4
  141. data/app/views/droom/folders/_folder.html.haml +7 -2
  142. data/app/views/droom/folders/_form.html.haml +11 -8
  143. data/app/views/droom/folders/index.html.haml +19 -22
  144. data/app/views/droom/group_invitations/_attending_groups.html.haml +1 -1
  145. data/app/views/droom/group_permissions/_toggle.html.haml +18 -0
  146. data/app/views/droom/groups/_action_menu.haml +0 -2
  147. data/app/views/droom/groups/_created.html.haml +0 -1
  148. data/app/views/droom/groups/_form.html.haml +3 -0
  149. data/app/views/droom/groups/_group.html.haml +10 -8
  150. data/app/views/droom/groups/_groups.html.haml +1 -1
  151. data/app/views/droom/groups/_search_result.html.haml +1 -1
  152. data/app/views/droom/groups/_suggested.html.haml +1 -1
  153. data/app/views/droom/groups/index.html.haml +15 -16
  154. data/app/views/droom/invitations/_form.html.haml +1 -1
  155. data/app/views/droom/invitations/_invitation.html.haml +1 -1
  156. data/app/views/droom/invitations/_invitations.html.haml +4 -4
  157. data/app/views/droom/memberships/_button.html.haml +5 -5
  158. data/app/views/droom/memberships/_form.html.haml +26 -7
  159. data/app/views/droom/memberships/_member.html.haml +1 -1
  160. data/app/views/droom/memberships/{_membership_toggle.html.haml → _toggle.html.haml} +4 -4
  161. data/app/views/droom/memberships/index.html.haml +9 -0
  162. data/app/views/droom/organisations/_action_menu.html.haml +1 -1
  163. data/app/views/droom/organisations/_organisation.html.haml +2 -2
  164. data/app/views/droom/organisations/_suggested.html.haml +1 -1
  165. data/app/views/droom/organisations/index.html.haml +11 -11
  166. data/app/views/droom/panels/_admin.html.haml +2 -2
  167. data/app/views/droom/panels/_configuration.html.haml +28 -0
  168. data/app/views/droom/panels/_devices.html.haml +2 -4
  169. data/app/views/droom/panels/_search.html.haml +9 -0
  170. data/app/views/droom/permissions/_action_menu.html.haml +10 -0
  171. data/app/views/droom/permissions/_created.html.haml +3 -0
  172. data/app/views/droom/permissions/_form.html.haml +17 -0
  173. data/app/views/droom/permissions/edit.html.haml +7 -0
  174. data/app/views/droom/permissions/new.html.haml +8 -0
  175. data/app/views/droom/permissions/show.html.haml +4 -0
  176. data/app/views/droom/preferences/_checkbox.html.haml +4 -2
  177. data/app/views/droom/scraps/_caption.html.haml +0 -2
  178. data/app/views/droom/scraps/_credit.html.haml +1 -1
  179. data/app/views/droom/scraps/_form.html.haml +68 -69
  180. data/app/views/droom/scraps/_preload.html.haml +4 -0
  181. data/app/views/droom/scraps/_stream.html.haml +11 -3
  182. data/app/views/droom/scraps/_thumb.html.haml +33 -1
  183. data/app/views/droom/scraps/edit.html.haml +6 -1
  184. data/app/views/droom/scraps/full/_document.html.haml +4 -3
  185. data/app/views/droom/scraps/full/_event.html.haml +17 -16
  186. data/app/views/droom/scraps/full/_image.html.haml +1 -2
  187. data/app/views/droom/scraps/full/_link.html.haml +4 -3
  188. data/app/views/droom/scraps/full/_quote.html.haml +4 -7
  189. data/app/views/droom/scraps/full/_text.html.haml +3 -2
  190. data/app/views/droom/scraps/full/_video.html.haml +2 -2
  191. data/app/views/droom/scraps/new.html.haml +6 -1
  192. data/app/views/droom/scraps/show.html.haml +4 -3
  193. data/app/views/droom/services/_action_menu.html.haml +12 -0
  194. data/app/views/droom/services/_created.html.haml +3 -0
  195. data/app/views/droom/services/_form.html.haml +18 -0
  196. data/app/views/droom/services/_services.html.haml +44 -0
  197. data/app/views/droom/services/edit.html.haml +7 -0
  198. data/app/views/droom/services/index.html.haml +5 -0
  199. data/app/views/droom/{people → services}/new.html.haml +4 -3
  200. data/app/views/droom/services/show.html.haml +4 -0
  201. data/app/views/droom/shared/_controls.html.haml +2 -2
  202. data/app/views/droom/shared/_navigation.html.haml +2 -2
  203. data/app/views/droom/shared/_toolbar.html.haml +1 -1
  204. data/app/views/droom/suggestions/index.html.haml +1 -0
  205. data/app/views/droom/users/_action_menu.html.haml +21 -0
  206. data/app/views/droom/users/_suggested.html.haml +14 -0
  207. data/app/views/droom/users/_user.html.haml +2 -2
  208. data/app/views/droom/users/_users.html.haml +7 -0
  209. data/app/views/droom/users/_users_table.html.haml +21 -22
  210. data/app/views/droom/users/admin.html.haml +10 -0
  211. data/app/views/droom/users/confirmations/_after_confirmation.html.haml +2 -0
  212. data/app/views/droom/users/confirmations/_password_required.html.haml +30 -0
  213. data/app/views/droom/users/confirmations/failure.en.html.haml +22 -0
  214. data/app/views/droom/users/confirmations/show.html.haml +13 -0
  215. data/app/views/droom/users/edit.html.haml +2 -10
  216. data/app/views/droom/users/edit/_details.html.haml +13 -0
  217. data/app/views/droom/users/edit/_memberships.html.haml +13 -0
  218. data/app/views/droom/users/edit/_password_fields.html.haml +16 -0
  219. data/app/views/droom/users/edit/_preferences.html.haml +37 -0
  220. data/app/views/droom/users/edit/_profile.html.haml +26 -0
  221. data/app/views/droom/users/edit/_user_fields.html.haml +66 -0
  222. data/app/views/droom/users/index.html.haml +6 -32
  223. data/app/views/droom/users/new.html.haml +3 -0
  224. data/app/views/droom/users/passwords/completed.html.haml +13 -0
  225. data/app/views/{devise → droom/users}/passwords/edit.html.haml +10 -4
  226. data/app/views/{devise → droom/users}/passwords/new.html.haml +4 -3
  227. data/app/views/droom/users/passwords/show.html.haml +6 -0
  228. data/app/views/droom/users/show.html.haml +2 -0
  229. data/app/views/droom/users/show/_listed.html.haml +46 -0
  230. data/app/views/droom/users/show/_profile.html.haml +33 -0
  231. data/app/views/droom/users/show/_tabled.html.haml +28 -0
  232. data/config/initializers/chronic.rb +2 -0
  233. data/config/initializers/devise.rb +35 -2
  234. data/config/initializers/paperclip.rb +11 -6
  235. data/config/locales/devise.en.yml +1 -1
  236. data/config/locales/en.yml +198 -103
  237. data/config/routes.rb +37 -45
  238. data/db/migrate/20130207123614_stream.rb +5 -1
  239. data/db/migrate/20130225095328_create_droom_calendars.rb +0 -1
  240. data/db/migrate/20130627065459_permissions.rb +34 -0
  241. data/db/migrate/20130627071938_users_take_over.rb +38 -0
  242. data/db/migrate/20130627073759_user_properties.rb +34 -0
  243. data/db/migrate/20130627080021_no_more_people.rb +11 -0
  244. data/db/migrate/20130701122935_directory_groups.rb +8 -0
  245. data/db/migrate/20130701123152_remove_old_access_control.rb +16 -0
  246. data/db/migrate/20130729102857_more_scrap_data.rb +12 -0
  247. data/db/migrate/20130904080340_international_names.rb +17 -0
  248. data/db/migrate/20130904080341_honours.rb +5 -0
  249. data/db/migrate/20131124082222_simple_addresses.rb +25 -0
  250. data/db/migrate/20131201093351_event_time_zone.rb +5 -0
  251. data/db/migrate/20131217060311_session_revocable.rb +5 -0
  252. data/db/migrate/20131219180311_event_types.rb +15 -0
  253. data/lib/devise/strategies/cookie_authenticatable.rb +46 -0
  254. data/lib/droom.rb +48 -33
  255. data/lib/droom/auth_cookie.rb +82 -0
  256. data/lib/droom/cropper.rb +24 -0
  257. data/lib/droom/engine.rb +20 -2
  258. data/lib/droom/folders.rb +6 -6
  259. data/lib/droom/lazy_hash.rb +11 -1
  260. data/lib/droom/monkeys.rb +6 -6
  261. data/lib/droom/taggability.rb +1 -1
  262. data/lib/droom/validators.rb +1 -1
  263. data/lib/droom/version.rb +1 -1
  264. data/lib/generators/droom/install/templates/droom_initializer.rb +10 -2
  265. data/lib/paperclip/geometry_transformation.rb +80 -0
  266. data/lib/paperclip/validators/attachment_height_validator.rb +89 -0
  267. data/lib/paperclip/validators/attachment_width_validator.rb +89 -0
  268. data/lib/paperclip_processors/offset_thumbnail.rb +85 -0
  269. data/spec/dummy/config/application.rb +0 -7
  270. data/spec/dummy/config/environments/development.rb +1 -10
  271. data/spec/dummy/config/environments/production.rb +1 -0
  272. data/spec/dummy/config/environments/test.rb +2 -7
  273. data/spec/dummy/db/migrate/20130130120631_folder_ancestry_to_parents.droom.rb +1 -1
  274. data/spec/dummy/db/migrate/20130724124758_dropbox_tokens.droom.rb +10 -0
  275. data/spec/dummy/db/migrate/20130724124759_preference_uuids.droom.rb +6 -0
  276. data/spec/dummy/db/migrate/20130724124760_stream.droom.rb +14 -0
  277. data/spec/dummy/db/migrate/20130724124761_access_token_secret.droom.rb +6 -0
  278. data/spec/dummy/db/migrate/20130724124762_person_image.droom.rb +10 -0
  279. data/spec/dummy/db/migrate/20130724124763_devise_confirmable.droom.rb +14 -0
  280. data/spec/dummy/db/migrate/20130724124764_create_droom_calendars.droom.rb +20 -0
  281. data/spec/dummy/db/migrate/20130724124765_give_scraps_document.droom.rb +6 -0
  282. data/spec/dummy/db/migrate/20130724124766_privateness.droom.rb +10 -0
  283. data/spec/dummy/db/migrate/20130724124767_store_metadata.droom.rb +6 -0
  284. data/spec/dummy/db/migrate/20130724124768_folders_nicely.droom.rb +7 -0
  285. data/spec/dummy/db/migrate/20130724124769_niceties.droom.rb +8 -0
  286. data/spec/dummy/db/migrate/20130724124770_create_droom_dropbox_documents.droom.rb +12 -0
  287. data/spec/dummy/db/migrate/20130724124771_dropbox_documents_changed.droom.rb +6 -0
  288. data/spec/dummy/db/migrate/20130724124772_user_titles.droom.rb +6 -0
  289. data/spec/dummy/db/migrate/20130724124773_permissions.droom.rb +35 -0
  290. data/spec/dummy/db/migrate/20130724124774_users_take_over.droom.rb +39 -0
  291. data/spec/dummy/db/migrate/20130724124775_user_properties.droom.rb +35 -0
  292. data/spec/dummy/db/migrate/20130724124776_no_more_people.droom.rb +12 -0
  293. data/spec/dummy/db/migrate/20130724124777_directory_groups.droom.rb +9 -0
  294. data/spec/dummy/db/migrate/20130724124778_remove_old_access_control.droom.rb +17 -0
  295. data/spec/dummy/db/schema.rb +217 -140
  296. data/spec/factories/documents.rb +0 -5
  297. data/spec/factories/events.rb +0 -9
  298. data/spec/factories/user.rb +4 -2
  299. data/spec/lib/droom/folders_spec.rb +8 -8
  300. data/spec/models/droom/document_spec.rb +6 -43
  301. data/spec/models/droom/event_spec.rb +0 -34
  302. data/spec/models/droom/mailing_list_membership_spec.rb +4 -4
  303. data/spec/models/droom/membership_spec.rb +2 -2
  304. data/spec/spec_helper.rb +1 -10
  305. metadata +322 -282
  306. data/app/assets/images/droom/Untitled-1.png +0 -0
  307. data/app/assets/images/droom/asterisk.png +0 -0
  308. data/app/assets/images/droom/smallmanage.png +0 -0
  309. data/app/assets/javascripts/droom/lib/kalendae.js +0 -1692
  310. data/app/assets/stylesheets/lib/_kalendae.css.sass +0 -139
  311. data/app/controllers/droom/pages_controller.rb +0 -61
  312. data/app/controllers/droom/people_controller.rb +0 -111
  313. data/app/models/droom/document_attachment.rb +0 -37
  314. data/app/models/droom/page.rb +0 -26
  315. data/app/models/droom/person.rb +0 -309
  316. data/app/models/droom/recurrence_rule.rb +0 -82
  317. data/app/models/droom/user_action_observer.rb +0 -12
  318. data/app/views/devise/confirmations/failure.en.html.haml +0 -20
  319. data/app/views/devise/confirmations/show.html.haml +0 -19
  320. data/app/views/droom/confirmations/show.html.haml +0 -40
  321. data/app/views/droom/documents/_document_line.html.haml +0 -2
  322. data/app/views/droom/events/_created.html.haml +0 -2
  323. data/app/views/droom/folders/_attachments.html.haml +0 -3
  324. data/app/views/droom/pages/_contents.html.haml +0 -10
  325. data/app/views/droom/pages/_form.html.haml +0 -36
  326. data/app/views/droom/pages/_full_page.html.haml +0 -17
  327. data/app/views/droom/pages/_page.html.haml +0 -5
  328. data/app/views/droom/pages/_pages.html.haml +0 -2
  329. data/app/views/droom/pages/admin.html.haml +0 -24
  330. data/app/views/droom/pages/edit.html.haml +0 -1
  331. data/app/views/droom/pages/index.html.haml +0 -10
  332. data/app/views/droom/pages/new.html.haml +0 -4
  333. data/app/views/droom/pages/show.html.haml +0 -5
  334. data/app/views/droom/panels/_account.html.haml +0 -16
  335. data/app/views/droom/panels/_readers.html.haml +0 -18
  336. data/app/views/droom/panels/_suggestions.html.haml +0 -15
  337. data/app/views/droom/people/_action_menu.html.haml +0 -22
  338. data/app/views/droom/people/_created.html.haml +0 -6
  339. data/app/views/droom/people/_form.html.haml +0 -66
  340. data/app/views/droom/people/_listing.html.haml +0 -19
  341. data/app/views/droom/people/_memberships.html.haml +0 -24
  342. data/app/views/droom/people/_people.html.haml +0 -5
  343. data/app/views/droom/people/_person.html.haml +0 -32
  344. data/app/views/droom/people/_search_result.html.haml +0 -14
  345. data/app/views/droom/people/_suggested.html.haml +0 -14
  346. data/app/views/droom/people/edit.html.haml +0 -9
  347. data/app/views/droom/people/index.html.haml +0 -8
  348. data/app/views/droom/people/show.html.haml +0 -31
  349. data/app/views/droom/scraps/_heading.html.haml +0 -16
  350. data/app/views/droom/scraps/thumbs/_document.html.haml +0 -9
  351. data/app/views/droom/scraps/thumbs/_event.html.haml +0 -17
  352. data/app/views/droom/scraps/thumbs/_image.html.haml +0 -6
  353. data/app/views/droom/scraps/thumbs/_link.html.haml +0 -10
  354. data/app/views/droom/scraps/thumbs/_quote.html.haml +0 -8
  355. data/app/views/droom/scraps/thumbs/_text.html.haml +0 -8
  356. data/app/views/droom/scraps/thumbs/_video.html.haml +0 -6
  357. data/app/views/droom/users/_extra_columns_header.html.haml +0 -0
  358. data/app/views/droom/users/_extra_columns_note.html.haml +0 -0
  359. data/app/views/droom/users/_form.html.haml +0 -14
  360. data/app/views/droom/users/_password_fields.html.haml +0 -15
  361. data/app/views/droom/users/_user_or_person.html.haml +0 -72
  362. data/app/views/kaminari/_paginator.html.haml +0 -16
  363. data/lib/droom/dav_resource.rb +0 -36
  364. data/lib/droom/model_helpers.rb +0 -25
  365. data/lib/droom/routing.rb +0 -13
  366. data/spec/datasets/calendar_events_dataset.rb +0 -44
  367. data/spec/datasets/calendar_pages_dataset.rb +0 -8
  368. data/spec/datasets/calendar_sites_dataset.rb +0 -6
  369. data/spec/datasets/calendars_dataset.rb +0 -34
  370. data/spec/datasets/documents_dataset.rb +0 -28
  371. data/spec/datasets/recurrence_dataset.rb +0 -7
  372. data/spec/dummy/config/sunspot.yml +0 -17
  373. data/spec/dummy/log/dav.log +0 -1
  374. data/spec/dummy/log/development.log +0 -2
  375. data/spec/dummy/log/test.log +0 -1
  376. data/spec/dummy/solr/conf/admin-extra.html +0 -31
  377. data/spec/dummy/solr/conf/elevate.xml +0 -36
  378. data/spec/dummy/solr/conf/mapping-ISOLatin1Accent.txt +0 -246
  379. data/spec/dummy/solr/conf/protwords.txt +0 -21
  380. data/spec/dummy/solr/conf/schema.xml +0 -238
  381. data/spec/dummy/solr/conf/scripts.conf +0 -24
  382. data/spec/dummy/solr/conf/solrconfig.xml +0 -934
  383. data/spec/dummy/solr/conf/spellings.txt +0 -2
  384. data/spec/dummy/solr/conf/stopwords.txt +0 -58
  385. data/spec/dummy/solr/conf/synonyms.txt +0 -31
  386. data/spec/dummy/solr/data/development/index/segments.gen +0 -0
  387. data/spec/dummy/solr/data/development/index/segments_1 +0 -0
  388. data/spec/dummy/solr/data/development/spellchecker/segments.gen +0 -0
  389. data/spec/dummy/solr/data/development/spellchecker/segments_1 +0 -0
  390. data/spec/dummy/solr/data/test/index/segments.gen +0 -0
  391. data/spec/dummy/solr/data/test/index/segments_3nu +0 -0
  392. data/spec/dummy/solr/data/test/spellchecker/segments.gen +0 -0
  393. data/spec/dummy/solr/data/test/spellchecker/segments_1 +0 -0
  394. data/spec/factories/recurrence_rules.rb +0 -25
  395. data/spec/models/droom/person_spec.rb +0 -72
  396. data/spec/models/droom/recurrence_rule_spec.rb +0 -81
@@ -34,6 +34,19 @@ unless Array::empty?
34
34
  Array::empty = ()->
35
35
  @length == 0
36
36
 
37
+ # Returns true if this array contains that thing.
38
+
39
+ unless Array::contains?
40
+ Array::contains = (thing)->
41
+ @indexOf(thing) != -1
42
+
43
+ # Returns the position of that thing in this array, for the few browsers that don't already know how to do that.
44
+ unless Array::indexOf?
45
+ Array::indexOf = (elt)->
46
+ for item, i in this
47
+ return i if item is elt
48
+ return -1
49
+
37
50
  # Removes one instance of the supplied thing from an array
38
51
 
39
52
  unless Array::remove?
@@ -0,0 +1,1026 @@
1
+ /**
2
+ * DatePicker 1.0.0
3
+ *
4
+ * A jQuery-based DatePicker that provides an easy way of creating both single
5
+ * and multi-viewed calendars capable of accepting single, range, and multiple
6
+ * selected dates. Easily styled with two example styles provided: an attractive
7
+ * 'dark' style, and a Google Analytics-like 'clean' style.
8
+ *
9
+ * View project page for Examples and Documentation:
10
+ * http://foxrunsoftware.github.com/DatePicker/
11
+ *
12
+ * This project is distinct from and not affiliated with the jquery.ui.datepicker.
13
+ *
14
+ * Copyright 2012, Justin Stern (www.foxrunsoftware.net)
15
+ * Dual licensed under the MIT and GPL Version 2 licenses.
16
+ *
17
+ * Based on Work by Original Author: Stefan Petre www.eyecon.ro
18
+ *
19
+ * Depends:
20
+ * jquery.js
21
+ */
22
+ (function ($) {
23
+ var cache = {}, tmpl,
24
+ DatePicker = function () {
25
+ var ids = {},
26
+ views = {
27
+ years: 'datepickerViewYears',
28
+ moths: 'datepickerViewMonths',
29
+ days: 'datepickerViewDays'
30
+ },
31
+ tpl = {
32
+ wrapper: '<div class="datepicker"><div class="datepickerBorderT" /><div class="datepickerBorderB" /><div class="datepickerBorderL" /><div class="datepickerBorderR" /><div class="datepickerBorderTL" /><div class="datepickerBorderTR" /><div class="datepickerBorderBL" /><div class="datepickerBorderBR" /><div class="datepickerContainer"><table cellspacing="0" cellpadding="0"><tbody><tr></tr></tbody></table></div></div>',
33
+ head: [
34
+ '<td class="datepickerBlock">',
35
+ '<table cellspacing="0" cellpadding="0">',
36
+ '<thead>',
37
+ '<tr>',
38
+ '<th colspan="7"><a class="datepickerGoPrev" href="#"><span><%=prev%></span></a>',
39
+ '<a class="datepickerMonth" href="#"><span></span></a>',
40
+ '<a class="datepickerGoNext" href="#"><span><%=next%></span></a></th>',
41
+ '</tr>',
42
+ '<tr class="datepickerDoW">',
43
+ '<th><span><%=day1%></span></th>',
44
+ '<th><span><%=day2%></span></th>',
45
+ '<th><span><%=day3%></span></th>',
46
+ '<th><span><%=day4%></span></th>',
47
+ '<th><span><%=day5%></span></th>',
48
+ '<th><span><%=day6%></span></th>',
49
+ '<th><span><%=day7%></span></th>',
50
+ '</tr>',
51
+ '</thead>',
52
+ '</table></td>'
53
+ ],
54
+ space : '<td class="datepickerSpace"><div></div></td>',
55
+ days: [
56
+ '<tbody class="datepickerDays">',
57
+ '<tr>',
58
+ '<td class="<%=weeks[0].days[0].classname%>"><a href="#"><span><%=weeks[0].days[0].text%></span></a></td>',
59
+ '<td class="<%=weeks[0].days[1].classname%>"><a href="#"><span><%=weeks[0].days[1].text%></span></a></td>',
60
+ '<td class="<%=weeks[0].days[2].classname%>"><a href="#"><span><%=weeks[0].days[2].text%></span></a></td>',
61
+ '<td class="<%=weeks[0].days[3].classname%>"><a href="#"><span><%=weeks[0].days[3].text%></span></a></td>',
62
+ '<td class="<%=weeks[0].days[4].classname%>"><a href="#"><span><%=weeks[0].days[4].text%></span></a></td>',
63
+ '<td class="<%=weeks[0].days[5].classname%>"><a href="#"><span><%=weeks[0].days[5].text%></span></a></td>',
64
+ '<td class="<%=weeks[0].days[6].classname%>"><a href="#"><span><%=weeks[0].days[6].text%></span></a></td>',
65
+ '</tr>',
66
+ '<tr>',
67
+ '<td class="<%=weeks[1].days[0].classname%>"><a href="#"><span><%=weeks[1].days[0].text%></span></a></td>',
68
+ '<td class="<%=weeks[1].days[1].classname%>"><a href="#"><span><%=weeks[1].days[1].text%></span></a></td>',
69
+ '<td class="<%=weeks[1].days[2].classname%>"><a href="#"><span><%=weeks[1].days[2].text%></span></a></td>',
70
+ '<td class="<%=weeks[1].days[3].classname%>"><a href="#"><span><%=weeks[1].days[3].text%></span></a></td>',
71
+ '<td class="<%=weeks[1].days[4].classname%>"><a href="#"><span><%=weeks[1].days[4].text%></span></a></td>',
72
+ '<td class="<%=weeks[1].days[5].classname%>"><a href="#"><span><%=weeks[1].days[5].text%></span></a></td>',
73
+ '<td class="<%=weeks[1].days[6].classname%>"><a href="#"><span><%=weeks[1].days[6].text%></span></a></td>',
74
+ '</tr>',
75
+ '<tr>',
76
+ '<td class="<%=weeks[2].days[0].classname%>"><a href="#"><span><%=weeks[2].days[0].text%></span></a></td>',
77
+ '<td class="<%=weeks[2].days[1].classname%>"><a href="#"><span><%=weeks[2].days[1].text%></span></a></td>',
78
+ '<td class="<%=weeks[2].days[2].classname%>"><a href="#"><span><%=weeks[2].days[2].text%></span></a></td>',
79
+ '<td class="<%=weeks[2].days[3].classname%>"><a href="#"><span><%=weeks[2].days[3].text%></span></a></td>',
80
+ '<td class="<%=weeks[2].days[4].classname%>"><a href="#"><span><%=weeks[2].days[4].text%></span></a></td>',
81
+ '<td class="<%=weeks[2].days[5].classname%>"><a href="#"><span><%=weeks[2].days[5].text%></span></a></td>',
82
+ '<td class="<%=weeks[2].days[6].classname%>"><a href="#"><span><%=weeks[2].days[6].text%></span></a></td>',
83
+ '</tr>',
84
+ '<tr>',
85
+ '<td class="<%=weeks[3].days[0].classname%>"><a href="#"><span><%=weeks[3].days[0].text%></span></a></td>',
86
+ '<td class="<%=weeks[3].days[1].classname%>"><a href="#"><span><%=weeks[3].days[1].text%></span></a></td>',
87
+ '<td class="<%=weeks[3].days[2].classname%>"><a href="#"><span><%=weeks[3].days[2].text%></span></a></td>',
88
+ '<td class="<%=weeks[3].days[3].classname%>"><a href="#"><span><%=weeks[3].days[3].text%></span></a></td>',
89
+ '<td class="<%=weeks[3].days[4].classname%>"><a href="#"><span><%=weeks[3].days[4].text%></span></a></td>',
90
+ '<td class="<%=weeks[3].days[5].classname%>"><a href="#"><span><%=weeks[3].days[5].text%></span></a></td>',
91
+ '<td class="<%=weeks[3].days[6].classname%>"><a href="#"><span><%=weeks[3].days[6].text%></span></a></td>',
92
+ '</tr>',
93
+ '<tr>',
94
+ '<td class="<%=weeks[4].days[0].classname%>"><a href="#"><span><%=weeks[4].days[0].text%></span></a></td>',
95
+ '<td class="<%=weeks[4].days[1].classname%>"><a href="#"><span><%=weeks[4].days[1].text%></span></a></td>',
96
+ '<td class="<%=weeks[4].days[2].classname%>"><a href="#"><span><%=weeks[4].days[2].text%></span></a></td>',
97
+ '<td class="<%=weeks[4].days[3].classname%>"><a href="#"><span><%=weeks[4].days[3].text%></span></a></td>',
98
+ '<td class="<%=weeks[4].days[4].classname%>"><a href="#"><span><%=weeks[4].days[4].text%></span></a></td>',
99
+ '<td class="<%=weeks[4].days[5].classname%>"><a href="#"><span><%=weeks[4].days[5].text%></span></a></td>',
100
+ '<td class="<%=weeks[4].days[6].classname%>"><a href="#"><span><%=weeks[4].days[6].text%></span></a></td>',
101
+ '</tr>',
102
+ '<tr>',
103
+ '<td class="<%=weeks[5].days[0].classname%>"><a href="#"><span><%=weeks[5].days[0].text%></span></a></td>',
104
+ '<td class="<%=weeks[5].days[1].classname%>"><a href="#"><span><%=weeks[5].days[1].text%></span></a></td>',
105
+ '<td class="<%=weeks[5].days[2].classname%>"><a href="#"><span><%=weeks[5].days[2].text%></span></a></td>',
106
+ '<td class="<%=weeks[5].days[3].classname%>"><a href="#"><span><%=weeks[5].days[3].text%></span></a></td>',
107
+ '<td class="<%=weeks[5].days[4].classname%>"><a href="#"><span><%=weeks[5].days[4].text%></span></a></td>',
108
+ '<td class="<%=weeks[5].days[5].classname%>"><a href="#"><span><%=weeks[5].days[5].text%></span></a></td>',
109
+ '<td class="<%=weeks[5].days[6].classname%>"><a href="#"><span><%=weeks[5].days[6].text%></span></a></td>',
110
+ '</tr>',
111
+ '</tbody>'
112
+ ],
113
+ months: [
114
+ '<tbody class="<%=className%>">',
115
+ '<tr>',
116
+ '<td colspan="2"><a href="#"><span><%=data[0]%></span></a></td>',
117
+ '<td colspan="2"><a href="#"><span><%=data[1]%></span></a></td>',
118
+ '<td colspan="2"><a href="#"><span><%=data[2]%></span></a></td>',
119
+ '<td colspan="1"><a href="#"><span><%=data[3]%></span></a></td>',
120
+ '</tr>',
121
+ '<tr>',
122
+ '<td colspan="2"><a href="#"><span><%=data[4]%></span></a></td>',
123
+ '<td colspan="2"><a href="#"><span><%=data[5]%></span></a></td>',
124
+ '<td colspan="2"><a href="#"><span><%=data[6]%></span></a></td>',
125
+ '<td colspan="1"><a href="#"><span><%=data[7]%></span></a></td>',
126
+ '</tr>',
127
+ '<tr>',
128
+ '<td colspan="2"><a href="#"><span><%=data[8]%></span></a></td>',
129
+ '<td colspan="2"><a href="#"><span><%=data[9]%></span></a></td>',
130
+ '<td colspan="2"><a href="#"><span><%=data[10]%></span></a></td>',
131
+ '<td colspan="1"><a href="#"><span><%=data[11]%></span></a></td>',
132
+ '</tr>',
133
+ '</tbody>'
134
+ ]
135
+ },
136
+ defaults = {
137
+ /**
138
+ * The currently selected date(s). This can be: a single date, an array
139
+ * of two dates (sets a range when 'mode' is 'range'), or an array of
140
+ * any number of dates (selects all dates when 'mode' is 'multiple'.
141
+ * The supplied dates can be any one of: Date object, milliseconds
142
+ * (as from date.getTime(), date.valueOf()), or a date string
143
+ * parseable by Date.parse().
144
+ */
145
+ date: null,
146
+ /**
147
+ * Optional date which determines the current calendar month/year. This
148
+ * can be one of: Date object, milliseconds (as from date.getTime(), date.valueOf()), or a date string
149
+ * parseable by Date.parse(). Defaults to todays date.
150
+ */
151
+ current: null,
152
+ /**
153
+ * true causes the datepicker calendar to be appended to the DatePicker
154
+ * element and rendered, false binds the DatePicker to an event on the trigger element
155
+ */
156
+ inline: false,
157
+ /**
158
+ * Date selection mode, one of 'single', 'range' or 'multiple'. Default
159
+ * 'single'. 'Single' allows the selection of a single date, 'range'
160
+ * allows the selection of range of dates, and 'multiple' allows the
161
+ * selection of any number of individual dates.
162
+ */
163
+ mode: 'single',
164
+ /**
165
+ * Number of side-by-side calendars, defaults to 1.
166
+ */
167
+ calendars: 1,
168
+ /**
169
+ * The day that starts the week, where 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday. Defaults to Sunday
170
+ */
171
+ starts: 0,
172
+ /**
173
+ * Previous link text. Default '&#9664;' (Unicode left arrow)
174
+ */
175
+ prev: '&#9664;',
176
+ /**
177
+ * Next link text. Default '&#9664;' (Unicode left arrow)
178
+ */
179
+ next: '&#9654;',
180
+ /**
181
+ * Initial calendar view, one of 'days', 'months' or 'years'. Defaults to 'days'.
182
+ */
183
+ view: 'days',
184
+ /**
185
+ * Date picker's position relative to the trigger element (non inline
186
+ * mode only), one of 'top', 'left', 'right' or 'bottom'. Defaults to 'bottom'
187
+ */
188
+ position: 'bottom',
189
+ /**
190
+ * The trigger event used to show a non-inline calendar. Defaults to
191
+ * 'focus' which is useful when the trigger element is a text input,
192
+ * can also be 'click' for instance if the trigger element is a button
193
+ * or some text element.
194
+ */
195
+ showOn: 'focus',
196
+ /**
197
+ * Callback, invoked prior to the rendering of each date cell, which
198
+ * allows control of the styling of the cell via the returned hash.
199
+ *
200
+ * @param HTMLDivElement el the datepicker containing element, ie the
201
+ * div with class 'datepicker'
202
+ * @param Date date the date that will be rendered
203
+ * @return hash with the following optional attributes:
204
+ * selected: if true, date will be selected
205
+ * disabled: if true, date cell will be disabled
206
+ * className: css class name to add to the cell
207
+ */
208
+ onRenderCell: function() { return {} },
209
+ /*
210
+ * Callback, invoked when a date is selected, with 'this' referring to
211
+ * the HTMLElement that DatePicker was invoked upon.
212
+ *
213
+ * @param dates: Selected date(s) depending on calendar mode. When calendar mode is 'single' this
214
+ * is a single Date object. When calendar mode is 'range', this is an array containing
215
+ * a 'from' and 'to' Date objects. When calendar mode is 'multiple' this is an array
216
+ * of Date objects.
217
+ * @param HTMLElement el the DatePicker element, ie the element that DatePicker was invoked upon
218
+ */
219
+ onChange: function() { },
220
+ /*
221
+ * Callback, invoked when a date range is selected, with 'this' referring to
222
+ * the HTMLElement that DatePicker was invoked upon.
223
+ *
224
+ * @param dates: Selected date(s), ie an array containing a 'from' and 'to' Date objects.
225
+ * @param HTMLElement el the DatePicker element, ie the element that DatePicker was invoked upon
226
+ */
227
+ onRangeChange: function() { },
228
+ /**
229
+ * Invoked before a non-inline datepicker is shown, with 'this'
230
+ * referring to the HTMLElement that DatePicker was invoked upon, ie
231
+ * the trigger element
232
+ *
233
+ * @param HTMLDivElement el The datepicker container element, ie the div with class 'datepicker'.
234
+ * @return true to allow the datepicker to be shown, false to keep it hidden
235
+ */
236
+
237
+ onBeforeShow: function() { return true },
238
+ /**
239
+ * Invoked after a non-inline datepicker is shown, with 'this'
240
+ * referring to the HTMLElement that DatePicker was invoked upon, ie
241
+ * the trigger element
242
+ *
243
+ * @param HTMLDivElement el The datepicker container element, ie the div with class 'datepicker'
244
+ */
245
+ onAfterShow: function() { },
246
+ /**
247
+ * Invoked before a non-inline datepicker is hidden, with 'this'
248
+ * referring to the HTMLElement that DatePicker was invoked upon, ie
249
+ * the trigger element
250
+ *
251
+ * @param HTMLDivElement el The datepicker container element, ie the div with class 'datepicker'
252
+ * @return true to allow the datepicker to be hidden, false to keep it visible
253
+ */
254
+ onBeforeHide: function() { return true },
255
+ /**
256
+ * Invoked after a non-inline datepicker is hidden, with 'this'
257
+ * referring to the HTMLElement that DatePicker was invoked upon, ie
258
+ * the trigger element
259
+ *
260
+ * @param HTMLDivElement el The datepicker container element, ie the div with class 'datepicker'
261
+ */
262
+ onAfterHide: function() { },
263
+ /**
264
+ * Locale text for day/month names: provide a hash with keys 'daysMin', 'months' and 'monthsShort'. Default english
265
+ */
266
+ locale: {
267
+ daysMin: ["S", "M", "T", "W", "T", "F", "S"],
268
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
269
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
270
+ },
271
+ /**
272
+ * The combined height from the top/bottom borders. 'false' is the default
273
+ * and generally the correct value.
274
+ */
275
+ extraHeight: false,
276
+ /**
277
+ * The combined width from the left/right borders. 'false' is the default
278
+ * and generally the correct value.
279
+ */
280
+ extraWidth: false,
281
+ /**
282
+ * Private option, used to determine when a range is selected
283
+ */
284
+ lastSel: false
285
+ },
286
+
287
+ /**
288
+ * Internal method which renders the calendar cells
289
+ *
290
+ * @param HTMLDivElement el datepicker container element
291
+ */
292
+ fill = function(el) {
293
+ var options = $(el).data('datepicker');
294
+ var cal = $(el);
295
+ var currentCal = Math.floor(options.calendars/2), date, data, dow, month, cnt = 0, days, indic, indic2, html, tblCal;
296
+
297
+ cal.find('td>table tbody').remove();
298
+ for(var i = 0; i < options.calendars; i++) {
299
+ date = new Date(options.current);
300
+ date.addMonths(-currentCal + i);
301
+ tblCal = cal.find('table').eq(i+1);
302
+
303
+ if(i == 0) tblCal.addClass('datepickerFirstView');
304
+ if(i == options.calendars - 1) tblCal.addClass('datepickerLastView');
305
+
306
+ if(tblCal.hasClass('datepickerViewDays')) {
307
+ dow = date.getMonthName(true)+" "+date.getFullYear();
308
+ } else if(tblCal.hasClass('datepickerViewMonths')) {
309
+ dow = date.getFullYear();
310
+ } else if(tblCal.hasClass('datepickerViewYears')) {
311
+ dow = (date.getFullYear()-6) + ' - ' + (date.getFullYear()+5);
312
+ }
313
+ tblCal.find('thead tr:first th a:eq(1) span').text(dow);
314
+ dow = date.getFullYear()-6;
315
+ data = {
316
+ data: [],
317
+ className: 'datepickerYears'
318
+ }
319
+ for( var j = 0; j < 12; j++) {
320
+ data.data.push(dow + j);
321
+ }
322
+ // datepickerYears template
323
+ html = tmpl(tpl.months.join(''), data);
324
+ date.setDate(1);
325
+ data = {weeks:[], test: 10};
326
+ month = date.getMonth();
327
+ var dow = (date.getDay() - options.starts) % 7;
328
+ date.addDays(-(dow + (dow < 0 ? 7 : 0)));
329
+ cnt = 0;
330
+ while(cnt < 42) {
331
+ indic = parseInt(cnt/7,10);
332
+ indic2 = cnt%7;
333
+ if (!data.weeks[indic]) {
334
+ data.weeks[indic] = {
335
+ days: []
336
+ };
337
+ }
338
+ data.weeks[indic].days[indic2] = {
339
+ text: date.getDate(),
340
+ classname: []
341
+ };
342
+ var today = new Date();
343
+ if (today.getDate() == date.getDate() && today.getMonth() == date.getMonth() && today.getYear() == date.getYear()) {
344
+ data.weeks[indic].days[indic2].classname.push('datepickerToday');
345
+ }
346
+ if (date > today) {
347
+ // current month, date in future
348
+ data.weeks[indic].days[indic2].classname.push('datepickerFuture');
349
+ }
350
+
351
+ if (month != date.getMonth()) {
352
+ data.weeks[indic].days[indic2].classname.push('datepickerNotInMonth');
353
+ // disable clicking of the 'not in month' cells
354
+ data.weeks[indic].days[indic2].classname.push('datepickerDisabled');
355
+ }
356
+ if (date.getDay() == 0) {
357
+ data.weeks[indic].days[indic2].classname.push('datepickerSunday');
358
+ }
359
+ if (date.getDay() == 6) {
360
+ data.weeks[indic].days[indic2].classname.push('datepickerSaturday');
361
+ }
362
+ var fromUser = options.onRenderCell(el, date);
363
+ var val = date.valueOf();
364
+ if(options.date && (!$.isArray(options.date) || options.date.length > 0)) {
365
+ if (fromUser.selected || options.date == val || $.inArray(val, options.date) > -1 || (options.mode == 'range' && val >= options.date[0] && val <= options.date[1])) {
366
+ data.weeks[indic].days[indic2].classname.push('datepickerSelected');
367
+ }
368
+ }
369
+ if (fromUser.disabled) {
370
+ data.weeks[indic].days[indic2].classname.push('datepickerDisabled');
371
+ }
372
+ if (fromUser.className) {
373
+ data.weeks[indic].days[indic2].classname.push(fromUser.className);
374
+ }
375
+ data.weeks[indic].days[indic2].classname = data.weeks[indic].days[indic2].classname.join(' ');
376
+ cnt++;
377
+ date.addDays(1);
378
+ }
379
+ // Fill the datepickerDays template with data
380
+ html = tmpl(tpl.days.join(''), data) + html;
381
+
382
+ data = {
383
+ data: options.locale.monthsShort,
384
+ className: 'datepickerMonths'
385
+ };
386
+ // datepickerMonths template
387
+ html = tmpl(tpl.months.join(''), data) + html;
388
+ tblCal.append(html);
389
+ }
390
+ },
391
+
392
+ /**
393
+ * Extends the Date object with some useful helper methods
394
+ */
395
+ extendDate = function(locale) {
396
+ if (Date.prototype.tempDate) {
397
+ return;
398
+ }
399
+ Date.prototype.tempDate = null;
400
+ Date.prototype.months = locale.months;
401
+ Date.prototype.monthsShort = locale.monthsShort;
402
+ Date.prototype.getMonthName = function(fullName) {
403
+ return this[fullName ? 'months' : 'monthsShort'][this.getMonth()];
404
+ };
405
+ Date.prototype.addDays = function (n) {
406
+ this.setDate(this.getDate() + n);
407
+ this.tempDate = this.getDate();
408
+ };
409
+ Date.prototype.addMonths = function (n) {
410
+ if (this.tempDate == null) {
411
+ this.tempDate = this.getDate();
412
+ }
413
+ this.setDate(1);
414
+ this.setMonth(this.getMonth() + n);
415
+ this.setDate(Math.min(this.tempDate, this.getMaxDays()));
416
+ };
417
+ Date.prototype.addYears = function (n) {
418
+ if (this.tempDate == null) {
419
+ this.tempDate = this.getDate();
420
+ }
421
+ this.setDate(1);
422
+ this.setFullYear(this.getFullYear() + n);
423
+ this.setDate(Math.min(this.tempDate, this.getMaxDays()));
424
+ };
425
+ Date.prototype.getMaxDays = function() {
426
+ var tmpDate = new Date(Date.parse(this)),
427
+ d = 28, m;
428
+ m = tmpDate.getMonth();
429
+ d = 28;
430
+ while (tmpDate.getMonth() == m) {
431
+ d ++;
432
+ tmpDate.setDate(d);
433
+ }
434
+ return d - 1;
435
+ };
436
+ },
437
+
438
+ /**
439
+ * Internal method which lays out the calendar widget
440
+ */
441
+ layout = function(el) {
442
+ var options = $(el).data('datepicker');
443
+ var cal = $('#' + options.id);
444
+ if (options.extraHeight === false) {
445
+ var divs = $(el).find('div');
446
+ options.extraHeight = divs.get(0).offsetHeight + divs.get(1).offsetHeight; // heights from top/bottom borders
447
+ options.extraWidth = divs.get(2).offsetWidth + divs.get(3).offsetWidth; // widths from left/right borders
448
+ }
449
+ var tbl = cal.find('table:first').get(0);
450
+ var width = tbl.offsetWidth;
451
+ var height = tbl.offsetHeight;
452
+ cal.css({
453
+ width: width + options.extraWidth + 'px',
454
+ height: height + options.extraHeight + 'px'
455
+ }).find('div.datepickerContainer').css({
456
+ width: width + 'px',
457
+ height: height + 'px'
458
+ });
459
+ },
460
+
461
+ /**
462
+ * Internal method, bound to the HTML DatePicker Element, onClick.
463
+ * This is the function that controls the behavior of the calendar when
464
+ * the title, next/previous, or a date cell is clicked on.
465
+ */
466
+ click = function(ev) {
467
+ if ($(ev.target).is('span')) {
468
+ ev.target = ev.target.parentNode;
469
+ }
470
+ var el = $(ev.target);
471
+ if (el.is('a')) {
472
+ ev.target.blur();
473
+ if (el.hasClass('datepickerDisabled')) {
474
+ return false;
475
+ }
476
+ var options = $(this).data('datepicker');
477
+ var parentEl = el.parent();
478
+ var tblEl = parentEl.parent().parent().parent();
479
+ var tblIndex = $('table', this).index(tblEl.get(0)) - 1;
480
+ var tmp = new Date(options.current);
481
+ var changed = false;
482
+ var changedRange = false;
483
+ var fillIt = false;
484
+ var currentCal = Math.floor(options.calendars/2);
485
+
486
+ if (parentEl.is('th')) {
487
+ // clicking the calendar title
488
+
489
+ if (el.hasClass('datepickerMonth')) {
490
+ // clicking on the title of a Month Datepicker
491
+ tmp.addMonths(tblIndex - currentCal);
492
+
493
+ if(options.mode == 'range') {
494
+ // range, select the whole month
495
+ options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
496
+ tmp.addDays(tmp.getMaxDays()-1);
497
+ tmp.setHours(23,59,59,0);
498
+ options.date[1] = tmp.valueOf();
499
+ fillIt = true;
500
+ changed = true;
501
+ options.lastSel = false;
502
+ } else if(options.calendars == 1) {
503
+ // single/multiple mode with a single calendar: swap between daily/monthly/yearly view.
504
+ // Note: there's no reason a multi-calendar widget can't have this functionality,
505
+ // however I think it looks really unintuitive.
506
+ if(tblEl.eq(0).hasClass('datepickerViewDays')) {
507
+ tblEl.eq(0).toggleClass('datepickerViewDays datepickerViewMonths');
508
+ el.find('span').text(tmp.getFullYear());
509
+ } else if(tblEl.eq(0).hasClass('datepickerViewMonths')) {
510
+ tblEl.eq(0).toggleClass('datepickerViewMonths datepickerViewYears');
511
+ el.find('span').text((tmp.getFullYear()-6) + ' - ' + (tmp.getFullYear()+5));
512
+ } else if(tblEl.eq(0).hasClass('datepickerViewYears')) {
513
+ tblEl.eq(0).toggleClass('datepickerViewYears datepickerViewDays');
514
+ el.find('span').text(tmp.getMonthName(true)+", "+tmp.getFullYear());
515
+ }
516
+ }
517
+ } else if (parentEl.parent().parent().is('thead')) {
518
+ // clicked either next/previous arrows
519
+ if(tblEl.eq(0).hasClass('datepickerViewDays')) {
520
+ options.current.addMonths(el.hasClass('datepickerGoPrev') ? -1 : 1);
521
+ } else if(tblEl.eq(0).hasClass('datepickerViewMonths')) {
522
+ options.current.addYears(el.hasClass('datepickerGoPrev') ? -1 : 1);
523
+ } else if(tblEl.eq(0).hasClass('datepickerViewYears')) {
524
+ options.current.addYears(el.hasClass('datepickerGoPrev') ? -12 : 12);
525
+ }
526
+ fillIt = true;
527
+ }
528
+
529
+ } else if (parentEl.is('td') && !parentEl.hasClass('datepickerDisabled')) {
530
+ // clicking the calendar grid
531
+
532
+ if(tblEl.eq(0).hasClass('datepickerViewMonths')) {
533
+ // clicked a month cell
534
+ options.current.setMonth(tblEl.find('tbody.datepickerMonths td').index(parentEl));
535
+ options.current.setFullYear(parseInt(tblEl.find('thead th a.datepickerMonth span').text(), 10));
536
+ options.current.addMonths(currentCal - tblIndex);
537
+ tblEl.eq(0).toggleClass('datepickerViewMonths datepickerViewDays');
538
+ } else if(tblEl.eq(0).hasClass('datepickerViewYears')) {
539
+ // clicked a year cell
540
+ options.current.setFullYear(parseInt(el.text(), 10));
541
+ tblEl.eq(0).toggleClass('datepickerViewYears datepickerViewMonths');
542
+ } else {
543
+ // clicked a day cell
544
+ var val = parseInt(el.text(), 10);
545
+ tmp.addMonths(tblIndex - currentCal);
546
+ if (parentEl.hasClass('datepickerNotInMonth')) {
547
+ tmp.addMonths(val > 15 ? -1 : 1);
548
+ }
549
+ tmp.setDate(val);
550
+ switch (options.mode) {
551
+ case 'multiple':
552
+ val = (tmp.setHours(0,0,0,0)).valueOf();
553
+ if ($.inArray(val, options.date) > -1) {
554
+ $.each(options.date, function(nr, dat){
555
+ if (dat == val) {
556
+ options.date.splice(nr,1);
557
+ return false;
558
+ }
559
+ });
560
+ } else {
561
+ options.date.push(val);
562
+ }
563
+ break;
564
+ case 'range':
565
+ if (!options.lastSel) {
566
+ // first click: set to the start of the day
567
+ options.date[0] = (tmp.setHours(0,0,0,0)).valueOf();
568
+ }
569
+ // get the very end of the day clicked
570
+ val = (tmp.setHours(23,59,59,0)).valueOf();
571
+
572
+ if (val < options.date[0]) {
573
+ // second range click < first
574
+ options.date[1] = options.date[0] + 86399000; // starting date + 1 day
575
+ options.date[0] = val - 86399000; // minus 1 day
576
+
577
+ } else {
578
+ // initial range click, or final range click >= first
579
+ options.date[1] = val;
580
+ }
581
+ options.lastSel = !options.lastSel;
582
+ changedRange = !options.lastSel;
583
+ break;
584
+ default:
585
+ options.date = tmp.valueOf();
586
+ break;
587
+ }
588
+ changed = true;
589
+ }
590
+ fillIt = true;
591
+ }
592
+ if(fillIt) {
593
+ fill(this);
594
+ }
595
+ if(changed) {
596
+ options.onChange.apply(this, prepareDate(options));
597
+ }
598
+ if(changedRange) {
599
+ options.onRangeChange.apply(this, prepareDate(options));
600
+ }
601
+ }
602
+ return false;
603
+ },
604
+
605
+ /**
606
+ * Internal method, called from the public getDate() method, and when
607
+ * invoking the onChange callback function
608
+ *
609
+ * @param object options with the following attributes: 'mode' which can
610
+ * be one of 'single', 'range', or 'multiple'. Attribute 'date'
611
+ * which will be a single timestamp when 'mode' is 'single', or
612
+ * an array of timestamps otherwise. Attribute 'el' which is the
613
+ * HTML element that DatePicker was invoked upon.
614
+ * @return array where the first item is either a Date object, or an
615
+ * array of Date objects, depending on the DatePicker mode, and
616
+ * the second item is the HTMLElement that DatePicker was invoked
617
+ * upon.
618
+ */
619
+ prepareDate = function (options) {
620
+ var dates = null;
621
+ if (options.mode == 'single') {
622
+ if(options.date) dates = new Date(options.date);
623
+ } else {
624
+ dates = new Array();
625
+ $(options.date).each(function(i, val){
626
+ dates.push(new Date(val));
627
+ });
628
+ }
629
+ return [dates, options.el];
630
+ },
631
+
632
+ /**
633
+ * Internal method, returns an object containing the viewport dimensions
634
+ */
635
+ getViewport = function () {
636
+ var m = document.compatMode == 'CSS1Compat';
637
+ return {
638
+ l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
639
+ t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
640
+ w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
641
+ h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
642
+ };
643
+ },
644
+
645
+ /**
646
+ * Internal method, returns true if el is a child of parentEl
647
+ */
648
+ isChildOf = function(parentEl, el, container) {
649
+ if(parentEl == el) {
650
+ return true;
651
+ }
652
+ if(parentEl.contains) {
653
+ return parentEl.contains(el);
654
+ }
655
+ if( parentEl.compareDocumentPosition ) {
656
+ return !!(parentEl.compareDocumentPosition(el) & 16);
657
+ }
658
+ var prEl = el.parentNode;
659
+ while(prEl && prEl != container) {
660
+ if(prEl == parentEl)
661
+ return true;
662
+ prEl = prEl.parentNode;
663
+ }
664
+ return false;
665
+ },
666
+
667
+ /**
668
+ * Bound to the HTML DatePicker element when it's not inline, and also
669
+ * can be called directly to show the bound datepicker. A DatePicker
670
+ * calendar shown with this method will hide on a mouseclick outside
671
+ * of the calendar.
672
+ *
673
+ * Method is not applicable for inline DatePickers
674
+ */
675
+ show = function (ev) {
676
+ var cal = $('#' + $(this).data('datepickerId'));
677
+ if (!cal.is(':visible')) {
678
+ var calEl = cal.get(0);
679
+ var options = cal.data('datepicker');
680
+
681
+ var test = options.onBeforeShow.apply(this, [calEl]);
682
+ if(options.onBeforeShow.apply(this, [calEl]) == false) {
683
+ return;
684
+ }
685
+
686
+ fill(calEl);
687
+ var pos = $(this).offset();
688
+ var viewPort = getViewport();
689
+ var top = pos.top;
690
+ var left = pos.left;
691
+ cal.css({
692
+ visibility: 'hidden',
693
+ display: 'block'
694
+ });
695
+ layout(calEl);
696
+ switch (options.position){
697
+ case 'top':
698
+ top -= calEl.offsetHeight;
699
+ break;
700
+ case 'left':
701
+ left -= calEl.offsetWidth;
702
+ break;
703
+ case 'right':
704
+ left += this.offsetWidth;
705
+ break;
706
+ case 'bottom':
707
+ top += this.offsetHeight;
708
+ break;
709
+ }
710
+ if(top + calEl.offsetHeight > viewPort.t + viewPort.h) {
711
+ top = pos.top - calEl.offsetHeight;
712
+ }
713
+ if(top < viewPort.t) {
714
+ top = pos.top + this.offsetHeight + calEl.offsetHeight;
715
+ }
716
+ if(left + calEl.offsetWidth > viewPort.l + viewPort.w) {
717
+ left = pos.left - calEl.offsetWidth;
718
+ }
719
+ if(left < viewPort.l) {
720
+ left = pos.left + this.offsetWidth
721
+ }
722
+ cal.css({
723
+ visibility: 'visible',
724
+ display: 'block',
725
+ top: top + 'px',
726
+ left: left + 'px'
727
+ });
728
+ options.onAfterShow.apply(this, [cal.get(0)]);
729
+ $(document).bind('mousedown', {cal: cal, trigger: this}, hide); // global listener so clicking outside the calendar will close it
730
+ }
731
+ return false;
732
+ },
733
+
734
+ /**
735
+ * Hide a non-inline DatePicker calendar.
736
+ *
737
+ * Not applicable for inline DatePickers.
738
+ *
739
+ * @param ev Event object
740
+ */
741
+ hide = function (ev) {
742
+ if (ev.target != ev.data.trigger && !isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
743
+ if (ev.data.cal.data('datepicker').onBeforeHide.apply(this, [ev.data.cal.get(0)]) != false) {
744
+ ev.data.cal.hide();
745
+ ev.data.cal.data('datepicker').onAfterHide.apply(this, [ev.data.cal.get(0)]);
746
+ $(document).unbind('mousedown', hide); // remove the global listener
747
+ }
748
+ }
749
+ },
750
+
751
+ /**
752
+ * Internal method to normalize the selected date based on the current
753
+ * calendar mode.
754
+ */
755
+ normalizeDate = function (mode, date) {
756
+ // if range/multi mode, make sure that the current date value is at least an empty array
757
+ if(mode != 'single' && !date) date = [];
758
+
759
+ // if we have a selected date and not a null or empty array
760
+ if(date && (!$.isArray(date) || date.length > 0)) {
761
+ // Create a standardized date depending on the calendar mode
762
+ if (mode != 'single') {
763
+ if (!$.isArray(date)) {
764
+ date = [((new Date(date)).setHours(0,0,0,0)).valueOf()];
765
+ if (mode == 'range') {
766
+ // create a range of one day
767
+ date.push(((new Date(date[0])).setHours(23,59,59,0)).valueOf());
768
+ }
769
+ } else {
770
+ for (var i = 0; i < date.length; i++) {
771
+ date[i] = ((new Date(date[i])).setHours(0,0,0,0)).valueOf();
772
+ }
773
+ if (mode == 'range') {
774
+ // for range mode, create the other end of the range
775
+ if(date.length == 1) date.push(new Date(date[0]));
776
+ date[1] = ((new Date(date[1])).setHours(23,59,59,0)).valueOf();
777
+ }
778
+ }
779
+ } else {
780
+ // mode is single, convert date object into a timestamp
781
+ date = ((new Date(date)).setHours(0,0,0,0)).valueOf();
782
+ }
783
+ // at this point date is either a timestamp at hour zero
784
+ // for 'single' mode, an array of timestamps at hour zero for
785
+ // 'multiple' mode, or a two-item array with timestamps at hour
786
+ // zero and hour 23:59 for 'range' mode
787
+ }
788
+ return date;
789
+ };
790
+ return {
791
+ /**
792
+ * 'Public' functions
793
+ */
794
+
795
+ /**
796
+ * Called when element.DatePicker() is invoked
797
+ *
798
+ * Note that 'this' is the HTML element that DatePicker was invoked upon
799
+ * @see DatePicker()
800
+ */
801
+ init: function(options){
802
+ options = $.extend({}, defaults, options||{});
803
+ extendDate(options.locale);
804
+ options.calendars = Math.max(1, parseInt(options.calendars,10)||1);
805
+ options.mode = /single|multiple|range/.test(options.mode) ? options.mode : 'single';
806
+
807
+ return this.each(function(){
808
+ if (!$(this).data('datepicker')) {
809
+ options.el = this;
810
+
811
+ options.date = normalizeDate(options.mode, options.date);
812
+
813
+ if (!options.current) {
814
+ options.current = new Date();
815
+ } else {
816
+ options.current = new Date(options.current);
817
+ }
818
+ options.current.setDate(1);
819
+ options.current.setHours(0,0,0,0);
820
+
821
+ var id = 'datepicker_' + parseInt(Math.random() * 1000), cnt;
822
+ options.id = id;
823
+ $(this).data('datepickerId', options.id);
824
+ var cal = $(tpl.wrapper).attr('id', id).bind('click', click).data('datepicker', options);
825
+ if (options.className) {
826
+ cal.addClass(options.className);
827
+ }
828
+ var html = '';
829
+ for (var i = 0; i < options.calendars; i++) {
830
+ cnt = options.starts;
831
+ if (i > 0) {
832
+ html += tpl.space;
833
+ }
834
+ // calendar header template
835
+ html += tmpl(tpl.head.join(''), {
836
+ prev: options.prev,
837
+ next: options.next,
838
+ day1: options.locale.daysMin[(cnt++)%7],
839
+ day2: options.locale.daysMin[(cnt++)%7],
840
+ day3: options.locale.daysMin[(cnt++)%7],
841
+ day4: options.locale.daysMin[(cnt++)%7],
842
+ day5: options.locale.daysMin[(cnt++)%7],
843
+ day6: options.locale.daysMin[(cnt++)%7],
844
+ day7: options.locale.daysMin[(cnt++)%7]
845
+ });
846
+ }
847
+ cal
848
+ .find('tr:first').append(html)
849
+ .find('table').addClass(views[options.view]);
850
+ fill(cal.get(0));
851
+ if (options.inline) {
852
+ cal.appendTo(this).show().css('position', 'relative');
853
+ layout(cal.get(0));
854
+ } else {
855
+ cal.appendTo(document.body);
856
+ $(this).bind(options.showOn, show);
857
+ }
858
+ }
859
+ });
860
+ },
861
+
862
+ /**
863
+ * Shows the DatePicker, applicable only when the picker is not inline
864
+ *
865
+ * @return the DatePicker HTML element
866
+ * @see DatePickerShow()
867
+ */
868
+ showPicker: function() {
869
+ return this.each( function() {
870
+ if ($(this).data('datepickerId')) {
871
+ var cal = $('#' + $(this).data('datepickerId'));
872
+ var options = cal.data('datepicker');
873
+ if(!options.inline) {
874
+ show.apply(this);
875
+ }
876
+ }
877
+ });
878
+ },
879
+
880
+ /**
881
+ * Hides the DatePicker, applicable only when the picker is not inline
882
+ *
883
+ * @return the DatePicker HTML element
884
+ * @see DatePickerHide()
885
+ */
886
+ hidePicker: function() {
887
+ return this.each( function() {
888
+ if ($(this).data('datepickerId')) {
889
+ var cal = $('#' + $(this).data('datepickerId'));
890
+ var options = cal.data('datepicker');
891
+ if(!options.inline) {
892
+ $('#' + $(this).data('datepickerId')).hide();
893
+ }
894
+ }
895
+ });
896
+ },
897
+
898
+ /**
899
+ * Sets the DatePicker current date, and optionally shifts the current
900
+ * calendar to that date.
901
+ *
902
+ * @param Date|String|int|Array date The currently selected date(s).
903
+ * This can be: a single date, an array
904
+ * of two dates (sets a range when 'mode' is 'range'), or an array of
905
+ * any number of dates (selects all dates when 'mode' is 'multiple'.
906
+ * The supplied dates can be any one of: Date object, milliseconds
907
+ * (as from date.getTime(), date.valueOf()), or a date string
908
+ * parseable by Date.parse().
909
+ * @param boolean shiftTo if true, shifts the visible calendar to the
910
+ * newly set date(s)
911
+ *
912
+ * @see DatePickerSetDate()
913
+ */
914
+ setDate: function(date, shiftTo){
915
+ return this.each(function(){
916
+ if ($(this).data('datepickerId')) {
917
+ var cal = $('#' + $(this).data('datepickerId'));
918
+ var options = cal.data('datepicker');
919
+ options.date = normalizeDate(options.mode, date);
920
+
921
+ if (shiftTo) {
922
+ options.current = new Date(options.mode != 'single' ? options.date[0] : options.date);
923
+ }
924
+ fill(cal.get(0));
925
+ }
926
+ });
927
+ },
928
+
929
+ /**
930
+ * Returns the currently selected date(s) and the datepicker element.
931
+ *
932
+ * @return array where the first element is the selected date(s) When calendar mode is 'single' this
933
+ * is a single date object, or null if no date is selected. When calendar mode is 'range', this is an array containing
934
+ * a 'from' and 'to' date objects, or the empty array if no date range is selected. When calendar mode is 'multiple' this
935
+ * is an array of Date objects, or the empty array if no date is selected.
936
+ * The second element is the HTMLElement that DatePicker was invoked upon
937
+ *
938
+ * @see DatePickerGetDate()
939
+ */
940
+ getDate: function() {
941
+ if (this.size() > 0) {
942
+ return prepareDate($('#' + $(this).data('datepickerId')).data('datepicker'));
943
+ }
944
+ },
945
+
946
+ /**
947
+ * Clears the currently selected date(s)
948
+ *
949
+ * @see DatePickerClear()
950
+ */
951
+ clear: function(){
952
+ return this.each(function(){
953
+ if ($(this).data('datepickerId')) {
954
+ var cal = $('#' + $(this).data('datepickerId'));
955
+ var options = cal.data('datepicker');
956
+ if (options.mode == 'single') {
957
+ options.date = null;
958
+ } else {
959
+ options.date = [];
960
+ }
961
+ fill(cal.get(0));
962
+ }
963
+ });
964
+ },
965
+
966
+ /**
967
+ * Only applicable when the DatePicker is inline
968
+ *
969
+ * @see DatePickerLayout()
970
+ */
971
+ fixLayout: function(){
972
+ return this.each(function(){
973
+ if ($(this).data('datepickerId')) {
974
+ var cal = $('#' + $(this).data('datepickerId'));
975
+ var options = cal.data('datepicker');
976
+ if(options.inline) {
977
+ layout(cal.get(0));
978
+ }
979
+ }
980
+ });
981
+ }
982
+ };
983
+ }(); // DatePicker
984
+
985
+ // Extend jQuery with the following functions so that they can be called on HTML elements, ie: $('#widgetCalendar').DatePicker();
986
+ $.fn.extend({
987
+ DatePicker: DatePicker.init,
988
+ DatePickerHide: DatePicker.hidePicker,
989
+ DatePickerShow: DatePicker.showPicker,
990
+ DatePickerSetDate: DatePicker.setDate,
991
+ DatePickerGetDate: DatePicker.getDate,
992
+ DatePickerClear: DatePicker.clear,
993
+ DatePickerLayout: DatePicker.fixLayout
994
+ });
995
+
996
+ tmpl = function tmpl(str, data){
997
+ // Figure out if we're getting a template, or if we need to
998
+ // load the template - and be sure to cache the result.
999
+ var fn = !/\W/.test(str) ?
1000
+ cache[str] = cache[str] ||
1001
+ tmpl(document.getElementById(str).innerHTML) :
1002
+
1003
+ // Generate a reusable function that will serve as a template
1004
+ // generator (and which will be cached).
1005
+ new Function("obj",
1006
+ "var p=[],print=function(){p.push.apply(p,arguments);};" +
1007
+
1008
+ // Introduce the data as local variables using with(){}
1009
+ "with(obj){p.push('" +
1010
+
1011
+ // Convert the template into pure JavaScript
1012
+ str
1013
+ .replace(/[\r\t\n]/g, " ")
1014
+ .split("<%").join("\t")
1015
+ .replace(/((^|%>)[^\t]*)'/g, "$1\r")
1016
+ .replace(/\t=(.*?)%>/g, "',$1,'")
1017
+ .split("\t").join("');")
1018
+ .split("%>").join("p.push('")
1019
+ .split("\r").join("\\'")
1020
+ + "');}return p.join('');");
1021
+
1022
+ // Provide some basic currying to the user
1023
+ return data ? fn( data ) : fn;
1024
+ };
1025
+
1026
+ })(jQuery);