spontaneous 0.2.0.alpha2 → 0.2.0.alpha3

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 (404) hide show
  1. data/Gemfile +3 -40
  2. data/Rakefile +29 -41
  3. data/Readme.markdown +21 -8
  4. data/application/css/add_alias_dialogue.css.scss +79 -0
  5. data/application/css/{v2.scss → core.css.scss} +537 -550
  6. data/application/css/{definitions.scss → definitions.css.scss} +121 -33
  7. data/application/css/dialogue.css.scss +409 -0
  8. data/application/css/{editing.scss → editing.css.scss} +25 -262
  9. data/application/css/font.css.scss +8 -0
  10. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  11. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  12. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_flat_10_000000_40x100.png +0 -0
  13. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  14. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  15. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  16. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  17. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  18. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  19. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_222222_256x240.png +0 -0
  20. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_228ef1_256x240.png +0 -0
  21. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ef8c08_256x240.png +0 -0
  22. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffd27a_256x240.png +0 -0
  23. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffffff_256x240.png +0 -0
  24. data/application/css/jquery-ui-1.8.21.custom/ui-lightness.css.scss +565 -0
  25. data/application/css/{login.scss → login.css.scss} +4 -4
  26. data/application/css/meta.css.scss +331 -0
  27. data/application/css/{popover.scss → popover.css.scss} +9 -8
  28. data/application/css/{schema_error.scss → schema_error.css.scss} +4 -4
  29. data/application/css/spontaneous.css +5 -0
  30. data/application/css/unsupported.css.scss +42 -0
  31. data/application/js/add_alias_dialogue.js +72 -10
  32. data/application/js/ajax.js +50 -16
  33. data/application/js/compatibility.js +19 -15
  34. data/application/js/content.js +39 -36
  35. data/application/js/content_area.js +53 -5
  36. data/application/js/dialogue.js +17 -0
  37. data/application/js/dom.js +1 -1
  38. data/application/js/edit_panel.js +23 -8
  39. data/application/js/extensions.js +7 -2
  40. data/application/js/field_preview.js +2 -1
  41. data/application/js/field_types/date_field.js +11 -8
  42. data/application/js/field_types/file_field.js +188 -9
  43. data/application/js/field_types/image_field.js +46 -29
  44. data/application/js/field_types/markdown_field.js +57 -14
  45. data/application/js/field_types/select_field.js +72 -0
  46. data/application/js/field_types/string_field.js +8 -0
  47. data/application/js/field_types/webvideo_field.js +8 -0
  48. data/application/js/init.js +1 -7
  49. data/application/js/location.js +41 -13
  50. data/application/js/login.js +3 -0
  51. data/application/js/meta_view/user_admin.js +543 -0
  52. data/application/js/meta_view.js +1 -0
  53. data/application/js/metadata.js +20 -0
  54. data/application/js/page.js +17 -3
  55. data/application/js/page_browser.js +40 -30
  56. data/application/js/page_entry.js +4 -0
  57. data/application/js/panel/root_menu.js +66 -0
  58. data/application/js/popover.js +2 -2
  59. data/application/js/preview.js +1 -1
  60. data/application/js/publish.js +138 -30
  61. data/application/js/services.js +43 -0
  62. data/application/js/sharded_upload.js +2 -2
  63. data/application/js/spontaneous.js +64 -5
  64. data/application/js/state.js +20 -9
  65. data/application/js/top_bar.js +273 -150
  66. data/application/js/types.js +20 -15
  67. data/application/js/upload.js +1 -2
  68. data/application/js/user.js +18 -4
  69. data/application/js/vendor/date.js +104 -0
  70. data/application/js/vendor/jquery-ui-1.8.18.custom.min.js +356 -0
  71. data/application/js/views/box_view.js +15 -8
  72. data/application/js/views/page_piece_view.js +11 -8
  73. data/application/js/views/page_view.js +21 -3
  74. data/application/js/views/piece_view.js +19 -10
  75. data/application/js/views.js +3 -0
  76. data/application/static/chromelogo-200x52-45c7cbc93be080bea342df5fcda2ef8b.png +0 -0
  77. data/application/static/dot-texture-9eea29e4ac7ad9a772285252078ec127.png +0 -0
  78. data/application/static/editing-textarea-resize-s-b5af62365eb7e19ea4beccf7242d508e.png +0 -0
  79. data/application/static/editing-texture-1-42b06a3439752490988f30f2a06d5e7c.png +0 -0
  80. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  81. data/application/static/loop_alt1-white-7894b458528e92216196cae26b4c2c96.svg +12 -0
  82. data/application/static/spontaneous-states-e91ec89db525c62da0105b97cdd781ce.png +0 -0
  83. data/application/views/index.erb +2 -2
  84. data/application/views/login.erb +4 -8
  85. data/application/views/schema_modification_error.html.erb +1 -4
  86. data/application/views/unsupported.erb +9 -7
  87. data/bin/spot +1 -1
  88. data/db/migrations/20110209152710_users_and_groups.rb +10 -10
  89. data/db/migrations/20120305112647_site_modification_time.rb +11 -0
  90. data/db/migrations/20120418153903_add_ownership_of_content.rb +14 -0
  91. data/db/migrations/20120423175416_add_pending_modifications.rb +21 -0
  92. data/db/migrations/20120525164947_add_field_versions.rb +27 -0
  93. data/lib/sequel/plugins/scoped_table_name.rb +10 -1
  94. data/lib/spontaneous/asset/file.rb +25 -0
  95. data/lib/spontaneous/asset/source.rb +28 -0
  96. data/lib/spontaneous/asset.rb +75 -0
  97. data/lib/spontaneous/box.rb +6 -4
  98. data/lib/spontaneous/capistrano/deploy.rb +47 -0
  99. data/lib/spontaneous/capistrano/sync.rb +81 -0
  100. data/lib/spontaneous/capistrano.rb +13 -0
  101. data/lib/spontaneous/change.rb +60 -68
  102. data/lib/spontaneous/cli/assets.rb +29 -0
  103. data/lib/spontaneous/cli/base.rb +0 -48
  104. data/lib/spontaneous/cli/console.rb +1 -1
  105. data/lib/spontaneous/cli/server.rb +6 -4
  106. data/lib/spontaneous/cli/site.rb +28 -17
  107. data/lib/spontaneous/cli/user.rb +107 -0
  108. data/lib/spontaneous/cli.rb +100 -4
  109. data/lib/spontaneous/collections/entry_set.rb +2 -2
  110. data/lib/spontaneous/collections/field_set.rb +48 -22
  111. data/lib/spontaneous/collections/prototype_set.rb +20 -13
  112. data/lib/spontaneous/constants.rb +3 -0
  113. data/lib/spontaneous/content.rb +22 -5
  114. data/lib/spontaneous/errors.rb +3 -3
  115. data/lib/spontaneous/extensions/array.rb +12 -0
  116. data/lib/spontaneous/extensions/enumerable.rb +30 -0
  117. data/lib/spontaneous/extensions/nil.rb +3 -1
  118. data/lib/spontaneous/extensions/string.rb +16 -0
  119. data/lib/spontaneous/field_types/date_field.rb +45 -2
  120. data/lib/spontaneous/field_types/field.rb +42 -9
  121. data/lib/spontaneous/field_types/file_field.rb +68 -0
  122. data/lib/spontaneous/field_types/image_field.rb +63 -0
  123. data/lib/spontaneous/field_types/select_field.rb +109 -0
  124. data/lib/spontaneous/field_types/string_field.rb +6 -1
  125. data/lib/spontaneous/field_types/webvideo_field.rb +85 -27
  126. data/lib/spontaneous/field_types.rb +1 -1
  127. data/lib/spontaneous/field_version.rb +8 -0
  128. data/lib/spontaneous/generators/page.rb +1 -1
  129. data/lib/spontaneous/generators/site/Capfile.tt +1 -4
  130. data/lib/spontaneous/generators/site/Gemfile.tt +13 -6
  131. data/lib/spontaneous/generators/site/config/deploy.rb.tt +28 -0
  132. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +7 -2
  133. data/lib/spontaneous/generators/site.rb +1 -0
  134. data/lib/spontaneous/json.rb +34 -11
  135. data/lib/spontaneous/layout.rb +22 -0
  136. data/lib/spontaneous/media/file.rb +4 -0
  137. data/lib/spontaneous/output/assets/compression.rb +58 -0
  138. data/lib/spontaneous/output/assets.rb +32 -0
  139. data/lib/spontaneous/output/context.rb +179 -0
  140. data/lib/spontaneous/output/format/html.rb +5 -0
  141. data/lib/spontaneous/output/format/plain.rb +5 -0
  142. data/lib/spontaneous/output/format.rb +180 -0
  143. data/lib/spontaneous/output/helpers/classes_helper.rb +18 -0
  144. data/lib/spontaneous/{render/helpers/html_helper.rb → output/helpers/conditional_comment_helper.rb} +3 -12
  145. data/lib/spontaneous/output/helpers/script_helper.rb +73 -0
  146. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +61 -0
  147. data/lib/spontaneous/output/helpers.rb +28 -0
  148. data/lib/spontaneous/output/template/engine.rb +59 -0
  149. data/lib/spontaneous/output/template/renderer.rb +153 -0
  150. data/lib/spontaneous/output/template.rb +21 -0
  151. data/lib/spontaneous/output.rb +163 -0
  152. data/lib/spontaneous/page.rb +2 -1
  153. data/lib/spontaneous/paths.rb +6 -1
  154. data/lib/spontaneous/permissions/access_key.rb +5 -5
  155. data/lib/spontaneous/permissions/user.rb +81 -35
  156. data/lib/spontaneous/permissions/user_level.rb +26 -22
  157. data/lib/spontaneous/plugins/aliases.rb +76 -12
  158. data/lib/spontaneous/plugins/allowed_types.rb +60 -18
  159. data/lib/spontaneous/plugins/application/paths.rb +0 -28
  160. data/lib/spontaneous/plugins/application/system.rb +35 -0
  161. data/lib/spontaneous/plugins/boxes.rb +4 -0
  162. data/lib/spontaneous/plugins/content_groups.rb +16 -0
  163. data/lib/spontaneous/plugins/entries.rb +50 -30
  164. data/lib/spontaneous/plugins/fields.rb +15 -0
  165. data/lib/spontaneous/plugins/layouts.rb +8 -2
  166. data/lib/spontaneous/plugins/modifications.rb +228 -0
  167. data/lib/spontaneous/plugins/page/formats.rb +67 -42
  168. data/lib/spontaneous/plugins/page/request.rb +10 -0
  169. data/lib/spontaneous/plugins/page/site_timestamps.rb +28 -0
  170. data/lib/spontaneous/plugins/paths.rb +15 -3
  171. data/lib/spontaneous/plugins/publishing.rb +124 -45
  172. data/lib/spontaneous/plugins/render.rb +13 -8
  173. data/lib/spontaneous/plugins/schema_hierarchy.rb +18 -6
  174. data/lib/spontaneous/plugins/site/helpers.rb +53 -0
  175. data/lib/spontaneous/plugins/site/hooks.rb +50 -0
  176. data/lib/spontaneous/plugins/site/map.rb +1 -1
  177. data/lib/spontaneous/plugins/site/paths.rb +13 -0
  178. data/lib/spontaneous/plugins/site/publishing.rb +6 -2
  179. data/lib/spontaneous/plugins/site/{revisions.rb → state.rb} +5 -1
  180. data/lib/spontaneous/plugins/site/storage.rb +4 -0
  181. data/lib/spontaneous/plugins/site/url.rb +15 -0
  182. data/lib/spontaneous/plugins/site_map.rb +13 -3
  183. data/lib/spontaneous/plugins/styles.rb +5 -1
  184. data/lib/spontaneous/plugins/visibility.rb +39 -12
  185. data/lib/spontaneous/prototypes/box_prototype.rb +4 -0
  186. data/lib/spontaneous/prototypes/field_prototype.rb +15 -10
  187. data/lib/spontaneous/publishing/event_client.rb +46 -0
  188. data/lib/spontaneous/publishing/immediate.rb +81 -44
  189. data/lib/spontaneous/publishing/simultaneous.rb +23 -6
  190. data/lib/spontaneous/publishing.rb +4 -3
  191. data/lib/spontaneous/rack/around_back.rb +1 -5
  192. data/lib/spontaneous/rack/around_front.rb +4 -4
  193. data/lib/spontaneous/rack/around_preview.rb +4 -3
  194. data/lib/spontaneous/rack/assets.rb +81 -54
  195. data/lib/spontaneous/rack/authentication.rb +0 -1
  196. data/lib/spontaneous/rack/back.rb +160 -72
  197. data/lib/spontaneous/rack/cookie_authentication.rb +2 -2
  198. data/lib/spontaneous/rack/css.rb +18 -15
  199. data/lib/spontaneous/rack/event_source.rb +9 -21
  200. data/lib/spontaneous/rack/fiber_pool.rb +26 -0
  201. data/lib/spontaneous/rack/front.rb +12 -4
  202. data/lib/spontaneous/rack/helpers.rb +35 -13
  203. data/lib/spontaneous/rack/js.rb +41 -0
  204. data/lib/spontaneous/rack/public.rb +34 -44
  205. data/lib/spontaneous/rack/sse.rb +18 -0
  206. data/lib/spontaneous/rack/static.rb +3 -0
  207. data/lib/spontaneous/rack/user_admin.rb +100 -0
  208. data/lib/spontaneous/rack/user_helpers.rb +1 -1
  209. data/lib/spontaneous/rack.rb +6 -2
  210. data/lib/spontaneous/schema.rb +31 -4
  211. data/lib/spontaneous/search/index.rb +19 -3
  212. data/lib/spontaneous/search/results.rb +1 -1
  213. data/lib/spontaneous/sequel.rb +17 -0
  214. data/lib/spontaneous/site.rb +11 -4
  215. data/lib/spontaneous/state.rb +11 -0
  216. data/lib/spontaneous/storage/cloud.rb +4 -0
  217. data/lib/spontaneous/storage/local.rb +11 -0
  218. data/lib/spontaneous/style.rb +2 -2
  219. data/lib/spontaneous/tasks/database.rake +21 -22
  220. data/lib/spontaneous/utils/database/mysql_dumper.rb +4 -0
  221. data/lib/spontaneous/utils/database/postgres_dumper.rb +78 -0
  222. data/lib/spontaneous/utils/database.rb +6 -3
  223. data/lib/spontaneous/utils/smart_quotes.rb +499 -0
  224. data/lib/spontaneous/utils/smush_it.rb +66 -0
  225. data/lib/spontaneous/utils.rb +3 -1
  226. data/lib/spontaneous/version.rb +2 -2
  227. data/lib/spontaneous.rb +25 -29
  228. data/spontaneous.gemspec +186 -106
  229. data/test/experimental/test_features.rb +1 -1
  230. data/test/fixtures/asset_pipeline/application/css/basic.css.scss +4 -0
  231. data/test/fixtures/asset_pipeline/application/css/complex.css.scss.erb +6 -0
  232. data/test/fixtures/asset_pipeline/application/css/simple.css +3 -0
  233. data/test/fixtures/asset_pipeline/application/css/spontaneous.css +7 -0
  234. data/test/fixtures/asset_pipeline/application/css/subdir/complex.css.scss.erb +6 -0
  235. data/test/fixtures/asset_pipeline/application/css/subdir/library.css.scss +1 -0
  236. data/test/fixtures/asset_pipeline/application/css/subdir/simple.css +3 -0
  237. data/test/fixtures/asset_pipeline/application/js/basic.js.coffee +1 -0
  238. data/test/fixtures/asset_pipeline/application/js/complex.js.coffee.erb +1 -0
  239. data/test/fixtures/asset_pipeline/application/js/login.js +1 -0
  240. data/test/fixtures/asset_pipeline/application/js/require.js +1 -0
  241. data/test/fixtures/asset_pipeline/application/js/simple.js +1 -0
  242. data/test/fixtures/asset_pipeline/application/js/spontaneous.js +5 -0
  243. data/test/fixtures/asset_pipeline/application/js/subdir/complex.js.coffee.erb +1 -0
  244. data/test/fixtures/asset_pipeline/application/js/subdir/library.js.coffee +1 -0
  245. data/test/fixtures/asset_pipeline/application/js/subdir/simple.js +1 -0
  246. data/test/fixtures/asset_pipeline/application/js/vendor/jquery.js +1 -0
  247. data/test/fixtures/asset_pipeline/application/static/dot-texture.png +0 -0
  248. data/test/fixtures/asset_pipeline/application/static/subdir/px.gif +0 -0
  249. data/test/fixtures/assets/public1/css/a.scss +1 -0
  250. data/test/fixtures/assets/public1/js/a.js +1 -0
  251. data/test/fixtures/assets/public1/js/m.coffee +1 -0
  252. data/test/fixtures/assets/public2/css/b.scss +1 -0
  253. data/test/fixtures/assets/public2/css/c.css +1 -0
  254. data/test/fixtures/assets/public2/js/b.js +1 -0
  255. data/test/fixtures/assets/public2/js/c.js +1 -0
  256. data/test/fixtures/assets/public2/js/n.coffee +1 -0
  257. data/test/fixtures/back/config/user_levels.yml +3 -0
  258. data/test/fixtures/back/public/js/coffeescript.coffee +1 -0
  259. data/test/fixtures/back/templates/layouts/standard.css.cut +1 -0
  260. data/test/fixtures/back/templates/layouts/standard.js.cut +1 -0
  261. data/test/fixtures/example_application/config/database.yml +4 -4
  262. data/test/fixtures/helpers/templates/layouts/standard.html.cut +1 -0
  263. data/test/fixtures/helpers/templates/layouts/standard.mobile.cut +1 -0
  264. data/test/fixtures/images/vimlogo.pdf +0 -0
  265. data/test/fixtures/outputs/templates/layouts/standard.atom.cut +1 -0
  266. data/test/fixtures/permissions/config/user_levels.yml +6 -3
  267. data/test/fixtures/serialisation/class_hash.yaml.erb +1 -0
  268. data/test/fixtures/serialisation/root_hash.yaml.erb +2 -2
  269. data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
  270. data/test/fixtures/templates/extended/main.html.cut +5 -5
  271. data/test/fixtures/templates/extended/parent.html.cut +8 -8
  272. data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -1
  273. data/test/fixtures/templates/extended/with_includes.html.cut +6 -6
  274. data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +6 -7
  275. data/test/fixtures/templates/layouts/entries.html.cut +4 -4
  276. data/test/fixtures/templates/layouts/standard.html.cut +1 -0
  277. data/test/fixtures/templates/layouts/variables.html.cut +1 -1
  278. data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -1
  279. data/test/fixtures/templates/publishing/templates/layouts/static.rtf.cut +1 -0
  280. data/test/fixtures/templates/template_class/complex_template.html.cut +2 -2
  281. data/test/fixtures/templates/template_class/complex_template.pdf.cut +2 -2
  282. data/test/fixtures/templates/template_class/default_template_style.html.cut +1 -1
  283. data/test/fixtures/templates/template_class/images_with_template.html.cut +2 -2
  284. data/test/fixtures/templates/template_class/slots_template.html.cut +2 -2
  285. data/test/fixtures/templates/template_class/slots_template.pdf.cut +2 -2
  286. data/test/fixtures/user_manager/config/user_levels.yml +9 -0
  287. data/test/functional/test_application.rb +7 -7
  288. data/test/functional/test_back.rb +352 -97
  289. data/test/functional/test_front.rb +71 -20
  290. data/test/functional/test_user_manager.rb +284 -0
  291. data/test/javascript/env.js +13505 -0
  292. data/test/javascript/test_markdown.rb +43 -3
  293. data/test/support/custom_matchers.rb +3 -2
  294. data/test/test_helper.rb +50 -9
  295. data/test/test_javascript.rb +13 -13
  296. data/test/ui_helper.rb +1 -1
  297. data/test/unit/test_alias.rb +79 -8
  298. data/test/unit/test_asset_bundler.rb +220 -0
  299. data/test/unit/test_assets.rb +213 -0
  300. data/test/unit/test_async.rb +55 -0
  301. data/test/unit/test_authentication.rb +52 -39
  302. data/test/unit/test_boxes.rb +20 -15
  303. data/test/unit/test_changesets.rb +261 -0
  304. data/test/unit/test_content.rb +73 -33
  305. data/test/unit/test_content_inheritance.rb +18 -18
  306. data/test/unit/test_extensions.rb +26 -0
  307. data/test/unit/test_fields.rb +303 -16
  308. data/test/unit/test_formats.rb +267 -34
  309. data/test/unit/test_helpers.rb +79 -2
  310. data/test/unit/test_images.rb +10 -0
  311. data/test/unit/test_layouts.rb +21 -13
  312. data/test/unit/test_modifications.rb +648 -0
  313. data/test/unit/test_page.rb +6 -2
  314. data/test/unit/test_permissions.rb +101 -27
  315. data/test/unit/test_piece.rb +4 -4
  316. data/test/unit/test_plugins.rb +3 -2
  317. data/test/unit/test_publishing.rb +332 -0
  318. data/test/unit/test_render.rb +118 -67
  319. data/test/unit/test_revisions.rb +546 -0
  320. data/test/unit/test_schema.rb +83 -1
  321. data/test/unit/test_search.rb +59 -0
  322. data/test/unit/test_serialisation.rb +2 -47
  323. data/test/unit/test_site.rb +217 -108
  324. data/test/unit/test_storage.rb +26 -0
  325. data/test/unit/test_structure.rb +2 -2
  326. data/test/unit/test_styles.rb +90 -75
  327. data/test/unit/test_table_scoping.rb +21 -17
  328. data/test/unit/test_templates.rb +75 -69
  329. data/test/{slow → unit}/test_visibility.rb +78 -22
  330. metadata +528 -221
  331. data/application/css/add_alias_dialogue.scss +0 -27
  332. data/application/css/min/14c2a35812c443001b15d8b12a4780f88c678035.css +0 -1
  333. data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +0 -1
  334. data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +0 -1
  335. data/application/css/spontaneous.scss +0 -111
  336. data/application/css/unsupported.scss +0 -16
  337. data/application/css/variables.scss +0 -80
  338. data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +0 -3
  339. data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +0 -2
  340. data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +0 -3
  341. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +0 -2
  342. data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +0 -90
  343. data/application/static/diagonal-texture.png +0 -0
  344. data/application/static/editing-0-noise.png +0 -0
  345. data/application/static/editing-1-noise.png +0 -0
  346. data/application/static/editing-texture-1.png +0 -0
  347. data/application/static/editing-texture.png +0 -0
  348. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  349. data/application/static/editing-toolbar-shadow-top.png +0 -0
  350. data/application/static/inner-glow.png +0 -0
  351. data/application/static/item-buttons-highlight.png +0 -0
  352. data/application/static/item-buttons.png +0 -0
  353. data/application/static/paper-texture-dark.png +0 -0
  354. data/application/static/plus_alt.svg +0 -8
  355. data/application/static/select-arrow-root.png +0 -0
  356. data/application/static/slot-up-arrow.png +0 -0
  357. data/application/static/spontaneous.png +0 -0
  358. data/lib/cutaneous/context_helper.rb +0 -187
  359. data/lib/cutaneous/preview_context.rb +0 -32
  360. data/lib/cutaneous/preview_renderer.rb +0 -10
  361. data/lib/cutaneous/publish_context.rb +0 -10
  362. data/lib/cutaneous/publish_renderer.rb +0 -14
  363. data/lib/cutaneous/publish_template.rb +0 -62
  364. data/lib/cutaneous/publish_token_parser.rb +0 -8
  365. data/lib/cutaneous/renderer.rb +0 -124
  366. data/lib/cutaneous/request_context.rb +0 -9
  367. data/lib/cutaneous/request_renderer.rb +0 -15
  368. data/lib/cutaneous/request_template.rb +0 -11
  369. data/lib/cutaneous/request_token_parser.rb +0 -9
  370. data/lib/cutaneous/token_parser.rb +0 -125
  371. data/lib/cutaneous.rb +0 -48
  372. data/lib/spontaneous/render/context_base.rb +0 -143
  373. data/lib/spontaneous/render/development_renderer.rb +0 -14
  374. data/lib/spontaneous/render/engine.rb +0 -19
  375. data/lib/spontaneous/render/format/html.rb +0 -5
  376. data/lib/spontaneous/render/format.rb +0 -75
  377. data/lib/spontaneous/render/helpers/script_helper.rb +0 -17
  378. data/lib/spontaneous/render/helpers/stylesheet_helper.rb +0 -16
  379. data/lib/spontaneous/render/helpers.rb +0 -14
  380. data/lib/spontaneous/render/preview_context.rb +0 -8
  381. data/lib/spontaneous/render/preview_renderer.rb +0 -24
  382. data/lib/spontaneous/render/publish_context.rb +0 -22
  383. data/lib/spontaneous/render/published_renderer.rb +0 -53
  384. data/lib/spontaneous/render/publishing_renderer.rb +0 -16
  385. data/lib/spontaneous/render/render_cache.rb +0 -26
  386. data/lib/spontaneous/render/renderer.rb +0 -50
  387. data/lib/spontaneous/render/request_context.rb +0 -8
  388. data/lib/spontaneous/render.rb +0 -214
  389. data/test/experimental/test_cutaneous.rb +0 -309
  390. data/test/fixtures/application/css/test.less +0 -5
  391. data/test/slow/test_publishing.rb +0 -1006
  392. /data/application/css/{developer.scss → developer.css.scss} +0 -0
  393. /data/application/js/vendor/{jquery-1.7.1.min.js → jquery.js} +0 -0
  394. /data/application/static/{location-arrow.png → location-arrow-c1c1d3ca472481c61a0a5f8cb289d743.png} +0 -0
  395. /data/application/static/{missing.png → missing-911ce6dbd9f4602e0f3fbcd7e78846a2.png} +0 -0
  396. /data/application/static/{orange-down-arrow.png → orange-down-arrow-395ae1929e8662b2ff0977daf12c35bb.png} +0 -0
  397. /data/application/static/{page-browser-next.png → page-browser-next-ce781a242c23b980b99b9db7abc20b05.png} +0 -0
  398. /data/application/static/{plus-box.png → plus-box-dcde74a1e496f68298c9b443caa1c5d5.png} +0 -0
  399. /data/application/static/{select-arrow.png → select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png} +0 -0
  400. /data/application/static/{slot-down-arrow.png → slot-down-arrow-59ad5f5ee5b52a7ebd00bca4b3104194.png} +0 -0
  401. /data/application/static/{splash.png → splash-65b493a714df9b8b3ab170103401b53d.png} +0 -0
  402. /data/application/static/{spot.png → spot-71fab1d2f065034f5fc15e7bea2ad36c.png} +0 -0
  403. /data/application/static/{spot.svg → spot-8505041082d8d3bbe8d34c29dddb3b7d.svg} +0 -0
  404. /data/application/static/{texture.png → texture-03f7627e8264b1d607113ab32c593a58.png} +0 -0
