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
@@ -75,48 +75,55 @@ module Spontaneous::Plugins
75
75
  mark_published = Proc.new do |dataset|
76
76
  dataset.update(:last_published_at => Sequel.datetime_class.now)
77
77
  end
78
+
78
79
  first_published = published = nil
79
80
 
80
- with_editable do
81
- first_published = self.filter(:first_published_at => nil)
82
- published = self.filter
81
+ db.transaction do
82
+ with_editable do
83
+ first_published = self.filter(:first_published_at => nil)
84
+ published = self.filter
85
+
86
+ must_publish_all = (content.nil? || (!revision_exists?(revision-1)) || \
87
+ (content.is_a?(Array) && content.empty?))
83
88
 
84
- must_publish_all = (content.nil? || (!revision_exists?(revision-1)) || \
85
- (content.is_a?(Array) && content.empty?))
89
+ if must_publish_all
90
+ create_revision(revision)
91
+ else
92
+ content = content.map do |c|
93
+ c.is_a?(Spontaneous::Content) ? c.reload : Spontaneous::Content.first(:id => c)
94
+ end.compact
86
95
 
87
- if must_publish_all
88
- create_revision(revision)
89
- else
90
- content = content.map do |c|
91
- c.is_a?(Spontaneous::Content) ? c.reload : Spontaneous::Content[c]
92
- end.compact
96
+ # pages should be published in depth order because its possible to be publishing a child of
97
+ # a page that's never been published
98
+ content.sort! { |c1, c2| c1.depth <=> c2.depth }
93
99
 
94
- first_published = first_published.filter(:id => content.map { |c| c.id })
95
- published = published.filter(:id => content.map { |c| c.id })
100
+ first_published = first_published.filter(:id => content.map { |c| c.id })
101
+ published = published.filter(:id => content.map { |c| c.id })
96
102
 
97
- create_revision(revision, revision-1)
98
- content.each do |c|
99
- c.sync_to_revision(revision)
103
+ create_revision(revision, revision-1)
104
+ content.each do |c|
105
+ c.sync_to_revision(revision, true)
106
+ end
100
107
  end
101
- end
102
108
 
103
- # run any passed code and if it fails revert the publish step
104
- if block_given?
105
- begin
106
- with_revision(revision) { yield }
107
- rescue Exception => e
108
- delete_revision(revision)
109
- raise e
109
+ # run any passed code and if it fails revert the publish step
110
+ if block_given?
111
+ begin
112
+ with_revision(revision) { yield }
113
+ rescue Exception => e
114
+ delete_revision(revision)
115
+ raise e
116
+ end
110
117
  end
111
- end
112
118
 
113
- with_editable do
114
- mark_first_published[first_published]
115
- mark_published[published]
116
- end
117
- with_revision(revision) do
118
- mark_first_published[first_published]
119
- mark_published[published]
119
+ with_editable do
120
+ mark_first_published[first_published]
121
+ mark_published[published]
122
+ end
123
+ with_revision(revision) do
124
+ mark_first_published[first_published]
125
+ mark_published[published]
126
+ end
120
127
  end
121
128
  end
122
129
  end
@@ -139,7 +146,7 @@ module Spontaneous::Plugins
139
146
 
140
147
  def delete_revision(revision)
141
148
  return if revision.nil?
142
- database.drop_table(revision_table(revision)) if revision_exists?(revision)
149
+ database.drop_table?(revision_table(revision))
143
150
  end
144
151
 
145
152
  def delete_all_revisions!
@@ -151,6 +158,11 @@ module Spontaneous::Plugins
151
158
 
152
159
  # InstanceMethods
153
160
 
161
+ def after_create
162
+ super
163
+ page.modified!(page?) if page
164
+ end
165
+
154
166
  def after_update
155
167
  super
156
168
  page.modified!(page?) if page
@@ -160,14 +172,8 @@ module Spontaneous::Plugins
160
172
  unless caller_is_page
