droom 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. data/README.md +2 -2
  2. data/app/assets/images/droom/Untitled-1.png +0 -0
  3. data/app/assets/images/droom/acceptance.png +0 -0
  4. data/app/assets/images/droom/add.png +0 -0
  5. data/app/assets/images/droom/asterisk.png +0 -0
  6. data/app/assets/images/droom/asterisk_up.png +0 -0
  7. data/app/assets/images/droom/checkboxes.png +0 -0
  8. data/app/assets/images/droom/clear.png +0 -0
  9. data/app/assets/images/droom/cog.png +0 -0
  10. data/app/assets/images/droom/copy.png +0 -0
  11. data/app/assets/images/droom/copy_to_dropbox.png +0 -0
  12. data/app/assets/images/droom/crosses.png +0 -0
  13. data/app/assets/images/droom/dark_scrap_icons.png +0 -0
  14. data/app/assets/images/droom/defilter.png +0 -0
  15. data/app/assets/images/droom/delete.png +0 -0
  16. data/app/assets/images/droom/dropbox.png +0 -0
  17. data/app/assets/images/droom/dropbox_button.png +0 -0
  18. data/app/assets/images/droom/dropbox_button_small.png +0 -0
  19. data/app/assets/images/droom/edit.png +0 -0
  20. data/app/assets/images/droom/expand.png +0 -0
  21. data/app/assets/images/droom/expander.png +0 -0
  22. data/app/assets/images/droom/folder.png +0 -0
  23. data/app/assets/images/droom/image_box.png +0 -0
  24. data/app/assets/images/droom/in_dropbox.png +0 -0
  25. data/app/assets/images/droom/integration_buttons.png +0 -0
  26. data/app/assets/images/droom/leftright.png +0 -0
  27. data/app/assets/images/droom/manage.png +0 -0
  28. data/app/assets/images/droom/medium_object_icons.png +0 -0
  29. data/app/assets/images/droom/object_icons.png +0 -0
  30. data/app/assets/images/droom/playable.png +0 -0
  31. data/app/assets/images/droom/revoke.png +0 -0
  32. data/app/assets/images/droom/scrap_icons.png +0 -0
  33. data/app/assets/images/droom/search.png +0 -0
  34. data/app/assets/images/droom/small_asterisk.png +0 -0
  35. data/app/assets/images/droom/small_cog.png +0 -0
  36. data/app/assets/images/droom/small_download.png +0 -0
  37. data/app/assets/images/droom/small_image_box.png +0 -0
  38. data/app/assets/images/droom/smalladd.png +0 -0
  39. data/app/assets/images/droom/smallarrows.png +0 -0
  40. data/app/assets/images/droom/smallcopy.png +0 -0
  41. data/app/assets/images/droom/smalldelete.png +0 -0
  42. data/app/assets/images/droom/smalldownload.png +0 -0
  43. data/app/assets/images/droom/smalledit.png +0 -0
  44. data/app/assets/images/droom/smallmanage.png +0 -0
  45. data/app/assets/images/droom/star.png +0 -0
  46. data/app/assets/images/droom/symbols.png +0 -0
  47. data/app/assets/images/droom/tinyarrows.png +0 -0
  48. data/app/assets/images/droom/to_dropbox.png +0 -0
  49. data/app/assets/images/droom/twisty.png +0 -0
  50. data/app/assets/images/droom/youtube_icon.png +0 -0
  51. data/app/assets/javascripts/droom.js.coffee +62 -65
  52. data/app/assets/javascripts/droom/actions.js.coffee +492 -0
  53. data/app/assets/javascripts/droom/ajax.js.coffee +84 -0
  54. data/app/assets/javascripts/droom/{lib/extensions.js.coffee → extensions.js.coffee} +22 -15
  55. data/app/assets/javascripts/droom/lib/ZeroClipboard.js +334 -0
  56. data/app/assets/javascripts/droom/lib/ZeroClipboard.swf +0 -0
  57. data/app/assets/javascripts/droom/lib/ZeroClipboard10.swf +0 -0
  58. data/app/assets/javascripts/droom/map.js.coffee +124 -86
  59. data/app/assets/javascripts/droom/popups.js.coffee +252 -0
  60. data/app/assets/javascripts/droom/stream.js.coffee +92 -0
  61. data/app/assets/javascripts/droom/utilities.js.coffee +120 -0
  62. data/app/assets/javascripts/droom/widgets.js.coffee +1209 -0
  63. data/app/assets/stylesheets/_definitions.css.sass +189 -0
  64. data/app/assets/stylesheets/droom.css.sass +1429 -376
  65. data/app/assets/stylesheets/lib/_kalendae.css.sass +2 -5
  66. data/app/assets/stylesheets/lib/_popups.css.sass +86 -0
  67. data/app/assets/stylesheets/lib/_toolbar.css.sass +17 -11
  68. data/app/controllers/droom/agenda_categories_controller.rb +24 -0
  69. data/app/controllers/droom/calendars_controller.rb +29 -0
  70. data/app/controllers/droom/confirmations_controller.rb +38 -0
  71. data/app/controllers/droom/dashboard_controller.rb +2 -0
  72. data/app/controllers/droom/documents_controller.rb +42 -51
  73. data/app/controllers/droom/dropbox_tokens_controller.rb +61 -0
  74. data/app/controllers/droom/engine_controller.rb +8 -23
  75. data/app/controllers/droom/events_controller.rb +39 -27
  76. data/app/controllers/droom/folders_controller.rb +106 -0
  77. data/app/controllers/droom/group_invitations_controller.rb +15 -7
  78. data/app/controllers/droom/groups_controller.rb +4 -4
  79. data/app/controllers/droom/invitations_controller.rb +37 -9
  80. data/app/controllers/droom/memberships_controller.rb +5 -3
  81. data/app/controllers/droom/organisations_controller.rb +53 -0
  82. data/app/controllers/droom/people_controller.rb +46 -27
  83. data/app/controllers/droom/preferences_controller.rb +34 -0
  84. data/app/controllers/droom/scraps_controller.rb +77 -0
  85. data/app/controllers/droom/search_controller.rb +66 -0
  86. data/app/controllers/droom/suggestions_controller.rb +22 -35
  87. data/app/controllers/droom/users_controller.rb +69 -0
  88. data/app/controllers/droom/venues_controller.rb +1 -2
  89. data/app/controllers/droom/youtube_controller.rb +22 -0
  90. data/app/helpers/droom/droom_helper.rb +93 -5
  91. data/app/models/droom/agenda_category.rb +8 -1
  92. data/app/models/droom/calendar.rb +19 -0
  93. data/app/models/droom/category.rb +4 -6
  94. data/app/models/droom/document.rb +103 -64
  95. data/app/models/droom/document_attachment.rb +13 -47
  96. data/app/models/droom/dropbox_document.rb +41 -0
  97. data/app/models/droom/dropbox_token.rb +29 -0
  98. data/app/models/droom/event.rb +125 -90
  99. data/app/models/droom/folder.rb +134 -0
  100. data/app/models/droom/group.rb +68 -27
  101. data/app/models/droom/group_invitation.rb +12 -3
  102. data/app/models/droom/invitation.rb +50 -8
  103. data/app/models/droom/mailing_list_membership.rb +128 -0
  104. data/app/models/droom/membership.rb +71 -9
  105. data/app/models/droom/organisation.rb +22 -0
  106. data/app/models/droom/page.rb +3 -3
  107. data/app/models/droom/person.rb +180 -166
  108. data/app/models/droom/personal_folder.rb +31 -0
  109. data/app/models/droom/preference.rb +35 -0
  110. data/app/models/droom/recurrence_rule.rb +1 -1
  111. data/app/models/droom/scrap.rb +110 -0
  112. data/app/models/droom/tag.rb +120 -0
  113. data/app/models/droom/tagging.rb +13 -0
  114. data/app/models/droom/user.rb +211 -0
  115. data/app/models/droom/user_action_observer.rb +12 -0
  116. data/app/models/droom/venue.rb +56 -39
  117. data/app/views/cropper/uploads/_crop.html.haml +46 -0
  118. data/app/views/devise/mailer/confirmation_instructions.en.html.haml +24 -0
  119. data/app/views/devise/mailer/reset_password_instructions.en.html.haml +21 -0
  120. data/app/views/devise/passwords/edit.html.haml +31 -0
  121. data/app/views/devise/passwords/new.html.haml +21 -0
  122. data/app/views/devise/sessions/new.html.haml +33 -0
  123. data/app/views/droom/agenda_categories/_form.html.haml +22 -0
  124. data/app/views/droom/agenda_categories/new.html.haml +6 -0
  125. data/app/views/droom/calendars/_action_menu.html.haml +6 -0
  126. data/app/views/droom/calendars/index.html.haml +12 -0
  127. data/app/views/droom/calendars/show.rss.builder +0 -0
  128. data/app/views/droom/confirmations/show.html.haml +40 -0
  129. data/app/views/droom/dashboard/_calendar.html.haml +1 -0
  130. data/app/views/droom/dashboard/_folders.html.haml +5 -0
  131. data/app/views/droom/dashboard/_future_events.html.haml +18 -0
  132. data/app/views/droom/dashboard/_invitations.html.haml +1 -0
  133. data/app/views/droom/dashboard/_past_events.haml +14 -0
  134. data/app/views/droom/dashboard/_quicksearch.html.haml +6 -0
  135. data/app/views/droom/dashboard/_stream.html.haml +9 -0
  136. data/app/views/droom/dashboard/index.html.haml +5 -3
  137. data/app/views/droom/documents/_action_menu.html.haml +7 -0
  138. data/app/views/droom/documents/_documents.html.haml +5 -0
  139. data/app/views/droom/documents/_documents_list.html.haml +6 -6
  140. data/app/views/droom/documents/_documents_table.html.haml +29 -10
  141. data/app/views/droom/documents/_form.html.haml +3 -7
  142. data/app/views/droom/documents/_listing.html.haml +5 -6
  143. data/app/views/droom/documents/_pagination.html.haml +8 -0
  144. data/app/views/droom/documents/_search_result.html.haml +14 -0
  145. data/app/views/droom/documents/_suggested.html.haml +0 -5
  146. data/app/views/droom/documents/_table_document.html.haml +2 -8
  147. data/app/views/droom/documents/edit.html.haml +7 -1
  148. data/app/views/droom/documents/index.html.haml +10 -27
  149. data/app/views/droom/documents/new.html.haml +10 -1
  150. data/app/views/droom/dropbox_tokens/new.html.haml +6 -0
  151. data/app/views/droom/events/_action_menu.html.haml +15 -0
  152. data/app/views/droom/events/_event.html.haml +67 -57
  153. data/app/views/droom/events/_form.html.haml +15 -4
  154. data/app/views/droom/events/_invitations.html.haml +4 -19
  155. data/app/views/droom/events/_search_result.html.haml +19 -0
  156. data/app/views/droom/events/_views.html.haml +2 -2
  157. data/app/views/droom/events/edit.html.haml +7 -1
  158. data/app/views/droom/events/index.html.haml +27 -10
  159. data/app/views/droom/events/index.rss.builder +1 -1
  160. data/app/views/droom/events/new.html.haml +6 -1
  161. data/app/views/droom/events/show.html.haml +5 -1
  162. data/app/views/droom/folders/_action_menu.html.haml +14 -0
  163. data/app/views/droom/folders/_attachments.html.haml +3 -0
  164. data/app/views/droom/folders/_contents.html.haml +6 -0
  165. data/app/views/droom/folders/_folder.html.haml +20 -0
  166. data/app/views/droom/folders/_folders.html.haml +2 -0
  167. data/app/views/droom/folders/_form.html.haml +18 -0
  168. data/app/views/droom/folders/edit.html.haml +6 -0
  169. data/app/views/droom/folders/index.html.haml +32 -0
  170. data/app/views/droom/folders/new.html.haml +6 -0
  171. data/app/views/droom/folders/show.html.haml +1 -0
  172. data/app/views/droom/group_invitations/_form.html.haml +15 -4
  173. data/app/views/droom/group_invitations/new.html.haml +6 -1
  174. data/app/views/droom/groups/_action_menu.haml +11 -0
  175. data/app/views/droom/groups/_form.html.haml +10 -11
  176. data/app/views/droom/groups/_group.html.haml +9 -10
  177. data/app/views/droom/groups/_groups.html.haml +2 -3
  178. data/app/views/droom/groups/_search_result.html.haml +16 -0
  179. data/app/views/droom/groups/_suggested.html.haml +7 -0
  180. data/app/views/droom/groups/edit.html.haml +7 -1
  181. data/app/views/droom/groups/index.html.haml +6 -3
  182. data/app/views/droom/groups/new.html.haml +7 -0
  183. data/app/views/droom/groups/show.html.haml +1 -1
  184. data/app/views/droom/invitations/_created.html.haml +1 -1
  185. data/app/views/droom/invitations/_form.html.haml +9 -5
  186. data/app/views/droom/invitations/_invitation.html.haml +9 -0
  187. data/app/views/droom/invitations/_invitations.html.haml +8 -0
  188. data/app/views/droom/invitations/new.html.haml +6 -1
  189. data/app/views/droom/memberships/_member.html.haml +1 -1
  190. data/app/views/droom/memberships/_membership_toggle.html.haml +10 -0
  191. data/app/views/droom/memberships/new.html.haml +10 -0
  192. data/app/views/droom/organisations/_action_menu.html.haml +7 -0
  193. data/app/views/droom/organisations/_form.html.haml +25 -0
  194. data/app/views/droom/organisations/_organisation.html.haml +23 -0
  195. data/app/views/droom/organisations/_organisations.html.haml +2 -0
  196. data/app/views/droom/organisations/_suggested.html.haml +7 -0
  197. data/app/views/droom/organisations/edit.html.haml +6 -0
  198. data/app/views/droom/organisations/index.html.haml +20 -0
  199. data/app/views/droom/organisations/new.html.haml +6 -0
  200. data/app/views/droom/organisations/show.html.haml +1 -0
  201. data/app/views/droom/pages/_full_page.html.haml +1 -1
  202. data/app/views/droom/pages/index.html.haml +1 -1
  203. data/app/views/droom/panels/_account.html.haml +16 -0
  204. data/app/views/droom/panels/_admin.html.haml +23 -0
  205. data/app/views/droom/panels/_devices.html.haml +19 -0
  206. data/app/views/droom/panels/_dropbox.html.haml +17 -0
  207. data/app/views/droom/panels/_email.html.haml +16 -0
  208. data/app/views/droom/panels/_keywords.html.haml +3 -0
  209. data/app/views/droom/panels/_networks.html.haml +3 -0
  210. data/app/views/droom/panels/_readers.html.haml +18 -0
  211. data/app/views/droom/panels/_rss.html.haml +10 -0
  212. data/app/views/droom/panels/_search.html.haml +16 -0
  213. data/app/views/droom/panels/_vcal.html.haml +3 -0
  214. data/app/views/droom/people/_action_menu.html.haml +22 -0
  215. data/app/views/droom/people/_form.html.haml +69 -39
  216. data/app/views/droom/people/_listing.html.haml +19 -0
  217. data/app/views/droom/people/_memberships.html.haml +24 -0
  218. data/app/views/droom/people/_people.html.haml +5 -29
  219. data/app/views/droom/people/_person.html.haml +30 -32
  220. data/app/views/droom/people/_search_result.html.haml +14 -0
  221. data/app/views/droom/people/_suggested.html.haml +10 -5
  222. data/app/views/droom/people/edit.html.haml +9 -1
  223. data/app/views/droom/people/index.html.haml +6 -9
  224. data/app/views/droom/people/new.html.haml +6 -1
  225. data/app/views/droom/people/show.html.haml +1 -1
  226. data/app/views/droom/preferences/_checkbox.html.haml +7 -0
  227. data/app/views/droom/preferences/_radio_set.html.haml +9 -0
  228. data/app/views/droom/scraps/_action_menu.html.haml +9 -0
  229. data/app/views/droom/scraps/_caption.html.haml +9 -0
  230. data/app/views/droom/scraps/_credit.html.haml +10 -0
  231. data/app/views/droom/scraps/_form.html.haml +77 -0
  232. data/app/views/droom/scraps/_heading.html.haml +16 -0
  233. data/app/views/droom/scraps/_scrap.html.haml +17 -0
  234. data/app/views/droom/scraps/_search_result.html.haml +5 -0
  235. data/app/views/droom/scraps/_stream.html.haml +4 -0
  236. data/app/views/droom/scraps/_suggested.html.haml +5 -0
  237. data/app/views/droom/scraps/_thumb.html.haml +5 -0
  238. data/app/views/droom/scraps/edit.html.haml +2 -0
  239. data/app/views/droom/scraps/full/_document.html.haml +6 -0
  240. data/app/views/droom/scraps/full/_event.html.haml +20 -0
  241. data/app/views/droom/scraps/full/_image.html.haml +4 -0
  242. data/app/views/droom/scraps/full/_link.html.haml +5 -0
  243. data/app/views/droom/scraps/full/_quote.html.haml +8 -0
  244. data/app/views/droom/scraps/full/_text.html.haml +4 -0
  245. data/app/views/droom/scraps/full/_video.html.haml +4 -0
  246. data/app/views/droom/scraps/index.atom.builder +26 -0
  247. data/app/views/droom/scraps/index.html.haml +15 -0
  248. data/app/views/droom/scraps/new.html.haml +2 -0
  249. data/app/views/droom/scraps/show.html.haml +4 -0
  250. data/app/views/droom/scraps/thumbs/_document.html.haml +9 -0
  251. data/app/views/droom/scraps/thumbs/_event.html.haml +17 -0
  252. data/app/views/droom/scraps/thumbs/_image.html.haml +6 -0
  253. data/app/views/droom/scraps/thumbs/_link.html.haml +10 -0
  254. data/app/views/droom/scraps/thumbs/_quote.html.haml +8 -0
  255. data/app/views/droom/scraps/thumbs/_text.html.haml +8 -0
  256. data/app/views/droom/scraps/thumbs/_video.html.haml +6 -0
  257. data/app/views/droom/shared/_controls.html.haml +5 -3
  258. data/app/views/droom/shared/_excerpt.html.haml +2 -0
  259. data/app/views/droom/shared/_navigation.html.haml +4 -4
  260. data/app/views/droom/shared/_panels.html.haml +4 -0
  261. data/app/views/droom/shared/_quicklinks.html.haml +5 -0
  262. data/app/views/droom/shared/_search_form.html.haml +2 -1
  263. data/app/views/droom/shared/_search_results.html.haml +9 -0
  264. data/app/views/droom/shared/_suggestions.html.haml +13 -9
  265. data/app/views/droom/shared/_title_excerpt.haml +2 -0
  266. data/app/views/droom/shared/search.html.haml +18 -0
  267. data/app/views/droom/users/_confirmation.html.haml +2 -0
  268. data/app/views/droom/users/_dropbox_status.html.haml +2 -0
  269. data/app/views/droom/users/_form.html.haml +34 -0
  270. data/app/views/droom/users/_user.html.haml +2 -0
  271. data/app/views/droom/users/_user_or_person.html.haml +63 -0
  272. data/app/views/droom/users/_users_table.html.haml +17 -0
  273. data/app/views/droom/users/edit.html.haml +10 -0
  274. data/app/views/droom/users/index.html.haml +42 -0
  275. data/app/views/droom/users/unwelcome.en.html.haml +17 -0
  276. data/app/views/droom/venues/_search_result.html.haml +17 -0
  277. data/app/views/droom/youtube/show.html.haml +12 -0
  278. data/app/views/kaminari/_paginator.html.haml +16 -0
  279. data/app/views/layouts/droom/application.html.haml +17 -17
  280. data/app/views/layouts/droom/email.html.haml +59 -0
  281. data/config/cucumber.yml +8 -0
  282. data/config/initializers/devise.rb +240 -0
  283. data/config/locales/devise.en.yml +58 -0
  284. data/config/locales/en.yml +203 -32
  285. data/config/routes.rb +55 -16
  286. data/config/sunspot.yml +17 -0
  287. data/db/migrate/20121120115447_tags.rb +18 -0
  288. data/db/migrate/20130116155331_dropbox_tokens.rb +9 -0
  289. data/db/migrate/20130118103540_folders.rb +47 -0
  290. data/db/migrate/20130124113715_preferences.rb +10 -0
  291. data/db/migrate/20130125132427_users_in_droom.rb +58 -0
  292. data/db/migrate/20130129142307_mobile_phones.rb +7 -0
  293. data/db/migrate/20130130120124_folder_ancestry_to_parents.rb +7 -0
  294. data/db/migrate/20130131161430_mailing_lists.rb +37 -0
  295. data/db/migrate/20130207091903_preference_uuids.rb +5 -0
  296. data/db/migrate/20130207123614_stream.rb +13 -0
  297. data/db/migrate/20130208035113_access_token_secret.rb +5 -0
  298. data/db/migrate/20130214145014_person_image.rb +9 -0
  299. data/db/migrate/20130217152644_devise_confirmable.rb +13 -0
  300. data/db/migrate/20130225095328_create_droom_calendars.rb +20 -0
  301. data/db/migrate/20130226092944_give_scraps_document.rb +5 -0
  302. data/db/migrate/20130228083509_privateness.rb +9 -0
  303. data/db/migrate/20130228134143_store_metadata.rb +5 -0
  304. data/db/migrate/20130305150648_folders_nicely.rb +6 -0
  305. data/db/migrate/20130305151936_niceties.rb +7 -0
  306. data/db/migrate/20130308103807_create_droom_dropbox_documents.rb +11 -0
  307. data/db/migrate/20130308154552_dropbox_documents_changed.rb +5 -0
  308. data/db/migrate/20130326135738_user_titles.rb +5 -0
  309. data/lib/droom.rb +189 -22
  310. data/lib/droom/engine.rb +6 -1
  311. data/lib/droom/folders.rb +106 -0
  312. data/lib/droom/lazy_hash.rb +73 -0
  313. data/lib/droom/{helpers.rb → model_helpers.rb} +1 -1
  314. data/lib/droom/monkeys.rb +21 -2
  315. data/lib/droom/routing.rb +13 -0
  316. data/lib/droom/searchability.rb +25 -0
  317. data/lib/droom/taggability.rb +60 -0
  318. data/lib/droom/title_case.rb +101 -0
  319. data/lib/droom/user_config.rb +67 -0
  320. data/lib/droom/validators.rb +6 -0
  321. data/lib/droom/version.rb +1 -1
  322. data/lib/generators/droom/install/templates/droom_initializer.rb +0 -1
  323. data/lib/tasks/cucumber.rake +65 -0
  324. data/spec/datasets/calendar_events_dataset.rb +44 -0
  325. data/spec/datasets/calendar_pages_dataset.rb +8 -0
  326. data/spec/datasets/calendar_sites_dataset.rb +6 -0
  327. data/spec/datasets/calendars_dataset.rb +34 -0
  328. data/spec/datasets/documents_dataset.rb +28 -0
  329. data/spec/datasets/recurrence_dataset.rb +7 -0
  330. data/spec/dummy/README.rdoc +261 -0
  331. data/spec/dummy/Rakefile +7 -0
  332. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  333. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  334. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  335. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  336. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  337. data/spec/dummy/config.ru +4 -0
  338. data/spec/dummy/config/application.rb +65 -0
  339. data/spec/dummy/config/boot.rb +10 -0
  340. data/spec/dummy/config/database.yml +21 -0
  341. data/spec/dummy/config/environment.rb +5 -0
  342. data/spec/dummy/config/environments/development.rb +38 -0
  343. data/spec/dummy/config/environments/production.rb +67 -0
  344. data/spec/dummy/config/environments/test.rb +38 -0
  345. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  346. data/spec/dummy/config/initializers/inflections.rb +15 -0
  347. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  348. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  349. data/spec/dummy/config/initializers/session_store.rb +8 -0
  350. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  351. data/spec/dummy/config/locales/en.yml +7 -0
  352. data/spec/dummy/config/routes.rb +3 -0
  353. data/spec/dummy/config/sunspot.yml +17 -0
  354. data/spec/dummy/db/migrate/20120911070124_create_droom_data.droom.rb +135 -0
  355. data/spec/dummy/db/migrate/20120921094604_agenda_sections.droom.rb +14 -0
  356. data/spec/dummy/db/migrate/20120921094605_add_postal_address_to_people.droom.rb +11 -0
  357. data/spec/dummy/db/migrate/20121102064845_give_groups_descriptions.droom.rb +6 -0
  358. data/spec/dummy/db/migrate/20121102064846_more_names.droom.rb +6 -0
  359. data/spec/dummy/db/migrate/20121102064847_event_agenda_sections.droom.rb +14 -0
  360. data/spec/dummy/db/migrate/20121102064848_create_group_invitations.droom.rb +11 -0
  361. data/spec/dummy/db/migrate/20121102064849_give_people_positions.droom.rb +6 -0
  362. data/spec/dummy/db/migrate/20121102064850_help_pages.droom.rb +14 -0
  363. data/spec/dummy/db/migrate/20121102064851_category_slugs.droom.rb +6 -0
  364. data/spec/dummy/db/migrate/20121102064852_document_links.droom.rb +15 -0
  365. data/spec/dummy/db/migrate/20121102064853_people_visibility.droom.rb +8 -0
  366. data/spec/dummy/db/migrate/20121102094820_shy_people.droom.rb +6 -0
  367. data/spec/dummy/db/migrate/20121102095927_visibility_defaults.droom.rb +10 -0
  368. data/spec/dummy/db/migrate/20130121122352_tags.droom.rb +19 -0
  369. data/spec/dummy/db/migrate/20130121122353_dropbox.droom.rb +10 -0
  370. data/spec/dummy/db/migrate/20130121122354_folders.droom.rb +48 -0
  371. data/spec/dummy/db/migrate/20130128142902_memberships_expire.droom.rb +6 -0
  372. data/spec/dummy/db/migrate/20130128142903_give_documents_extracted_text.droom.rb +6 -0
  373. data/spec/dummy/db/migrate/20130128142904_preferences.droom.rb +11 -0
  374. data/spec/dummy/db/migrate/20130128142905_users_in_droom.droom.rb +59 -0
  375. data/spec/dummy/db/migrate/20130130120631_folder_ancestry_to_parents.droom.rb +8 -0
  376. data/spec/dummy/db/migrate/20130201103737_mobile_phones.droom.rb +8 -0
  377. data/spec/dummy/db/migrate/20130201103738_mailing_lists.droom.rb +38 -0
  378. data/spec/dummy/db/schema.rb +327 -0
  379. data/spec/dummy/log/sunspot-solr-test.log.1 +222 -0
  380. data/spec/dummy/public/404.html +26 -0
  381. data/spec/dummy/public/422.html +26 -0
  382. data/spec/dummy/public/500.html +25 -0
  383. data/spec/dummy/public/favicon.ico +0 -0
  384. data/spec/dummy/public/system/droom/documents/files/000/000/001/original/frog.png +0 -0
  385. data/spec/dummy/public/system/droom/documents/files/000/000/001/original/rat.png +0 -0
  386. data/spec/dummy/script/rails +6 -0
  387. data/spec/dummy/solr/conf/admin-extra.html +31 -0
  388. data/spec/dummy/solr/conf/elevate.xml +36 -0
  389. data/spec/dummy/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  390. data/spec/dummy/solr/conf/protwords.txt +21 -0
  391. data/spec/dummy/solr/conf/schema.xml +238 -0
  392. data/spec/dummy/solr/conf/scripts.conf +24 -0
  393. data/spec/dummy/solr/conf/solrconfig.xml +934 -0
  394. data/spec/dummy/solr/conf/spellings.txt +2 -0
  395. data/spec/dummy/solr/conf/stopwords.txt +58 -0
  396. data/spec/dummy/solr/conf/synonyms.txt +31 -0
  397. data/spec/dummy/solr/data/development/index/segments.gen +0 -0
  398. data/spec/dummy/solr/data/development/index/segments_1 +0 -0
  399. data/spec/dummy/solr/data/development/spellchecker/segments.gen +0 -0
  400. data/spec/dummy/solr/data/development/spellchecker/segments_1 +0 -0
  401. data/spec/dummy/solr/data/test/index/segments.gen +0 -0
  402. data/spec/dummy/solr/data/test/index/segments_3nu +0 -0
  403. data/spec/dummy/solr/data/test/spellchecker/segments.gen +0 -0
  404. data/spec/dummy/solr/data/test/spellchecker/segments_1 +0 -0
  405. data/spec/dummy/webdav/1/group/rat.png +0 -0
  406. data/spec/dummy/webdav/1/unattached/rat.png +0 -0
  407. data/spec/dummy/webdav/group/rat.png +0 -0
  408. data/spec/dummy/webdav/unattached/rat.png +0 -0
  409. data/spec/dummy/webdav/unattached/rat_v1.png +0 -0
  410. data/spec/factories/agenda_categories.rb +5 -0
  411. data/spec/factories/categories.rb +5 -0
  412. data/spec/factories/documents.rb +16 -0
  413. data/spec/factories/events.rb +41 -0
  414. data/spec/factories/folders.rb +5 -0
  415. data/spec/factories/groups.rb +6 -0
  416. data/spec/factories/memberships.rb +5 -0
  417. data/spec/factories/people.rb +16 -0
  418. data/spec/factories/recurrence_rules.rb +25 -0
  419. data/spec/factories/user.rb +6 -0
  420. data/spec/fixtures/dummy.ics +59 -0
  421. data/spec/fixtures/images/frog.png +0 -0
  422. data/spec/fixtures/images/rat.png +0 -0
  423. data/spec/fixtures/ny.ics +36 -0
  424. data/spec/lib/droom/folders_spec.rb +46 -0
  425. data/spec/lib/droom/lazy_hash_spec.rb +33 -0
  426. data/spec/models/droom/agenda_category_spec.rb +15 -0
  427. data/spec/models/droom/document_spec.rb +76 -0
  428. data/spec/models/droom/event_spec.rb +154 -0
  429. data/spec/models/droom/folder_spec.rb +5 -0
  430. data/spec/models/droom/ical_spec.rb +62 -0
  431. data/spec/models/droom/mailing_list_membership_spec.rb +81 -0
  432. data/spec/models/droom/membership_spec.rb +22 -0
  433. data/spec/models/droom/person_spec.rb +72 -0
  434. data/spec/models/droom/recurrence_rule_spec.rb +81 -0
  435. data/spec/models/droom/user_spec.rb +27 -0
  436. data/spec/models/droom/visibility_spec.rb +6 -0
  437. data/spec/spec_helper.rb +119 -0
  438. data/spec/support/matchers/content_type_matcher.rb +17 -0
  439. metadata +591 -36
  440. data/app/assets/javascripts/droom/calendar.js.coffee +0 -121
  441. data/app/assets/javascripts/droom/drag_sort.js.coffee +0 -22
  442. data/app/assets/javascripts/droom/forms.js.coffee +0 -746
  443. data/app/assets/javascripts/droom/sort.js.coffee +0 -126
  444. data/app/assets/javascripts/droom/suggester.js.coffee +0 -230
  445. data/app/controllers/droom/document_attachments_controller.rb +0 -19
  446. data/app/models/droom/document_link.rb +0 -31
  447. data/app/models/droom/personal_document.rb +0 -98
  448. data/app/views/droom/dashboard/_marginalia.html.haml +0 -3
  449. data/app/views/droom/dashboard/_my_future_events.html.haml +0 -9
  450. data/app/views/droom/dashboard/_my_group_documents.html.haml +0 -6
  451. data/app/views/droom/dashboard/_my_past_events.haml +0 -6
  452. data/app/views/droom/documents/_event_document_form.html.haml +0 -15
  453. data/app/views/droom/errors/bang.html.haml +0 -12
  454. data/app/views/droom/errors/not_allowed.html.haml +0 -12
  455. data/app/views/droom/errors/not_found.html.haml +0 -12
  456. data/app/views/droom/events/_attachment.html.haml +0 -1
  457. data/app/views/droom/events/_attachment_list.html.haml +0 -4
  458. data/app/views/droom/invitations/_attending_people.html.haml +0 -8
  459. data/config/initializers/dav.rb +0 -2