@@ -14,7 +14,6 @@ module Spontaneous::Plugins
14
14
 
15
15
  # InstanceMethods
16
16
 
17
- VISIBILITY_PATH_SEP = ".".freeze
18
17
 
19
18
  # because it's possible to build content out of order
20
19
  # some relations don't necessarily get created straight away
@@ -31,31 +30,29 @@ module Spontaneous::Plugins
31
30
  end
32
31
 
33
32
  def after_save
34
- pieces.each do |entry|
33
+ contents.each do |entry|
35
34
  entry.save if entry.modified?
36
35
  end
37
36
  super
38
37
  end
39
38
 
40
- def destroy(remove_owner_entry=true, owner=nil)
41
- owner ||= self.owner
42
- if owner && remove_owner_entry
43
- owner.destroy_entry!(self)
44
- end
39
+ def destroy(remove_owner_entry=true, origin = nil)
40
+ is_origin = origin.nil?
41
+ origin ||= owner
42
+ recursive_destroy(origin)
43
+ origin.child_page_deleted! if (origin && page?)
44
+ owner = self.owner
45
+ owner.destroy_entry!(self) if (owner && remove_owner_entry)
45
46
  super()
47
+ origin.after_child_destroy if is_origin && origin
46
48
  end
47
49
 
48
- def before_destroy
49
- recursive_destroy
50
- super
51
- end
52
-
53
- def recursive_destroy
54
- all_pieces.destroy
50
+ def recursive_destroy(origin)
51
+ all_contents.destroy(origin)
55
52
  end