161
173
  self.model.where(:id => self.id).update(:modified_at => Sequel.datetime_class.now)
162
174
  end
163
- push_page_change
164
175
  end
165
176
 
166
- def push_page_change
167
- Spontaneous::Change.push(self) if page?
168
- end
169
-
170
-
171
177
  def with_revision(revision, &block)
172
178
  self.class.with_revision(revision, &block)
173
179
  end
@@ -175,37 +181,110 @@ module Spontaneous::Plugins
175
181
  self.class.with_editable(&block)
176
182
  end
177
183
 
178
- def sync_to_revision(revision, origin=true)
184
+ def never_published?
185
+ first_published_at.nil?
186
+ end
187
+
188
+ def before_publish(revision); end
189
+ def after_publish(revision); end
190
+
191
+ def sync_to_revision(revision, origin=false)
179
192
  # 'publish' is a lock to make sure the duplication doesn't cross
180
193
  # page boundaries unless that's necessary (such as in the case
181
194
  # of a page addition)
182
195
  publish = origin || !self.page?
196
+ first_publish = false
183
197
 
184
198
  with_revision(revision) do
185
- published_copy = Spontaneous::Content[self.id]
199
+ published_copy = Spontaneous::Content.first(:id => self.id)
186
200
  if published_copy
187
201
  if publish and published_copy.entry_store
188
202
  pieces_to_delete = published_copy.entry_store - self.entry_store
189
203
  pieces_to_delete.each do |entry|
190
- if c = Spontaneous::Content[entry[0]]
191
- c.destroy(false)
204
+ if c = Spontaneous::Content.first(:id => entry[0])
205
+ c.destroy(false) rescue ::Sequel::NoExistingObject
192
206
  end
193
207
  end
194
208
  end
195
209
  else # missing content (so force a publish)
196
- Spontaneous::Content.insert({:id => self.id})
210
+ Spontaneous::Content.insert({:id => self.id, :type_sid => values[:type_sid]})
197
211
  publish = true
212
+ first_publish = true
198
213
  end
199
214
 
200
215
  if publish
216
+ self.before_publish(revision)
201
217
  with_editable do
202
218
  self.pieces.each do |entry|
203
219
  entry.sync_to_revision(revision, false)
204
220
  end
205
221
  end
206
- Spontaneous::Content.where(:id => self.id).update(self.values)
222
+
223
+ if self.page?
224
+ sync_children_to_revision(revision)
225
+ end
226
+
227
+ Spontaneous::Content.where(:id => self.id).update(values)
228
+
229
+ published_values = {}
230
+ # ancestors can have un-published changes to their paths so we can't just directly publish the current path.
231
+ # Instead we re-calculate our path using the published version of the ancestor's path & our (potentially) updated slug.
232
+ if self.page?
233
+ published = self.class.first :id => self.id
234
+ published_values[:path] = published.calculate_path_with_slug(values[:slug])
235
+ end
236
+
237
+ # need to calculate the correct visibility for published items. I can't just take this from the editable
238
+ # content because up-tree visibility changes might not have been published. This kinda mess is why individual
239
+ # page publishing is a pain.
240
+ # However, this only applies if the item's visibility is dependent on some up-tree state. So
241
+ # if hidden_origin is empty (which means we have a separately calculated visibility) we want
242
+ # to take visibility from our own value.
243
+
244
+ published_values[:hidden] = self.recalculated_hidden unless self.hidden_origin.blank?
245
+
246
+ unless published_values.empty?
247
+ Spontaneous::Content.where(:id => self.id).update(published_values)
248
+ end
249
+
250
+ # Pages that haven't been published before can be published independently of their parents.
251
+ # In that case we need to insert an entry for them. We can't guarantee that the published
252
+ # parent has the same entries
253
+ insert_entry_for_new_page(revision) if first_publish && page?
254
+ self.after_publish(revision)
255
+ end
256
+ end
257
+ end
258
+
259
+ def sync_children_to_revision(revision)
260
+ published_children = with_revision(revision) { S::Content.filter(:parent_id => self.id) }
261
+ published_children.each do |child_page|
262
+ deleted = with_editable { S::Content.select(:id).first(:id => child_page.id).nil? }
263
+ if deleted
264
+ with_revision(revision) do
265
+ child_page.destroy
266
+ end
207
267
  end