data/README.md CHANGED
@@ -4,7 +4,7 @@ This is a minimal system for secure document and event distribution. It provides
4
4
 
5
5
  ## Status
6
6
 
7
- Brand new. In progress. Avoid!
7
+ Brand new. In progress. Little bit volatile, perhaps.
8
8
 
9
9
  ## Installation
10
10
 
@@ -16,7 +16,7 @@ To migrate:
16
16
 
17
17
  rake droom:install:migrations
18
18
  rake db:migrate
19
-
19
+
20
20
 
21
21
  ## Copyright
22
22
 
@@ -1,88 +1,85 @@
1
1
  #= require droom/lib/modernizr
2
- #= require droom/lib/extensions
3
2
  #= require jquery
4
3
  #= require jquery_ujs
4
+ #= require droom/lib/ZeroClipboard
5
5
  #= require droom/lib/jquery.animate-colors
6
6
  #= require droom/lib/jquery.sortable
7
7
  #= require droom/lib/jquery.cookie
8
8
  #= require droom/lib/kalendae
9
9
  #= require droom/lib/wysihtml5
10
10
  #= require droom/lib/parser_rules/advanced
11
- #= require droom/forms
12
- #= require droom/suggester
13
- #= require droom/calendar
14
- #= require droom/sort
11
+ #= require cropper
12
+ #= require droom/extensions
13
+ #= require droom/utilities
14
+ #= require droom/ajax
15
+ #= require droom/popups
16
+ #= require droom/actions
17
+ #= require droom/widgets
18
+ #= require droom/stream
15
19
  #= require droom/map