56
53
 
57
54
  def destroy_entry!(entry)
58
- pieces.remove(entry)
55
+ contents.remove(entry)
59
56
  # save the owner because it won't be obvious to the caller
60
57
  # that content other than the destroyed object will have been
61
58
  # modified
@@ -67,39 +64,42 @@ module Spontaneous::Plugins
67
64
  end
68
65
 
69
66
  def entry_modified!(modified_entry)
70
- self.entry_store = all_pieces.serialize_db
67
+ # See plugins/modifications.rb for details of __ignore_page_modification ... basically
68
+ # it stops the parent page appearing in the publishing list when a new page is added.
69
+ @__ignore_page_modification = modified_entry && modified_entry.added? && modified_entry.page?
70
+ self.entry_store = all_contents.serialize_db
71
71
  end
72
72
 
73
- def pieces
74
- return visible_pieces if Spontaneous::Content.visible_only?
75
- all_pieces
73
+ def contents
74
+ return visible_contents if Spontaneous::Content.visible_only?
75
+ all_contents
76
76
  end
77
77
 
78
78
  # ensure that all access to pieces is through their corresponding entry
79
79
  # alias_method :pieces, :entries
80
80
 
81
- def all_pieces
82
- @all_pieces ||= Spontaneous::Collections::EntrySet.new(self, entry_store)
81
+ def all_contents
82
+ @all_contents ||= Spontaneous::Collections::EntrySet.new(self, entry_store)
83
83
  end