208
268
  end
209
269
  end
270
+
271
+ # Finds an entry in the parent page and duplicates it to the parent
272
+ # of the newly published page. Positions are not exact as other child pages might not have
273
+ # been published.
274
+ def insert_entry_for_new_page(revision)
275
+ detect_entry = proc { |e| e[0] == self.id }
276
+
277
+ parent_entry_store = with_editable { self.parent.entry_store.dup }
278
+ entry = parent_entry_store.find(&detect_entry)
279
+ index = parent_entry_store.index(&detect_entry)
280
+ published_parent = Spontaneous::Content.first :id => parent_id
281
+
282
+ published_parent.entry_store ||= []
283
+
284
+ unless published_parent.entry_store.find(&detect_entry)
285
+ published_parent.entry_store.insert(index, entry).compact!
286
+ end
287
+ published_parent.save
288
+ end
210
289
  end
211
290
  end
@@ -4,13 +4,18 @@ module Spontaneous::Plugins
4
4
  module Render
5
5
  extend ActiveSupport::Concern
6
6
 
7
- # InstanceMethods
8
- def render(format=:html, params={}, *args)
9
- if format.is_a?(Hash)
10
- params = format
11
- format = :html
12
- end
13
- Spontaneous::Render.render(self, format, params, *args)
7
+ def output(format = :html)
8
+ return page.output(format, self) if page
9
+ raise "Cannot render content without enclosing page"
14
10
  end
15
- end # Render
11
+
12
+ def render(format = :html, params = {}, *args)
13
+ params, format = format, :html if format.is_a?(Hash)
14
+ output(format).render(params, *args)
15
+ end
16
+
17
+ def render_using(renderer, format = :html, params = {}, *args)
18
+ output(format).render_using(renderer, params, *args)
19
+ end
20
+ end
16
21
  end
@@ -5,37 +5,49 @@ module Spontaneous::Plugins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- def schema_validate
8
+ def schema_validate(schema)
9
9
  if schema_id.nil?
10
- Spontaneous.schema.missing_id!(:type, self)
10
+ schema.missing_id!(:type, self)
11
11
  else
12
12
  # only need to check internal consistency if class already existed
13
13
  fields.each do |field|
14
14
  if field.owner == self and field.schema_id.nil?
15
- Spontaneous.schema.missing_id!(:field, field)
15
+ schema.missing_id!(:field, field)
16
16
  end
17
17
  end
18
18
  # boxes don't have boxes
19
19
  if respond_to?(:boxes)
20
20
  boxes.each do |box|
21
21
  if box.owner == self and box.schema_id.nil?
22
- Spontaneous.schema.missing_id!(:box, box)
22
+ schema.missing_id!(:box, box)
23
23
  end
24
24
  end
25
25
  end
26
26
 
27
27
  styles.each do |style|
28
28
  if style.owner == self and style.schema_id.nil?
29
- Spontaneous.schema.missing_id!(:style, style)
29
+ schema.missing_id!(:style, style)
30
30
  end
31
31
  end
32
32
  if respond_to?(:layouts)
33
33
  layouts.each do |layout|
34
34
  if layout.owner == self and layout.schema_id.nil?
35
- Spontaneous.schema.missing_id!(:layout, layout)
35
+ schema.missing_id!(:layout, layout)
36
36
  end
37
37
  end
38
38
  end