16
- #= require droom/drag_sort
17
20
  #= require_self
18
21
 
19
22
  jQuery ($) ->
20
- $.fn.flash = ->
21
- @each ->
22
- container = $(this)
23
- container.fadeIn "fast"
24
- $("<a href=\"#\" class=\"closer\">close</a>").prependTo(container)
25
- container.bind "click", (e) ->
26
- e.preventDefault()
27
- container.fadeOut "fast"
28
-
29
- $.fn.signal = (color, duration) ->
30
- color ?= "#f7f283"
31
- duration ?= 1000
32
- @each ->
33
- $(@).css('backgroundColor', color).animate({'backgroundColor': '#ffffff'}, duration)
34
-
35
- $.fn.signal_confirmation = ->
36
- @signal('#c7ebb4')
37
-
38
- $.fn.signal_error = ->
39
- @signal('#e55a51')
40
-
41
- $.fn.signal_cancellation = ->
42
- @signal('#a2a3a3')
23
+ $.activate_with () ->
24
+ # console.log "activate", @
43
25
 
44
- $.fn.back_button = ->
45
- @click (e) ->
46
- e.preventDefault() if e
47
- history.back()
48
- true
49
-
50
- $.fn.find_including_self = (selector) ->
51
- selection = @.find(selector)
52
- selection.push @ if @is(selector)
53
- selection
54
-
55
- $.fn.activate = () ->
56
- @find_including_self('a.toggle_active').replace_with_remote_toggle()
57
26
  @find_including_self('#flashes p:parent').flash()