84
84
 
85
- def visible_pieces
86
- @visible_pieces ||= all_pieces.visible!
85
+ def visible_contents
86
+ @visible_contents ||= all_contents.visible!
87
87
  end
88
88
 
89
- protected(:all_pieces, :visible_pieces)
89
+ protected(:all_contents, :visible_contents)
90
90
 
91
91
  def reload
92
- @all_pieces = @visible_pieces = nil
92
+ @all_contents = @visible_contents = nil
93
93
  super
94
94
  end
95
95
 
96
96
 
97
97
  def first
98
- pieces.first
98
+ contents.first
99
99
  end
100
100
 
101
101
  def last
102
- pieces.last
102
+ contents.last
103
103
  end
104
104
 
105
105
  def push(page_or_piece)
@@ -139,6 +139,7 @@ module Spontaneous::Plugins
139
139
  entry_style = style_for_content(content, box)
140
140
  content.box_sid = box.schema_id if box
141
141
  content._prototype = box.prototype_for_content(content) if box
142
+ content.set_visible(self.visible?, self.id)
142
143
  content.save if content.new?
143
144
  entry = \
144
145
  case type
@@ -149,7 +150,7 @@ module Spontaneous::Plugins
149
150
  content
150
151
  end
151
152
  begin
152
- pieces.insert(index, box, entry)
153
+ contents.insert(index, box, entry)
153
154
  rescue TypeError, RuntimeError => e