39
+ # Group memberships can get out of sync if a class is modified
40
+ # but their details are transient & not stored in the map so
41
+ # we don't need to raise any errors and can fix things auto-
42
+ # matically.
43
+ if respond_to?(:group_memberships)
44
+ type_memberships = group_memberships || []
45
+ schema_memberships = schema.group_memberships(self)
46
+ if type_memberships != schema_memberships
47
+ schema.remove_group_members(self)
48
+ schema.add_group_member(self, type_memberships)
49
+ end
50
+ end
39
51
  end
40
52
  end
41
53
 
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+
3
+
4
+ module Spontaneous::Plugins::Site
5
+ module Helpers
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def helper(*formats, &block)
10
+ helper_module = Module.new(&block)
11
+ register_helper(helper_module, *formats.flatten)
12
+ helper_module
13
+ end
14
+
15
+ # Private: Generates a module including all helper methods for the requested format(s)
16
+ def context(*formats)
17
+ formats = [:*].concat formats.flatten.map { |f| f.to_sym }
18
+ helper_module = Module.new
19
+ formats.each do |format|
20
+ Spontaneous::Output::Helpers.registered_helpers[format].each do |mod|
21
+ helper_module.send :include, mod
22
+ helper_module.send :extend, mod
23
+ end
24
+ Spontaneous::Site.registered_helpers[format].each do |mod|
25
+ helper_module.send :include, mod
26
+ helper_module.send :extend, mod
27
+ end
28
+ end
29
+ helper_module
30
+ end
31
+
32
+ def register_helper(helper_module, *formats)
33
+ site = instance
34
+ if formats.empty?
35
+ site.registered_helpers[:*] << helper_module
36
+ else
37
+ formats.each do |format|
38
+ site.registered_helpers[format.to_sym] << helper_module
39
+ end
40
+ end
41
+ end
42
+
43
+ def registered_helpers
44
+ instance.registered_helpers
45
+ end
46
+ end
47
+
48
+ def registered_helpers
49
+ @registered_helpers ||= Hash.new { |hash, key| hash[key] = [] }
50
+ end
51
+ end # Helpers
52
+ end
53
+
@@ -0,0 +1,50 @@
1
+
2
+ module Spontaneous::Plugins::Site
3
+ module Hooks
4
+ extend ActiveSupport::Concern
5
+
6
+ HOOKS = [:after_publish]
7
+
8
+ module ClassMethods
9
+ HOOKS.each do |hook|
10
+ # def after_publish(&block)
11
+ # instance.after_publish(&block)
12
+ # end
13
+ class_eval(<<-RB)
14
+ def #{hook}(&block)
15
+ instance.#{hook}(&block)
16
+ end
17
+ RB
18
+ end
19
+
20
+ def trigger(event_name, *args)
21
+ instance.trigger(event_name, *args)
22
+ end
23
+ end
24
+
25
+ HOOKS.each do |hook|
26
+ # def after_publish(&block)
27
+ # add_trigger(:after_publish, block)
28
+ # end
29
+ class_eval(<<-RB)
30
+ def #{hook}(&block)
31
+ add_trigger(:#{hook}, block)
32
+ end
33
+ RB
34
+ end
35
+
36
+ def triggers
37
+ @triggers ||= Hash.new { |hash, key| hash[key] = [] }
38
+ end
39
+
40
+ def add_trigger(trigger_name, block)
41
+ triggers[trigger_name] << block
42
+ end
43
+
44
+ def trigger(event_name, *args)
45
+ triggers[event_name].each do |block|
46
+ block.call(*args)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -10,7 +10,7 @@ module Spontaneous::Plugins::Site
10
10
  if root_id.nil?
11
11
  Spontaneous::Page.root
12
12
  else
13
- Spontaneous::Content[root_id]
13
+ Spontaneous::Content.first :id => root_id
14
14
  end
15
15
  return nil unless page
16
16
  page.map_entry
@@ -0,0 +1,13 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Plugins::Site
4
+ module Paths
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def paths(group)
9
+ instance.facets.flat_map { |facet| facet.paths.expanded(group) }
10
+ end
11
+ end # ClassMethods
12
+ end # Paths
13
+ end
@@ -27,14 +27,18 @@ module Spontaneous::Plugins::Site
27
27
  end
28
28
  end
29
29
 
30
- def publish_changes(change_list=nil)
31
- publishing_method.new(self.revision).publish_changes(change_list)
30
+ def publish_pages(page_list=nil)
31
+ publishing_method.new(self.revision).publish_pages(page_list)
32
32
  end
33
33
 
34
34
  def publish_all
35
35
  publishing_method.new(self.revision).publish_all
36
36
  end
37
37
 
38
+ def rerender
39
+ publishing_method.new(self.published_revision).rerender_revision
40
+ end
41
+
38
42
  def publishing_status
39
43
  status = rest = nil
40
44
  # if r = S::Site.pending_revision
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Spontaneous::Plugins::Site
4
- module Revisions
4
+ module State
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
@@ -21,6 +21,10 @@ module Spontaneous::Plugins::Site
21
21
  Spontaneous::State.pending_revision
22
22
  end
23
23
 
24
+ def modified_at
25
+ Spontaneous::State.modified_at
26
+ end
27
+
24
28
  def revision_root(*path)
25
29
  instance.revision_root(*path)
26
30
  end
@@ -28,6 +28,10 @@ module Spontaneous::Plugins::Site
28
28
  def local_storage
29
29
  instance.local_storage
30
30
  end
31
+
32
+ def default_storage
33
+ instance.default_storage
34
+ end
31
35
  end # ClassMethods
32
36
 
33
37
  def storage(mimetype = nil)
@@ -0,0 +1,15 @@
1
+ module Spontaneous::Plugins::Site
2
+ module URL
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def public_url(path = "/")
7
+ instance.public_url(path)
8
+ end
9
+ end
10
+
11
+ def public_url(path = "/")
12
+ "http://%s%s" % [ config.site_domain, path ]
13
+ end
14
+ end
15
+ end
@@ -11,11 +11,21 @@ module Spontaneous::Plugins
11
11
 
12
12
  def map_entry
13
13
  shallow_map_entry.merge({
14
- :children => self.children.map {|c| c.shallow_map_entry },
15
- :generation => self.generation.map {|c| c.shallow_map_entry },
16
- :ancestors => self.ancestors.map {|c| c.shallow_map_entry },
14
+ :children => grouped_page_list(self.children),
15
+ :generation => grouped_page_list(self.generation),
16
+ :ancestors => self.ancestors.map {|c| c.shallow_map_entry }
17
17
  })
18
18
  end
19
+
20
+ def grouped_page_list(pages)
21
+ Hash.new { |hash, key| hash[key] = [] }.tap { |map|
22
+ pages.each do |p|
23
+ return {:Root => [p.shallow_map_entry]} if p.container.nil? # guard for site root
24
+ map[p.container._prototype.title] << p.shallow_map_entry
25
+ end
26
+ }
27
+ end
28
+
19
29
  def shallow_map_entry
20
30
  {
21
31
  :id => id,
@@ -64,7 +64,11 @@ module Spontaneous::Plugins
64
64
  # InstanceMethods
65
65
 
66
66
  def style=(style)
67
- self.style_sid = style_to_schema_id(style)
67
+ self[:style_sid] = style_to_schema_id(style).to_s
68
+ end
69
+
70
+ def style_sid
71
+ self[:style_sid]
68
72
  end
69
73
 
70
74
  # converts a symbol or string into a Schema::UID instance
@@ -9,7 +9,7 @@ module Spontaneous::Plugins
9
9
 
10
10
  def _set_visible_dataset!
11
11
  @_saved_dataset ||= self.dataset
12
- ds = self.dataset.filter(:hidden => false)
12
+ ds = filter_visible self.dataset
13
13
  @dataset = ds
14
14
  # set_dataset clears the row_proc which desroys the STI
15
15
  # self.set_dataset(ds)
@@ -49,18 +49,22 @@ module Spontaneous::Plugins
49
49
  end
50
50
 
51
51
  def visible
52
- self.dataset.filter(:hidden => false)
52
+ filter_visible self.dataset
53
+ end
54
+
55
+ def filter_visible(dataset)
56
+ dataset.filter(:hidden => false)
53
57
  end
54
58
  end # ClassMethods
55
59
 
56
60
  # InstanceMethods
57
61
 
58
62
  def visible?
59
- !self.hidden
63
+ !self.hidden?
60
64
  end
61
65
 
62
66
  def hidden?
63
- self.hidden
67
+ self.hidden || false
64
68
  end
65
69
 
66
70
  def hide!
@@ -92,34 +96,48 @@ module Spontaneous::Plugins
92
96
  set_visible(visible)
93
97
  end
94
98
 
95
-
96
- protected
97
-
98
99
  def set_visible!(state)
99
100
  self.set_visible(state)
100
101
  self.save
101
102
  self
102
103
  end
103
104
 
104
- def set_visible(visible)
105
+ # Private: Used by visibility modifications to force a cascade of visibility
106
+ # state during the publish process.
107
+ def set_visible_with_cascade!(state)
108
+ set_visible(state)
109
+ force_visibility_cascade
110
+ self.save
111
+ self
112
+ end
113
+
114
+ def set_visible(visible, hidden_origin = nil)
105
115
  protect_root_visibility!
106
116
  if self.visible? != visible
107
117
  raise Spontaneous::NotShowable.new(self, hidden_origin) if hidden? && visible && !showable?
108
118
  self[:hidden] = !visible
109
- self[:hidden_origin] = nil
110
- @_visibility_modified = true
119
+ self[:hidden_origin] = hidden_origin
120
+ force_visibility_cascade
111
121
  end
112
122
  end
113
123
 
124
+ def force_visibility_cascade
125
+ @_visibility_modified = true
126
+ end
127
+
114
128
  def after_save
115
129
  super
116
130
  if @_visibility_modified
117
- hide_descendents(self.visible?)
118
- hide_aliases(self.visible?)
131
+ propagate_visibility_state
119
132
  @_visibility_modified = false
120
133
  end
121
134
  end
122
135
 
136
+ def propagate_visibility_state
137
+ hide_descendents(self.visible?)
138
+ hide_aliases(self.visible?)
139
+ end
140
+
123
141
  def hide_aliases(visible)
124
142
  dataset = Spontaneous::Content.filter(:target_id => self.id)
125
143
  origin = visible ? nil : self.id
@@ -149,6 +167,15 @@ module Spontaneous::Plugins
149
167
  # Spontaneous::Content.from(:content___n, :content___p).filter(path_like).filter(:n__page_id => :p__id).set(:n__visible => visible, :n__hidden_origin => origin)
150
168
  end
151
169
 
170
+ def visibility_ancestors
171
+ return [] if visibility_path.blank?
172
+ visibility_path.split(Spontaneous::VISIBILITY_PATH_SEP).map { |id| S::Content[id] }
173
+ end
174
+
175
+ def recalculated_hidden
176
+ visibility_ancestors.any? { |ancestor| ancestor.hidden? }
177
+ end
178
+
152
179
  def protect_root_visibility!
153
180
  if self.is_page? && self.is_root?
154
181
  raise "Root page is not hidable"
@@ -171,6 +171,10 @@ module Spontaneous::Prototypes
171
171
  instance_class.readable_fields(user)
172
172
  end
173
173
 
174
+ def allow(*args)
175
+ instance_class.allow(*args)
176
+ end
177
+
174
178
  def allowed_types(user)
175
179
  if writable?(user)
176
180
  types = []