58
- @find_including_self('.twister').twister()
27
+ @find_including_self('[data-refreshable]').refresher()
28
+ @find_including_self('.hidden').find('input, select, textarea').attr('disabled', true)
29
+ @find_including_self('.temporary').disappearAfter(1000)
30
+
31
+ # link actions
32
+
33
+ @find_including_self('[data-action="popup"]').popup()
34
+ @find_including_self('[data-action="close"]').closes()
35
+ @find_including_self('[data-action="upload"]').uploader()
36
+ @find_including_self('[data-action="recrop"]').recropper()
37
+ @find_including_self('[data-action="affect"]').affects()
38
+ @find_including_self('[data-action="reveal"]').reveals()
39
+ @find_including_self('[data-action="remove"]').removes()
40
+ @find_including_self('[data-action="copy"]').copier()
41
+ @find_including_self('[data-action="column_toggle"]').column_expander()
42
+ @find_including_self('[data-action="toggle"]').toggle()
43
+ @find_including_self('[data-action="twister"]').twister()
44
+ @find_including_self('[data-action="alternate"]').alternator()
45
+ @find_including_self('[data-action="replace"]').replace_with_remote_content()
46
+ @find_including_self('[data-action="autofetch"]').replace_with_remote_content ".holder", {force: true}
47
+ @find_including_self('[data-action="slide"]').sliding_link()
48
+ @find_including_self('[data-action="fit"]').self_sizes()
49
+ @find_including_self('form[data-action="filter"]').filter_form()
50
+ @find_including_self('[data-menu]').action_menu()
51
+
52
+ # it's not very easy to add data attributes to kaminari pagination links
53
+
54
+ @find_including_self('.pagination a').page_turner()
55
+
56
+ # and some shortcuts for compatibility
57
+
58
+ @find_including_self('a.inline, a.fetch').replace_with_remote_content()
59
+
60
+ # form widgets and input modification. These might move to [data-widget] markup.
61
+
59
62
  @find_including_self('.wysihtml').html_editable()