154
155
  # TODO: raise a custom more helpful error here
155
156
  logger.error { "Attempting to modify visible only pieces" }
@@ -159,6 +160,16 @@ module Spontaneous::Plugins
159
160
  entry
160
161
  end
161
162
 
163
+ # added is my private mechanism for tracking if a content item is new
164
+ def before_create
165
+ @added = true
166
+ super
167
+ end
168
+
169
+ def added?
170
+ @added
171
+ end
172
+
162
173
  def update_position(position)
163
174
  entry.set_position(position)
164
175
  owner.save
@@ -168,7 +179,7 @@ module Spontaneous::Plugins
168
179
  if box
169
180
  box.set_position(self, new_position)
170
181
  else
171
- owner.pieces.set_position(self, new_position)
182
+ owner.contents.set_position(self, new_position)
172
183
  end
173
184
  end
174
185
 
@@ -186,7 +197,16 @@ module Spontaneous::Plugins
186
197
 
187
198
  def owner=(owner)
188
199
  super
189
- self[:visibility_path] = [owner.visibility_path, owner.id].compact.join(VISIBILITY_PATH_SEP)
200
+ set_visibility_path
201
+ end
202
+
203
+ def set_visibility_path
204
+ self[:visibility_path] = [owner.visibility_path, owner.id].compact.join(Spontaneous::VISIBILITY_PATH_SEP)
205
+ end
206
+
207
+ def set_visibility_path!
208
+ set_visibility_path
209
+ save
190
210
  end
191
211
  end # Entries
192
212
  end # Spontaneous::Plugins
@@ -75,6 +75,21 @@ module Spontaneous::Plugins
75
75
  fields.saved
76
76
  end
77
77
 
78
+ def before_save
79
+ save_field_versions
80
+ super
81
+ end
82
+
83
+ def field_versions(field)
84
+ Spontaneous::FieldVersion.filter(:content_id => self.id, :field_sid => field.schema_id.to_s).order(:created_at.desc)
85
+ end
86
+
87
+ def save_field_versions
88
+ fields.each do |field|
89
+ field.create_version if field.modified?
90
+ end
91
+ end
92
+
78
93
  def reload
79
94
  @field_set = nil
80
95
  super
@@ -5,8 +5,13 @@ module Spontaneous::Plugins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- def layout(name, options={})
9
- layout_prototypes[name] = Spontaneous::Prototypes::LayoutPrototype.new(self, name, options)
8
+ def layout(name = nil, options = {}, &block)
9
+ if block_given?
10
+ @layout_proc = block
11
+ else
12
+ raise "Layouts must be given a name" if name.blank?
13
+ layout_prototypes[name] = Spontaneous::Prototypes::LayoutPrototype.new(self, name, options)
14
+ end
10
15
  end
11
16
 
12
17
  def layout_prototypes
@@ -24,6 +29,7 @@ module Spontaneous::Plugins
24
29
  end
25
30
 
26
31
  def default_layout
32
+ return Spontaneous::Layout::Anonymous.new(@layout_proc) unless @layout_proc.nil?
27
33
  if prototype = (layouts.hierarchy_detect { |prototype| prototype.default? } || layouts.local_first)
28
34
  prototype.layout(self)
29
35
  else