60
63
  @find_including_self('.venuepicker').venue_picker()
61
64
  @find_including_self('.datepicker').date_picker()
62
65
  @find_including_self('.timepicker').time_picker()
63
66
  @find_including_self('.filepicker').file_picker()
64
- @find_including_self('a.delete').removes('.holder')
65
- @find_including_self('[data-action="popup"]').popup_remote_content()
66
- @find_including_self('[data-action="toggle"]').toggle()
67
- @find_including_self('[data-action="append_form"]').append_remote_form()
68
- @find_including_self('[data-action="overlay_form"]').overlay_remote_form()
69
- @find_including_self('[data-action="replace_with_form"]').replace_with_remote_form()
70
- @find_including_self('[data-refreshable]').refresher()
71
- @find_including_self('table.sortable').table_sort
72
- sort: "created"
73
- order: "DESC"
74
- @find_including_self('#map').init_map()
67
+ @find_including_self('.person_selector').person_selector()
68
+ @find_including_self('.person_picker').person_picker()
69
+ @find_including_self('.group_picker').group_picker()
70
+ @find_including_self('.drag_sort').drag_sort()
75
71
  @find_including_self('input.password').password_field()
76
72
  @find_including_self('input[type="submit"]').submitter()
77
- @find_including_self('input.person_picker').person_picker()
78
- @find_including_self('input.group_picker').group_picker()
79
- @find_including_self('.drag_sort').drag_sort()
80
- @find_including_self('.back').back_button()
73
+ @find_including_self('form.preferences').preferences_form()
74
+ @find_including_self('form.scrap').scrap_form()
75
+
76
+ # page widgets
77
+
78
+ @find_including_self('#map').init_map()
79
+ @find_including_self('#minicalendar').calendar()
80
+ @find_including_self('form.search_form').search()
81
+ @find_including_self('form.fancy').captive()
82
+ @find_including_self('li.folder').folder()
83
+ @find_including_self('form#suggestions').suggestion_form()
84
+ @find_including_self('.panel').panel()
81
85
  @