@@ -0,0 +1,228 @@
1
+ module Spontaneous::Plugins
2
+ # Modifications is responsible for tracking changes made to Content items
3
+ module Modifications
4
+ extend ActiveSupport::Concern
5
+
6
+ class SlugModification
7
+ def self.type
8
+ :slug
9
+ end
10
+
11
+ attr_reader :owner, :user, :created_at, :old_value, :new_value
12
+
13
+ def initialize(owner, user, created_at, old_value, new_value)
14
+ @owner, @user, @created_at, @old_value, @new_value = owner, user, created_at, old_value, new_value
15
+ @created_at = Time.parse(created_at) if @created_at.is_a?(String)
16
+ @user = Spontaneous::Permissions::User[user] if @user.is_a?(Fixnum)
17
+ end
18
+
19
+ # Must apply this change the slow way by cascading updates from the parent because
20
+ # otherwise it's difficult to publish changes to a child page's slug and publish them
21
+ # separately
22
+ def apply(revision)
23
+ owner.with_revision(revision) do
24
+ owner.force_path_changes
25
+ end
26
+ end
27
+
28
+ def dataset
29
+ path_like = :ancestor_path.like("#{owner[:ancestor_path]}.#{owner.id}%")
30
+ Spontaneous::Content.filter(path_like)
31
+ end
32
+
33
+ def count
34
+ dataset.count
35
+ end
36
+
37
+ def serialize
38
+ [type, user_id, created_at.to_s(:rfc822), old_value, new_value]
39
+ end
40
+
41
+ def user_id
42
+ @user.nil? ? nil : @user.id
43
+ end
44
+
45
+ def type
46
+ self.class.type
47
+ end
48
+
49
+ def ==(other)
50
+ super || (other.class == self.class &&
51
+ other.owner.id == self.owner.id &&
52
+ other.old_value == self.old_value &&
53
+ other.new_value == self.new_value)
54
+ end
55
+
56
+ def new_value=(value)
57
+ @created_at = Time.now
58
+ @new_value = value
59
+ end
60
+
61
+ def inspect
62
+ %(#<#{self.class}:#{self.object_id.to_s(16)} owner="#{owner.id}" old_value=#{old_value.inspect} new_value=#{new_value.inspect}>)
63
+ end
64
+ end
65
+
66
+ class HiddenModification < SlugModification
67
+ def self.type
68
+ :visibility
69
+ end
70
+
71
+ def apply(revision)
72
+ owner.with_revision(revision) do
73
+ published = Spontaneous::Content.first :id => owner.id
74
+ published.set_visible_with_cascade!(!new_value)
75
+ end
76
+ end
77
+
78
+ def dataset
79
+ path_like = :visibility_path.like("#{owner[:visibility_path]}.#{owner.id}%")
80
+ Spontaneous::Page.filter(path_like)
81
+ end
82
+ end
83
+
84
+ class DeletionModification < SlugModification
85
+ def self.type
86
+ :deletion
87
+ end
88
+
89
+ def apply(revision)
90
+ # Deletion modifications are handled higher up the publish chain.
91
+ # The modification objects are merely for informational purposes.
92
+ end
93
+
94
+ def count
95
+ old_value - new_value
96
+ end
97
+ end
98
+
99
+ def current_editor
100
+ @current_editor
101
+ end
102
+
103
+ def current_editor=(user)
104
+ @current_editor = user
105
+ end
106
+
107
+ def reload
108
+ @local_modifications = nil
109
+ super
110
+ end
111
+
112
+ def before_save
113
+ # Home of many hacks.
114
+ #
115
+ # @__ignore_page_modification is set if a box has been modified by the addition of a page.
116
+ # This is to correctly map changes to a list of pages to publish. In the case of a page
117
+ # addition the change is owned by the new page.
118
+ self.modified_at = Time.now unless @__ignore_page_modification or changed_columns.empty?
119
+ # marks this object as the modified object appending modifications to the list
120
+ # needed in order to know if changes to the modification list will be saved automatically
121
+ # or if we need an explicit call to #save
122
+ generate_modification_list
123
+ super
124
+ end
125
+
126
+ def after_publish(revision)
127
+ pending_modifications.each do |modification|
128
+ modification.apply(revision)
129
+ end
130
+ with_editable { clear_pending_modifications! }
131
+ with_revision(revision) { clear_pending_modifications! }
132
+ super
133
+ end
134
+
135
+ def generate_modification_list
136
+ create_slug_modifications
137
+ create_visibility_modifications
138
+ serialize_pending_modifications
139
+ end
140
+
141
+ def child_page_deleted!
142
+ @child_page_deletion_count ||= 0
143
+ @child_page_deletion_count += 1
144
+ end
145
+
146
+ def after_child_destroy
147
+ create_deletion_modifications && serialize_pending_modifications
148
+ save
149
+ end
150
+
151
+ def create_deletion_modifications
152
+ if @child_page_deletion_count && @child_page_deletion_count > 0
153
+ count = S::Page.count
154
+ append_modification DeletionModification.new(self, current_editor, Time.now, count + @child_page_deletion_count, count)
155
+ end
156
+ end
157
+
158
+ def create_visibility_modifications
159
+ # We only want to record visibility changes that originate from user action, not ones propagated
160
+ # from higher up the tree, hence the check against the hidden_origin.
161
+ if changed_columns.include?(:hidden) && hidden_origin.nil?
162
+ if (previous_modification = local_modifications.detect { |mod| mod.type == :visibility })
163
+ if previous_modification.old_value == hidden?
164
+ remove_modification(:visibility)
165
+ return nil
166
+ end
167
+ end
168
+ append_modification HiddenModification.new(self, current_editor, Time.now, !hidden?, hidden)
169
+ end
170
+ end
171
+
172
+ def create_slug_modifications
173
+ return unless (old_slug = @__slug_changed)
174
+ if (previous_modification = local_modifications.detect { |mod| mod.type == :slug })
175
+ if previous_modification.old_value == self[:slug]
176
+ remove_modification(:slug)
177
+ return nil
178
+ end
179
+ previous_modification.new_value = self[:slug]
180
+ else
181
+ append_modification SlugModification.new(self, current_editor, Time.now, old_slug, self[:slug])
182
+ end
183
+ end
184
+
185
+ def remove_modification(type)
186
+ local_modifications.delete_if { |mod| mod.type == type }
187
+ end
188
+
189
+ def append_modification(modification)
190
+ local_modifications.push modification
191
+ end
192
+
193
+ def pending_modifications(filter_type = nil)
194
+ (local_modifications + pieces.flat_map { |piece| piece.local_modifications })
195
+ end
196
+
197
+ def clear_pending_modifications!
198
+ self.serialized_modifications = nil
199
+ self.class.filter(:id => self.id).update(:serialized_modifications => "[]")
200
+ @local_modifications = nil
201
+ pieces.each do |piece|
202
+ piece.clear_pending_modifications!
203
+ end
204
+ end
205
+
206
+ def serialize_pending_modifications
207
+ self.serialized_modifications = local_modifications.map { |modification| modification.serialize }
208
+ end
209
+
210
+ def local_modifications
211
+ @local_modifications ||= deserialize_local_modifications
212
+ end
213
+
214
+ def deserialize_local_modifications
215
+ values = self.serialized_modifications || []
216
+ class_map = modification_class_map
217
+ values.map do |(type, *values)|
218
+ type = type.to_sym
219
+ args = [self, *values]
220
+ class_map[type].new(*args)
221
+ end
222
+ end
223
+
224
+ def modification_class_map
225
+ Hash[[SlugModification, HiddenModification, DeletionModification].map { |mod_class| [mod_class.type, mod_class] }]
226
+ end
227
+ end
228
+ end
@@ -7,86 +7,111 @@ module Spontaneous::Plugins::Page
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  module ClassMethods
10
- def formats(*formats)
11
- return format_list if formats.nil? or formats.empty?
12
- set_formats(formats)
10
+ def outputs(*outputs)
11
+ return output_list if outputs.nil? or outputs.empty?
12
+ set_outputs(outputs)
13
13
  end
14
14
 
15
- def format_list
16
- @formats ||= supertype_formats
15
+ def output_map
16
+ @outputs ||= supertype_outputs
17
17
  end
18
18
 
19
- def mime_types
20
- @mime_types ||= supertype_mimetypes
19
+ def output_list
20
+ output_map.values
21
21
  end
22
22
 
23
- def add_format(new_format)
24
- format = define_format(new_format)
25
- format_list.push(format)
23
+ def add_output(format, *args)
24
+ options = args.extract_options!
25
+ output = define_and_add_output(format, options)
26
26
  end
27
27
 
28
- def set_formats(formats)
29
- formats = formats.flatten
30
- mime_types.clear
31
- format_list.clear
32
- formats.map do |format|
33
- format_list.push define_format(format)
28
+ def set_outputs(outputs)
29
+ output_map.clear
30
+ outputs.each do |definition|
31
+ define_and_add_output(*definition)
34
32
  end
35
33
  end
36
34
 
37
- def define_format(format)
38
- mime_type = nil
39
- if format.is_a?(Hash)
40
- mime_type = format.values.first
41
- format = format.keys.first
42
- mime_types[format.to_sym] = mime_type
43
- else
44
- mime_type = ::Rack::Mime.mime_type(".#{format}", nil)
35
+ def define_and_add_output(format, options = {})
36
+ output = define_output(format, options)
37
+ output_map[output.name] = output
38
+ end
39
+
40
+ def define_output(format, options = {})
41
+ o = Spontaneous::Output.create(format, options).tap do |output|
42
+ silence_warnings { self.const_set("Output#{format.to_s.upcase}", output) }
45
43
  end
46
- raise Spontaneous::UnknownFormatException.new(format) unless mime_type
47
- format.to_sym
48
44
  end
49
45
 
50
- def supertype_formats
51
- supertype? && supertype.respond_to?(:formats) ? supertype.formats.dup : [:html]
46
+ def supertype_outputs
47
+ supertype? && supertype.respond_to?(:outputs) ? supertype.output_map.dup : { :html => standard_output }
52
48
  end
53
49
 
54
- def supertype_mimetypes
55
- supertype? && supertype.respond_to?(:mime_types) ? supertype.mime_types.dup : {}
50
+ def standard_output
51
+ define_output(:html)
56
52
  end
57
53
 
58
- def default_format
59
- formats.first
54
+ def default_output
55
+ output_list.first
60
56
  end
61
57
 
62
58
  def provides_format?(format)
63
- format = (format || :html).to_sym
64
- formats.include?(format)
59
+ return true if format.blank?
60
+ format = format.to_s
61
+ outputs.any? { |output| (output == format) or (output.name.to_s == format) }
62
+ end
63
+
64
+ alias_method :provides_output?, :provides_format?
65
+
66
+ def output(name = nil)
67
+ output_without_validation(name) or raise Spontaneous::UnknownOutputException.new(self, name)
68
+ end
69
+
70
+ def output_without_validation(name = nil)
71
+ return name if name.is_a?(Spontaneous::Output::Format)
72
+ return default_output if name.blank?
73
+ output_map[name.to_sym]
65
74
  end
66
75
 
67
76
  def mime_type(format)
68
- if mime_types && mime_types.key?(format)
69
- mime_types[format]
77
+ return format.mime_type if format.respond_to?(:mime_type)
78
+ if (match = output_without_validation(format))
79
+ match.mime_type
70
80
  else
71
81
  ::Rack::Mime.mime_type(".#{format}")
72
82
  end
73
83
  end
74
84
  end # ClassMethods
75
85
 
76
- def formats
77
- self.class.formats
86
+ def outputs
87
+ self.class.outputs.map { |output| output.new(self) }
88
+ end
89
+
90
+ def default_output
91
+ self.class.default_output.new(self)
78
92
  end
79
93
 
80
- def default_format
81
- self.class.default_format
94
+ def provides_output?(format)
95
+ self.class.provides_output?(format)
82
96
  end
83
97
 
84
- def provides_format?(format)
85
- self.class.provides_format?(format)
98
+ def output(format, content = nil)
99
+ return format if format.is_a?(Spontaneous::Output::Format)
100
+ output_class = self.class.output(format)
101
+ output_class.new(self, content)
86
102
  end
87
103
 
88
104
  def mime_type(format)
89
105
  self.class.mime_type(format)
90
106
  end
107
+
108
+ def render(format=:html, params={}, *args)
109
+ if format.is_a?(Hash)
110
+ params = format
111
+ format = :html
112
+ end
113
+ output = output(format)
114
+ output.render(params, *args)
115
+ end
91
116
  end # Formats
92
117
  end # Spontaneous::Plugins::Page
@@ -63,10 +63,20 @@ module Spontaneous::Plugins::Page
63
63
  @request_blocks ||= {}
64
64
  end
65
65
 
66
+
67
+ METHOD_MAP = {"GET" => :get, "POST" => :post, "PUT" => :put, "DELETE" => :delete, "HEAD" => :head }.freeze
68
+
69
+ # Translate Rack's uppercase string methods to the symbols used internally
70
+ def normalize_method(method)
71
+ return method if method.is_a?(Symbol)
72
+ METHOD_MAP[method]
73
+ end
74
+
66
75
  # Tests for existance of a request handler for a method
67
76
  # Used by the publishing mechanism to determine which template bucket a
68
77
  # published page should be placed in.
69
78
  def dynamic?(method = :get)
79
+ method = normalize_method(method)
70
80
  request_blocks.has_key?(method) && !request_blocks[method].nil?
71
81
  end
72
82
 
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rack'
4
+
5
+ module Spontaneous::Plugins::Page
6
+ module SiteTimestamps
7
+ extend ActiveSupport::Concern
8
+
9
+ def after_update
10
+ ::Spontaneous::State.site_modified! if field?(title_field) && fields[title_field].modified?
11
+ super
12
+ end
13
+
14
+ # Update the Site's modification time to force clients
15
+ # to reload their map data
16
+ def after_create
17
+ ::Spontaneous::State.site_modified!
18
+ super
19
+ end
20
+
21
+ # Update the Site's modification time to force clients
22
+ # to reload their map data
23
+ def after_destroy
24
+ ::Spontaneous::State.site_modified!
25
+ super
26
+ end
27
+ end
28
+ end
@@ -50,6 +50,7 @@ module Spontaneous::Plugins
50
50
 
51
51
  def parent=(parent)
52
52
  @__parent_changed = true
53
+ update_path
53
54
  super
54
55
  end
55
56
 
@@ -91,6 +92,10 @@ module Spontaneous::Plugins
91
92
 
92
93
 
93
94
  def calculate_path
95
+ calculate_path_with_slug(self.slug)
96
+ end
97
+
98
+ def calculate_path_with_slug(slug)
94
99
  if parent.nil?
95
100
  root? ? Spontaneous::SLASH : '' # bad case, no parent but not root
96
101
  else
@@ -100,15 +105,15 @@ module Spontaneous::Plugins
100
105
 
101
106
  def slug=(s)
102
107
  if (new_slug = s.to_url) != self.slug
103
- @__slug_changed = true
108
+ @__slug_changed = self.slug
104
109
  # slugs can be max 255 characters long
105
110
  self[:slug] = new_slug[0..254]
106
111
  self.update_path
107
112
  end
108
113
  end
109
114
 
110
- def check_for_path_changes
111
- if @__slug_changed
115
+ def check_for_path_changes(force = false)
116
+ if @__slug_changed || force
112
117
  @__slug_changed = false
113
118
  children.each do |child|
114
119
  child.propagate_path_changes
@@ -119,7 +124,14 @@ module Spontaneous::Plugins
119
124
  end
120
125
  end
121
126
 
127
+ def force_path_changes
128
+ check_for_path_changes(true)
129
+ end
130
+
122
131
  def propagate_path_changes
132
+ # this happens in the child pages who shouldn't update their modification dates
133
+ # because updates to paths are handled by modifications held on the origin of the path change
134
+ @__ignore_page_modification = true
123
135
  self.update_path
124
136
  self.save
125
137
  children.each do |child|