82
-
83
- $ ->
84
- $('body').activate()
85
- $('#minicalendar').calendar()
86
- $('form#searchform').captive
87
- replacing: '.search_results'
88
- fast: true
@@ -0,0 +1,492 @@
1
+ # This is a collection of useful interface behaviours. Most of them are form- or input-based. They shouldn't ever
2
+ # be object-specific, but can be used throughout the droom interface to make forms and other controls more lively.
3
+ #
4
+ # The basic approach here is PJAX: our remote calls always return chunks of html. There are no client-side templates
5
+ # or model classes. Instead we have defined a set of actions, by which page elements can interact with the server in
6
+ # structured ways. A tag will declare that it triggers an action, and may also declare that the action will replace or
7
+ # affect other elements.
8
+ #
9
+ # Many elements are refreshable, and an action that affects them will trigger their refreshment. Editing an event is
10
+ # a simple remote form operation with several consequences for the page:
11
+ #
12
+ # link_to t(:edit_event), edit_event_url(event), :class => 'edit minimal', :data => {
13
+ # :action => "popup",
14
+ # :replaced => "#event_#{event.id}",
15
+ # :affected => ".minimonth"
16
+ # }
17
+ #
18
+ # When the `popup` action is complete - that is, the server returns a response with no form in it - the final response
19
+ # will replace the original event container and the small calendar display will be refreshed to show the possibly revised
20
+ # date of the event.
21
+ #
22
+ # It is our hope that this simple non-architecture will make it easy to support a future pub-sub update.
23
+
24
+ jQuery ($) ->
25
+
26
+ ## Affecting the page
27
+ #
28
+ # refreshable, affected rules, etc.
29
+
30
+ $.fn.refresher = () ->
31
+ @each ->
32
+ new Refresher @
33
+
34
+ class Refresher
35
+ constructor: (element) ->
36
+ @_container = $(element)
37
+ @_url = @_container.attr 'data-url'
38
+ @_container.bind "refresh", @refresh
39
+
40
+ refresh: (e) =>
41
+ e.stopPropagation()
42
+ e.preventDefault()
43
+ $.ajax @_url,
44
+ dataType: "html"
45
+ success: @replace
46
+
47
+ replace: (data, textStatus, jqXHR) =>
48
+ replacement = $(data)
49
+ @_container.fadeOut 'fast', () =>
50
+ replacement.hide().insertAfter(@_container)
51
+ @_container.remove()
52
+ @_container = replacement
53
+ @_container.activate().fadeIn('fast')
54
+
55
+
56
+ # ## Actions
57
+ #
58
+ # The 'remove' action takes out the parent element of this node designated by the usual 'affected'
59
+ # attribute. The delete link next to an event, for example:
60
+ #
61
+ # link_to t(:remove), event_url(event), :method => 'delete', :data => {
62
+ # :confirm => t(:confirm_delete_event, :name => event.name),
63
+ # :removes => ".holder",
64
+ # :affected => ".minimonth"}
65
+ #
66
+ # ...will (on success) remove the first containing '.holder' element and also refresh the mini calendar display.
67
+ #
68
+ $.fn.removes = () ->
69
+ @each ->
70
+ removed = $(@).attr('data-removed') || ".holder"
71
+ affected = $(@).attr('data-affected')
72
+
73
+ $(@).remote
74
+ on_success: (response) =>
75
+ $(@).parents(removed).first().fadeOut 'fast', () ->
76
+ $(@).remove()
77
+ $(affected).trigger "refresh"
78
+
79
+
80
+ $.fn.affects = () ->
81
+ @each ->
82
+ affected = $(@).attr('data-affected')
83
+ $(@).remote
84
+ on_success: (response) =>
85
+ $(affected).trigger "refresh"
86
+
87
+
88
+ # Close links work just by triggering a 'hide' event and hoping that something further up the tree will bind
89
+ # it to the right thing.
90
+
91
+ $.fn.closes = () ->
92
+ @click (e) ->
93
+ e.preventDefault()
94
+ $(@).trigger('close')
95
+
96
+
97
+
98
+ # *replace_with_remote_content* is a useful shortcut for links and forms that should simply be replaced with the
99
+ # result of their action.
100
+ #
101
+ $.fn.replace_with_remote_content = (selector, opts) ->
102
+ selector ?= '.holder'
103
+ options = $.extend { force: false }, opts
104
+ @each ->
105
+ container = $(@).attr('data-replaced') || selector
106
+ affected = $(@).attr('data-affected')
107
+ $(@).remote
108
+ on_success: (r) =>
109
+ replaced = $(@).self_or_ancestor(container).last()
110
+ replacement = $(r).insertAfter(replaced)
111
+ replaced?.remove()
112
+ replacement.activate()
113
+ $(affected).trigger('refresh')
114
+ $(@).click() if options['force']
115
+
116
+
117
+
118
+
119
+ # The submitter is a self-disabling submit button that can only be clicked once.
120
+ #
121
+ $.fn.submitter = ->
122
+ @each ->
123
+ button = $(@)
124
+ button.parents('form').bind "submit", (e) ->
125
+ button.addClass('waiting').text('Please wait').bind "click", (e) =>
126
+ e.preventDefault() if e
127
+
128
+
129
+ # The toggle action shows or hides the affected elements with cookie-based persistence across page
130
+ # views. A link like this:
131
+ #
132
+ # %a{:data => {:action => 'toggle', :affected => '.admin'}}
133
+ #
134
+ # will toggle on and off the display of anything with the 'admin' class.
135
+ #
136
+ $.fn.toggle = () ->
137
+ @each ->
138
+ new Toggle(@, $(@).attr('data-affected'))
139
+
140
+ #todo: make this a more versatile base class
141
+ class Toggle
142
+ constructor: (element, @_selector, @_name) ->
143
+ @_container = $(element)
144
+ @_name ?= "droom_#{@_selector}_state"
145
+ @_showing_text = @_container.text().replace('show', 'hide').replace('Show', 'Hide').replace('more', 'less').replace('More', 'Less')
146
+ @_hiding_text = @_showing_text.replace('hide', 'show').replace('Hide', 'Show').replace('less', 'more').replace('Less', 'More')
147
+ @_container.click @toggle
148
+ if cookie = $.cookie(@_name)
149
+ @_showing = cookie is "showing"
150
+ @apply()
151
+ else
152
+ @_showing = $(@_selector).is(":visible")
153
+ @store()
154
+
155
+ apply: (e) =>
156
+ e.preventDefault() if e
157
+ if @_showing then @show() else @hide()
158
+
159
+ toggle: (e) =>
160
+ e.preventDefault() if e
161
+ if @_showing then @slideUp() else @slideDown()
162
+
163
+ slideDown: =>
164
+ @_container.addClass('showing')
165
+ $(@_selector).slideDown () =>
166
+ @show()
167
+
168
+ show: =>
169
+ $(@_selector).show()
170
+ @_container.addClass('showing')
171
+ @_container.text(@_showing_text)
172
+ @_showing = true
173
+ @store()
174
+
175
+ slideUp: =>
176
+ $(@_selector).slideUp () =>
177
+ @hide()
178
+
179
+ hide: =>
180
+ $(@_selector).hide()
181
+ @_container.removeClass('showing')
182
+ @_container.text(@_hiding_text)
183
+ @_showing = false
184
+ @store()
185
+
186
+ store: () =>
187
+ value = if @_showing then "showing" else "hidden"
188
+ $.cookie @_name, value,
189
+ path: '/'
190
+
191
+
192
+ # The collapser is a self-expanding unit. Basically a toggle. #todo: amalgamate!
193
+
194
+ $.fn.collapser = (options) ->
195
+ @each ->
196
+ new Collapser(@, options)
197
+ @
198
+
199
+ class Collapser
200
+ constructor: (element, opts) ->
201
+ @container = $(element)
202
+ @options = $.extend {
203
+ toggle: ".heading a.name"
204
+ body: ".detail"
205
+ preview: ".preview"
206
+ }, opts
207
+ @id = @container.attr('id')
208
+ @switch = @container.find(@options.toggle)
209
+ @body = @container.find(@options.body)
210
+ @preview = @container.find(@options.preview)
211
+ @switch.click @toggle
212
+ @set()
213
+
214
+ set: () =>
215
+ if @container.hasClass("open") then @show() else @hide()
216
+
217
+ toggle: (e) =>
218
+ e.preventDefault() if e
219
+ if @container.hasClass("open") then @hide() else @show()
220
+
221
+ hide: () =>
222
+ @container.removeClass('open')
223
+ @preview.show().css('position', 'relative')
224
+ @body.stop().slideUp
225
+ duration: 'slow'
226
+ easing: 'glide'
227
+ complete: =>
228
+ @body.hide()
229
+
230
+ show: () =>
231
+ @container.addClass('open')
232
+ @preview.css('position', 'absolute')
233
+ @body.stop().slideDown
234
+ duration: 'normal'
235
+ easing: 'boing'
236
+ complete: =>
237
+ @preview.hide().css('position', 'relative')
238
+
239
+
240
+ # this one just shows or hides based on whether a checkbox is checked
241
+
242
+ $.fn.reveals = () ->
243
+ @each ->
244
+ new Revealer(@)
245
+
246
+ class Revealer
247
+ constructor: (element) ->
248
+ @_input = $(element)
249
+ @_affected = @_input.attr('data-affected')
250
+ @_converse = @_input.attr('data-converse')
251
+ @_input.bind "click", @set
252
+ @set()
253
+
254
+ set: () =>
255
+ if @_input.is(":checked") then @show() else @hide()
256
+
257
+ show: (e) =>
258
+ $(@_affected).stop().slideDown()
259
+ $(@_affected).find('input').attr('disabled', false)
260
+ $(@_converse).stop().slideUp()
261
+ $(@_converse).find('input').attr('disabled', true)
262
+
263
+ hide: (e) =>
264
+ $(@_affected).stop().slideUp()
265
+ $(@_affected).find('input').attr('disabled', true)
266
+ $(@_converse).stop().slideDown()
267
+ $(@_converse).find('input').attr('disabled', false)
268
+
269
+
270
+ # Yet another toggle, preserved for cdr reviewers but I hope not for long.
271
+
272
+ $.fn.twister = ->
273
+ @each ->
274
+ new Twister(@)
275
+
276
+ class Twister
277
+ @currently_open: []
278
+ constructor: (element) ->
279
+ @_twister = $(element)
280
+ @_twisted = @_twister.find('.twisted')
281
+ @_toggles = @_twister.find('a.twisty')
282
+ @_toggles.click @toggle
283
+ @_open = @_twister.hasClass("showing")
284
+ @set()
285
+
286
+ set: () =>
287
+ if @_open then @open() else @close()
288
+
289
+ toggle: (e) =>
290
+ e.preventDefault() if e
291
+ if @_open then @close() else @open()
292
+
293
+ open: () =>
294
+ @_twister.addClass("showing")
295
+ @_twisted.show()
296
+ @_open = true
297
+ Twister.currently_open.push(@_id)
298
+
299
+ close: () =>
300
+ @_twister.removeClass("showing")
301
+ @_twisted.hide()
302
+ @_open = false
303
+ Twister.currently_open.remove(@_id) # remove is defined in lib/extensions
304
+
305
+
306
+
307
+ # The *alternator* action is a more extreme toggle. It allows an element to declare its alternate:
308
+ # when a link within the element is clicked, it will be removed from the DOM and its alternate
309
+ # inserted. Usually the relation is reciprocal, so that another link in the alternate will bring
310
+ # the original element back.
311
+ #
312
+ # The main use for this is to have two alternative blocks of form inputs: one to add a new associate
313
+ # and one to choose from the existing list.
314
+ #
315
+ class Alternator
316
+ constructor: (element) ->
317
+ @_container = $(element)
318
+ @_selector = @_container.attr("data-selector")
319
+ @_alternate = @_container.siblings(@_selector)
320
+ @revert()
321
+
322
+ flip: (e) =>
323
+ e.preventDefault() if e
324
+ @_container.after(@_alternate)
325
+ @_container.remove()
326
+ @_alternate.find('a').click @revert
327
+
328
+ revert: (e) =>
329
+ e.preventDefault() if e
330
+ @_alternate.before(@_container)
331
+ @_alternate.remove()
332
+ @_container.find('a').click @flip
333
+
334
+ $.fn.alternator = ->
335
+ @each ->
336
+ new Alternator(@)
337
+
338
+
339
+
340
+
341
+
342
+
343
+ # The *copier* action uses ZeroClipboard to put on the clipboard whatever is in our data-value attribute.
344
+ #
345
+ $.fn.copier = ->
346
+ ZeroClipboard.setMoviePath( '/assets/droom/lib/ZeroClipboard.swf' );
347
+ @each ->
348
+ new Copier @
349
+
350
+ class Copier
351
+ constructor: (element) ->
352
+ @_link = $(element)
353
+ @_link.click @failed
354
+ @_link.wrap $('<div class="copyholder" />')
355
+ @_container = @_link.parents('.copyholder')
356
+ @_clip = new ZeroClipboard.Client()
357
+ @_clip.setHandCursor true
358
+ @_clip.setText(@_link.attr('data-value').replace(/^\s+/gm, ''))
359
+
360
+ [w, h] = [@_link.width() || 60, @_link.height() || 15]
361
+ @_clip_element = @_clip.getHTML(w, h+5)
362
+ $(@_clip_element).appendTo @_container
363
+
364
+ @_clip.addEventListener 'complete', @complete
365
+ @_clip.addEventListener 'onMouseOver', @hover
366
+ @_clip.addEventListener 'onMouseOut', @unHover
367
+
368
+ hover: (e) =>
369
+ @_link.addClass('hover')
370
+
371
+ unHover: (e) =>
372
+ @_link.removeClass('hover')
373
+
374
+ complete: (client, text) =>
375
+ @_link.signal_confirmation()
376
+
377
+ failed: (e) =>
378
+ e.preventDefault()
379
+
380
+
381
+ # The main search page hasn't had much love yet.
382
+ #
383
+ # If we keep the inline functionality it should probably use the standard captive form.
384
+
385
+ $.fn.search = ->
386
+ @each ->
387
+ new Search @
388
+
389
+ class Search
390
+ constructor: (element) ->
391
+ @form = $(element)
392
+ @search_box = @form.find(".search_box")
393
+ @container = $(".search_results")
394
+ @filters = @form.find "input[type='checkbox']"
395
+ @search_box.on "keyup", @submit
396
+ @filters.on "change", @submit
397
+
398
+ submit: =>
399
+ $.ajax
400
+ url: "#{@form.attr('action')}?#{@form.serialize()}"
401
+ type: "GET"
402
+ dataType: "script"
403
+ complete: (data) =>
404
+ @container.replaceWith data.responseText
405
+ @container = $(".search_results")
406
+
407
+ #todo: Dragsort also needs to use Remote.
408
+
409
+ $.fn.drag_sort = (options) ->
410
+ @each ->
411
+ first = 0
412
+ offset = 1 + first
413
+ sorter = $(@).sortable
414
+ handle: ".handle"
415
+ $.each $(@).children(), (i, child) =>
416
+ $(child).bind "dragend", (e) =>
417
+ child = $(child)
418
+ index = child.index() + offset
419
+ id = parseInt(child.attr('id').split("person_")[1], 10)
420
+ $.ajax
421
+ url: "/people/#{id}"
422
+ type: "PUT"
423
+ dataType: "JSON"
424
+ data:
425
+ person:
426
+ position: index
427
+
428
+
429
+ #todo: this has been replaced with the filterform.
430
+
431
+ $.fn.search_filter = () ->
432
+ @each ->
433
+ new Filter @
434
+ @
435
+
436
+ class Filter
437
+ constructor: (element) ->
438
+ @_container = $(element)
439
+ @_defilter = $('<a href="#" class="defilter" />').insertAfter(@_container)
440
+ @_affected = @_container.attr('data-affected')
441
+ @setDefilter()
442
+ @_container.bind "keyup", @setQuery
443
+ @_defilter.bind "click", @clearQuery
444
+ # @announce()
445
+
446
+ setDefilter: () =>
447
+ if @_container.val()
448
+ @_defilter.show()
449
+ else
450
+ @_defilter.hide()
451
+
452
+ setQuery: (e) =>
453
+ kc = e.which
454
+ # delete, backspace, alphanumerics, number pad, punctuation
455
+ if (kc is 8) or (kc is 46) or (47 < kc < 91) or (96 < kc < 112) or (kc > 145)
456
+ @setDefilter()
457
+ @filter()
458
+
459
+ clearQuery: (e) =>
460
+ e.preventDefault() if e
461
+ @_container.val("")
462
+ @setDefilter()
463
+ @filter()
464
+
465
+ filter: () =>
466
+ $(@_affected).trigger "filter", @_container.val()
467
+
468
+
469
+
470
+
471
+
472
+ # A text input that sizes to fit will adjust its font size to suit the length of its content.
473
+ # At the moment this is done just by fitting a curve, but it ought really to be based on a
474
+ # calculation of area occupied.
475
+
476
+ $.size_to_fit = (e) ->
477
+ container = $(@)
478
+ l = container.val().length
479
+ size = if l then (((560.0/(2 * l+150.0)) + 0.25)).toFixed(2) else 1
480
+ container.stop().animate
481
+ 'font-size': "#{size}em"
482
+ width: 532
483
+ height: 290
484
+ ,
485
+ queue: false
486
+ duration: 100
487
+
488
+ $.fn.self_sizes = () ->
489
+ @each ->
490
+ $(@).bind "keyup", $.size_to_fit
491
+ $(@).bind "change", $.size_to_fit
492
+ $.size_to_fit.apply(@)