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.
- data/Gemfile +3 -40
- data/Rakefile +29 -41
- data/Readme.markdown +21 -8
- data/application/css/add_alias_dialogue.css.scss +79 -0
- data/application/css/{v2.scss → core.css.scss} +537 -550
- data/application/css/{definitions.scss → definitions.css.scss} +121 -33
- data/application/css/dialogue.css.scss +409 -0
- data/application/css/{editing.scss → editing.css.scss} +25 -262
- data/application/css/font.css.scss +8 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_flat_10_000000_40x100.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_222222_256x240.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_228ef1_256x240.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ef8c08_256x240.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffd27a_256x240.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffffff_256x240.png +0 -0
- data/application/css/jquery-ui-1.8.21.custom/ui-lightness.css.scss +565 -0
- data/application/css/{login.scss → login.css.scss} +4 -4
- data/application/css/meta.css.scss +331 -0
- data/application/css/{popover.scss → popover.css.scss} +9 -8
- data/application/css/{schema_error.scss → schema_error.css.scss} +4 -4
- data/application/css/spontaneous.css +5 -0
- data/application/css/unsupported.css.scss +42 -0
- data/application/js/add_alias_dialogue.js +72 -10
- data/application/js/ajax.js +50 -16
- data/application/js/compatibility.js +19 -15
- data/application/js/content.js +39 -36
- data/application/js/content_area.js +53 -5
- data/application/js/dialogue.js +17 -0
- data/application/js/dom.js +1 -1
- data/application/js/edit_panel.js +23 -8
- data/application/js/extensions.js +7 -2
- data/application/js/field_preview.js +2 -1
- data/application/js/field_types/date_field.js +11 -8
- data/application/js/field_types/file_field.js +188 -9
- data/application/js/field_types/image_field.js +46 -29
- data/application/js/field_types/markdown_field.js +57 -14
- data/application/js/field_types/select_field.js +72 -0
- data/application/js/field_types/string_field.js +8 -0
- data/application/js/field_types/webvideo_field.js +8 -0
- data/application/js/init.js +1 -7
- data/application/js/location.js +41 -13
- data/application/js/login.js +3 -0
- data/application/js/meta_view/user_admin.js +543 -0
- data/application/js/meta_view.js +1 -0
- data/application/js/metadata.js +20 -0
- data/application/js/page.js +17 -3
- data/application/js/page_browser.js +40 -30
- data/application/js/page_entry.js +4 -0
- data/application/js/panel/root_menu.js +66 -0
- data/application/js/popover.js +2 -2
- data/application/js/preview.js +1 -1
- data/application/js/publish.js +138 -30
- data/application/js/services.js +43 -0
- data/application/js/sharded_upload.js +2 -2
- data/application/js/spontaneous.js +64 -5
- data/application/js/state.js +20 -9
- data/application/js/top_bar.js +273 -150
- data/application/js/types.js +20 -15
- data/application/js/upload.js +1 -2
- data/application/js/user.js +18 -4
- data/application/js/vendor/date.js +104 -0
- data/application/js/vendor/jquery-ui-1.8.18.custom.min.js +356 -0
- data/application/js/views/box_view.js +15 -8
- data/application/js/views/page_piece_view.js +11 -8
- data/application/js/views/page_view.js +21 -3
- data/application/js/views/piece_view.js +19 -10
- data/application/js/views.js +3 -0
- data/application/static/chromelogo-200x52-45c7cbc93be080bea342df5fcda2ef8b.png +0 -0
- data/application/static/dot-texture-9eea29e4ac7ad9a772285252078ec127.png +0 -0
- data/application/static/editing-textarea-resize-s-b5af62365eb7e19ea4beccf7242d508e.png +0 -0
- data/application/static/editing-texture-1-42b06a3439752490988f30f2a06d5e7c.png +0 -0
- data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
- data/application/static/loop_alt1-white-7894b458528e92216196cae26b4c2c96.svg +12 -0
- data/application/static/spontaneous-states-e91ec89db525c62da0105b97cdd781ce.png +0 -0
- data/application/views/index.erb +2 -2
- data/application/views/login.erb +4 -8
- data/application/views/schema_modification_error.html.erb +1 -4
- data/application/views/unsupported.erb +9 -7
- data/bin/spot +1 -1
- data/db/migrations/20110209152710_users_and_groups.rb +10 -10
- data/db/migrations/20120305112647_site_modification_time.rb +11 -0
- data/db/migrations/20120418153903_add_ownership_of_content.rb +14 -0
- data/db/migrations/20120423175416_add_pending_modifications.rb +21 -0
- data/db/migrations/20120525164947_add_field_versions.rb +27 -0
- data/lib/sequel/plugins/scoped_table_name.rb +10 -1
- data/lib/spontaneous/asset/file.rb +25 -0
- data/lib/spontaneous/asset/source.rb +28 -0
- data/lib/spontaneous/asset.rb +75 -0
- data/lib/spontaneous/box.rb +6 -4
- data/lib/spontaneous/capistrano/deploy.rb +47 -0
- data/lib/spontaneous/capistrano/sync.rb +81 -0
- data/lib/spontaneous/capistrano.rb +13 -0
- data/lib/spontaneous/change.rb +60 -68
- data/lib/spontaneous/cli/assets.rb +29 -0
- data/lib/spontaneous/cli/base.rb +0 -48
- data/lib/spontaneous/cli/console.rb +1 -1
- data/lib/spontaneous/cli/server.rb +6 -4
- data/lib/spontaneous/cli/site.rb +28 -17
- data/lib/spontaneous/cli/user.rb +107 -0
- data/lib/spontaneous/cli.rb +100 -4
- data/lib/spontaneous/collections/entry_set.rb +2 -2
- data/lib/spontaneous/collections/field_set.rb +48 -22
- data/lib/spontaneous/collections/prototype_set.rb +20 -13
- data/lib/spontaneous/constants.rb +3 -0
- data/lib/spontaneous/content.rb +22 -5
- data/lib/spontaneous/errors.rb +3 -3
- data/lib/spontaneous/extensions/array.rb +12 -0
- data/lib/spontaneous/extensions/enumerable.rb +30 -0
- data/lib/spontaneous/extensions/nil.rb +3 -1
- data/lib/spontaneous/extensions/string.rb +16 -0
- data/lib/spontaneous/field_types/date_field.rb +45 -2
- data/lib/spontaneous/field_types/field.rb +42 -9
- data/lib/spontaneous/field_types/file_field.rb +68 -0
- data/lib/spontaneous/field_types/image_field.rb +63 -0
- data/lib/spontaneous/field_types/select_field.rb +109 -0
- data/lib/spontaneous/field_types/string_field.rb +6 -1
- data/lib/spontaneous/field_types/webvideo_field.rb +85 -27
- data/lib/spontaneous/field_types.rb +1 -1
- data/lib/spontaneous/field_version.rb +8 -0
- data/lib/spontaneous/generators/page.rb +1 -1
- data/lib/spontaneous/generators/site/Capfile.tt +1 -4
- data/lib/spontaneous/generators/site/Gemfile.tt +13 -6
- data/lib/spontaneous/generators/site/config/deploy.rb.tt +28 -0
- data/lib/spontaneous/generators/site/config/environments/production.rb.tt +7 -2
- data/lib/spontaneous/generators/site.rb +1 -0
- data/lib/spontaneous/json.rb +34 -11
- data/lib/spontaneous/layout.rb +22 -0
- data/lib/spontaneous/media/file.rb +4 -0
- data/lib/spontaneous/output/assets/compression.rb +58 -0
- data/lib/spontaneous/output/assets.rb +32 -0
- data/lib/spontaneous/output/context.rb +179 -0
- data/lib/spontaneous/output/format/html.rb +5 -0
- data/lib/spontaneous/output/format/plain.rb +5 -0
- data/lib/spontaneous/output/format.rb +180 -0
- data/lib/spontaneous/output/helpers/classes_helper.rb +18 -0
- data/lib/spontaneous/{render/helpers/html_helper.rb → output/helpers/conditional_comment_helper.rb} +3 -12
- data/lib/spontaneous/output/helpers/script_helper.rb +73 -0
- data/lib/spontaneous/output/helpers/stylesheet_helper.rb +61 -0
- data/lib/spontaneous/output/helpers.rb +28 -0
- data/lib/spontaneous/output/template/engine.rb +59 -0
- data/lib/spontaneous/output/template/renderer.rb +153 -0
- data/lib/spontaneous/output/template.rb +21 -0
- data/lib/spontaneous/output.rb +163 -0
- data/lib/spontaneous/page.rb +2 -1
- data/lib/spontaneous/paths.rb +6 -1
- data/lib/spontaneous/permissions/access_key.rb +5 -5
- data/lib/spontaneous/permissions/user.rb +81 -35
- data/lib/spontaneous/permissions/user_level.rb +26 -22
- data/lib/spontaneous/plugins/aliases.rb +76 -12
- data/lib/spontaneous/plugins/allowed_types.rb +60 -18
- data/lib/spontaneous/plugins/application/paths.rb +0 -28
- data/lib/spontaneous/plugins/application/system.rb +35 -0
- data/lib/spontaneous/plugins/boxes.rb +4 -0
- data/lib/spontaneous/plugins/content_groups.rb +16 -0
- data/lib/spontaneous/plugins/entries.rb +50 -30
- data/lib/spontaneous/plugins/fields.rb +15 -0
- data/lib/spontaneous/plugins/layouts.rb +8 -2
- data/lib/spontaneous/plugins/modifications.rb +228 -0
- data/lib/spontaneous/plugins/page/formats.rb +67 -42
- data/lib/spontaneous/plugins/page/request.rb +10 -0
- data/lib/spontaneous/plugins/page/site_timestamps.rb +28 -0
- data/lib/spontaneous/plugins/paths.rb +15 -3
- data/lib/spontaneous/plugins/publishing.rb +124 -45
- data/lib/spontaneous/plugins/render.rb +13 -8
- data/lib/spontaneous/plugins/schema_hierarchy.rb +18 -6
- data/lib/spontaneous/plugins/site/helpers.rb +53 -0
- data/lib/spontaneous/plugins/site/hooks.rb +50 -0
- data/lib/spontaneous/plugins/site/map.rb +1 -1
- data/lib/spontaneous/plugins/site/paths.rb +13 -0
- data/lib/spontaneous/plugins/site/publishing.rb +6 -2
- data/lib/spontaneous/plugins/site/{revisions.rb → state.rb} +5 -1
- data/lib/spontaneous/plugins/site/storage.rb +4 -0
- data/lib/spontaneous/plugins/site/url.rb +15 -0
- data/lib/spontaneous/plugins/site_map.rb +13 -3
- data/lib/spontaneous/plugins/styles.rb +5 -1
- data/lib/spontaneous/plugins/visibility.rb +39 -12
- data/lib/spontaneous/prototypes/box_prototype.rb +4 -0
- data/lib/spontaneous/prototypes/field_prototype.rb +15 -10
- data/lib/spontaneous/publishing/event_client.rb +46 -0
- data/lib/spontaneous/publishing/immediate.rb +81 -44
- data/lib/spontaneous/publishing/simultaneous.rb +23 -6
- data/lib/spontaneous/publishing.rb +4 -3
- data/lib/spontaneous/rack/around_back.rb +1 -5
- data/lib/spontaneous/rack/around_front.rb +4 -4
- data/lib/spontaneous/rack/around_preview.rb +4 -3
- data/lib/spontaneous/rack/assets.rb +81 -54
- data/lib/spontaneous/rack/authentication.rb +0 -1
- data/lib/spontaneous/rack/back.rb +160 -72
- data/lib/spontaneous/rack/cookie_authentication.rb +2 -2
- data/lib/spontaneous/rack/css.rb +18 -15
- data/lib/spontaneous/rack/event_source.rb +9 -21
- data/lib/spontaneous/rack/fiber_pool.rb +26 -0
- data/lib/spontaneous/rack/front.rb +12 -4
- data/lib/spontaneous/rack/helpers.rb +35 -13
- data/lib/spontaneous/rack/js.rb +41 -0
- data/lib/spontaneous/rack/public.rb +34 -44
- data/lib/spontaneous/rack/sse.rb +18 -0
- data/lib/spontaneous/rack/static.rb +3 -0
- data/lib/spontaneous/rack/user_admin.rb +100 -0
- data/lib/spontaneous/rack/user_helpers.rb +1 -1
- data/lib/spontaneous/rack.rb +6 -2
- data/lib/spontaneous/schema.rb +31 -4
- data/lib/spontaneous/search/index.rb +19 -3
- data/lib/spontaneous/search/results.rb +1 -1
- data/lib/spontaneous/sequel.rb +17 -0
- data/lib/spontaneous/site.rb +11 -4
- data/lib/spontaneous/state.rb +11 -0
- data/lib/spontaneous/storage/cloud.rb +4 -0
- data/lib/spontaneous/storage/local.rb +11 -0
- data/lib/spontaneous/style.rb +2 -2
- data/lib/spontaneous/tasks/database.rake +21 -22
- data/lib/spontaneous/utils/database/mysql_dumper.rb +4 -0
- data/lib/spontaneous/utils/database/postgres_dumper.rb +78 -0
- data/lib/spontaneous/utils/database.rb +6 -3
- data/lib/spontaneous/utils/smart_quotes.rb +499 -0
- data/lib/spontaneous/utils/smush_it.rb +66 -0
- data/lib/spontaneous/utils.rb +3 -1
- data/lib/spontaneous/version.rb +2 -2
- data/lib/spontaneous.rb +25 -29
- data/spontaneous.gemspec +186 -106
- data/test/experimental/test_features.rb +1 -1
- data/test/fixtures/asset_pipeline/application/css/basic.css.scss +4 -0
- data/test/fixtures/asset_pipeline/application/css/complex.css.scss.erb +6 -0
- data/test/fixtures/asset_pipeline/application/css/simple.css +3 -0
- data/test/fixtures/asset_pipeline/application/css/spontaneous.css +7 -0
- data/test/fixtures/asset_pipeline/application/css/subdir/complex.css.scss.erb +6 -0
- data/test/fixtures/asset_pipeline/application/css/subdir/library.css.scss +1 -0
- data/test/fixtures/asset_pipeline/application/css/subdir/simple.css +3 -0
- data/test/fixtures/asset_pipeline/application/js/basic.js.coffee +1 -0
- data/test/fixtures/asset_pipeline/application/js/complex.js.coffee.erb +1 -0
- data/test/fixtures/asset_pipeline/application/js/login.js +1 -0
- data/test/fixtures/asset_pipeline/application/js/require.js +1 -0
- data/test/fixtures/asset_pipeline/application/js/simple.js +1 -0
- data/test/fixtures/asset_pipeline/application/js/spontaneous.js +5 -0
- data/test/fixtures/asset_pipeline/application/js/subdir/complex.js.coffee.erb +1 -0
- data/test/fixtures/asset_pipeline/application/js/subdir/library.js.coffee +1 -0
- data/test/fixtures/asset_pipeline/application/js/subdir/simple.js +1 -0
- data/test/fixtures/asset_pipeline/application/js/vendor/jquery.js +1 -0
- data/test/fixtures/asset_pipeline/application/static/dot-texture.png +0 -0
- data/test/fixtures/asset_pipeline/application/static/subdir/px.gif +0 -0
- data/test/fixtures/assets/public1/css/a.scss +1 -0
- data/test/fixtures/assets/public1/js/a.js +1 -0
- data/test/fixtures/assets/public1/js/m.coffee +1 -0
- data/test/fixtures/assets/public2/css/b.scss +1 -0
- data/test/fixtures/assets/public2/css/c.css +1 -0
- data/test/fixtures/assets/public2/js/b.js +1 -0
- data/test/fixtures/assets/public2/js/c.js +1 -0
- data/test/fixtures/assets/public2/js/n.coffee +1 -0
- data/test/fixtures/back/config/user_levels.yml +3 -0
- data/test/fixtures/back/public/js/coffeescript.coffee +1 -0
- data/test/fixtures/back/templates/layouts/standard.css.cut +1 -0
- data/test/fixtures/back/templates/layouts/standard.js.cut +1 -0
- data/test/fixtures/example_application/config/database.yml +4 -4
- data/test/fixtures/helpers/templates/layouts/standard.html.cut +1 -0
- data/test/fixtures/helpers/templates/layouts/standard.mobile.cut +1 -0
- data/test/fixtures/images/vimlogo.pdf +0 -0
- data/test/fixtures/outputs/templates/layouts/standard.atom.cut +1 -0
- data/test/fixtures/permissions/config/user_levels.yml +6 -3
- data/test/fixtures/serialisation/class_hash.yaml.erb +1 -0
- data/test/fixtures/serialisation/root_hash.yaml.erb +2 -2
- data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
- data/test/fixtures/templates/extended/main.html.cut +5 -5
- data/test/fixtures/templates/extended/parent.html.cut +8 -8
- data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -1
- data/test/fixtures/templates/extended/with_includes.html.cut +6 -6
- data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +6 -7
- data/test/fixtures/templates/layouts/entries.html.cut +4 -4
- data/test/fixtures/templates/layouts/standard.html.cut +1 -0
- data/test/fixtures/templates/layouts/variables.html.cut +1 -1
- data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -1
- data/test/fixtures/templates/publishing/templates/layouts/static.rtf.cut +1 -0
- data/test/fixtures/templates/template_class/complex_template.html.cut +2 -2
- data/test/fixtures/templates/template_class/complex_template.pdf.cut +2 -2
- data/test/fixtures/templates/template_class/default_template_style.html.cut +1 -1
- data/test/fixtures/templates/template_class/images_with_template.html.cut +2 -2
- data/test/fixtures/templates/template_class/slots_template.html.cut +2 -2
- data/test/fixtures/templates/template_class/slots_template.pdf.cut +2 -2
- data/test/fixtures/user_manager/config/user_levels.yml +9 -0
- data/test/functional/test_application.rb +7 -7
- data/test/functional/test_back.rb +352 -97
- data/test/functional/test_front.rb +71 -20
- data/test/functional/test_user_manager.rb +284 -0
- data/test/javascript/env.js +13505 -0
- data/test/javascript/test_markdown.rb +43 -3
- data/test/support/custom_matchers.rb +3 -2
- data/test/test_helper.rb +50 -9
- data/test/test_javascript.rb +13 -13
- data/test/ui_helper.rb +1 -1
- data/test/unit/test_alias.rb +79 -8
- data/test/unit/test_asset_bundler.rb +220 -0
- data/test/unit/test_assets.rb +213 -0
- data/test/unit/test_async.rb +55 -0
- data/test/unit/test_authentication.rb +52 -39
- data/test/unit/test_boxes.rb +20 -15
- data/test/unit/test_changesets.rb +261 -0
- data/test/unit/test_content.rb +73 -33
- data/test/unit/test_content_inheritance.rb +18 -18
- data/test/unit/test_extensions.rb +26 -0
- data/test/unit/test_fields.rb +303 -16
- data/test/unit/test_formats.rb +267 -34
- data/test/unit/test_helpers.rb +79 -2
- data/test/unit/test_images.rb +10 -0
- data/test/unit/test_layouts.rb +21 -13
- data/test/unit/test_modifications.rb +648 -0
- data/test/unit/test_page.rb +6 -2
- data/test/unit/test_permissions.rb +101 -27
- data/test/unit/test_piece.rb +4 -4
- data/test/unit/test_plugins.rb +3 -2
- data/test/unit/test_publishing.rb +332 -0
- data/test/unit/test_render.rb +118 -67
- data/test/unit/test_revisions.rb +546 -0
- data/test/unit/test_schema.rb +83 -1
- data/test/unit/test_search.rb +59 -0
- data/test/unit/test_serialisation.rb +2 -47
- data/test/unit/test_site.rb +217 -108
- data/test/unit/test_storage.rb +26 -0
- data/test/unit/test_structure.rb +2 -2
- data/test/unit/test_styles.rb +90 -75
- data/test/unit/test_table_scoping.rb +21 -17
- data/test/unit/test_templates.rb +75 -69
- data/test/{slow → unit}/test_visibility.rb +78 -22
- metadata +528 -221
- data/application/css/add_alias_dialogue.scss +0 -27
- data/application/css/min/14c2a35812c443001b15d8b12a4780f88c678035.css +0 -1
- data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +0 -1
- data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +0 -1
- data/application/css/spontaneous.scss +0 -111
- data/application/css/unsupported.scss +0 -16
- data/application/css/variables.scss +0 -80
- data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +0 -3
- data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +0 -2
- data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +0 -3
- data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +0 -2
- data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +0 -90
- data/application/static/diagonal-texture.png +0 -0
- data/application/static/editing-0-noise.png +0 -0
- data/application/static/editing-1-noise.png +0 -0
- data/application/static/editing-texture-1.png +0 -0
- data/application/static/editing-texture.png +0 -0
- data/application/static/editing-toolbar-shadow-bottom.png +0 -0
- data/application/static/editing-toolbar-shadow-top.png +0 -0
- data/application/static/inner-glow.png +0 -0
- data/application/static/item-buttons-highlight.png +0 -0
- data/application/static/item-buttons.png +0 -0
- data/application/static/paper-texture-dark.png +0 -0
- data/application/static/plus_alt.svg +0 -8
- data/application/static/select-arrow-root.png +0 -0
- data/application/static/slot-up-arrow.png +0 -0
- data/application/static/spontaneous.png +0 -0
- data/lib/cutaneous/context_helper.rb +0 -187
- data/lib/cutaneous/preview_context.rb +0 -32
- data/lib/cutaneous/preview_renderer.rb +0 -10
- data/lib/cutaneous/publish_context.rb +0 -10
- data/lib/cutaneous/publish_renderer.rb +0 -14
- data/lib/cutaneous/publish_template.rb +0 -62
- data/lib/cutaneous/publish_token_parser.rb +0 -8
- data/lib/cutaneous/renderer.rb +0 -124
- data/lib/cutaneous/request_context.rb +0 -9
- data/lib/cutaneous/request_renderer.rb +0 -15
- data/lib/cutaneous/request_template.rb +0 -11
- data/lib/cutaneous/request_token_parser.rb +0 -9
- data/lib/cutaneous/token_parser.rb +0 -125
- data/lib/cutaneous.rb +0 -48
- data/lib/spontaneous/render/context_base.rb +0 -143
- data/lib/spontaneous/render/development_renderer.rb +0 -14
- data/lib/spontaneous/render/engine.rb +0 -19
- data/lib/spontaneous/render/format/html.rb +0 -5
- data/lib/spontaneous/render/format.rb +0 -75
- data/lib/spontaneous/render/helpers/script_helper.rb +0 -17
- data/lib/spontaneous/render/helpers/stylesheet_helper.rb +0 -16
- data/lib/spontaneous/render/helpers.rb +0 -14
- data/lib/spontaneous/render/preview_context.rb +0 -8
- data/lib/spontaneous/render/preview_renderer.rb +0 -24
- data/lib/spontaneous/render/publish_context.rb +0 -22
- data/lib/spontaneous/render/published_renderer.rb +0 -53
- data/lib/spontaneous/render/publishing_renderer.rb +0 -16
- data/lib/spontaneous/render/render_cache.rb +0 -26
- data/lib/spontaneous/render/renderer.rb +0 -50
- data/lib/spontaneous/render/request_context.rb +0 -8
- data/lib/spontaneous/render.rb +0 -214
- data/test/experimental/test_cutaneous.rb +0 -309
- data/test/fixtures/application/css/test.less +0 -5
- data/test/slow/test_publishing.rb +0 -1006
- /data/application/css/{developer.scss → developer.css.scss} +0 -0
- /data/application/js/vendor/{jquery-1.7.1.min.js → jquery.js} +0 -0
- /data/application/static/{location-arrow.png → location-arrow-c1c1d3ca472481c61a0a5f8cb289d743.png} +0 -0
- /data/application/static/{missing.png → missing-911ce6dbd9f4602e0f3fbcd7e78846a2.png} +0 -0
- /data/application/static/{orange-down-arrow.png → orange-down-arrow-395ae1929e8662b2ff0977daf12c35bb.png} +0 -0
- /data/application/static/{page-browser-next.png → page-browser-next-ce781a242c23b980b99b9db7abc20b05.png} +0 -0
- /data/application/static/{plus-box.png → plus-box-dcde74a1e496f68298c9b443caa1c5d5.png} +0 -0
- /data/application/static/{select-arrow.png → select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png} +0 -0
- /data/application/static/{slot-down-arrow.png → slot-down-arrow-59ad5f5ee5b52a7ebd00bca4b3104194.png} +0 -0
- /data/application/static/{splash.png → splash-65b493a714df9b8b3ab170103401b53d.png} +0 -0
- /data/application/static/{spot.png → spot-71fab1d2f065034f5fc15e7bea2ad36c.png} +0 -0
- /data/application/static/{spot.svg → spot-8505041082d8d3bbe8d34c29dddb3b7d.svg} +0 -0
- /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
|
-
|
|
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,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
74
|
-
return
|
|
75
|
-
|
|
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
|
|
82
|
-
@
|
|
81
|
+
def all_contents
|
|
82
|
+
@all_contents ||= Spontaneous::Collections::EntrySet.new(self, entry_store)
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def
|
|
86
|
-
@
|
|
85
|
+
def visible_contents
|
|
86
|
+
@visible_contents ||= all_contents.visible!
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
protected(:
|
|
89
|
+
protected(:all_contents, :visible_contents)
|
|
90
90
|
|
|
91
91
|
def reload
|
|
92
|
-
@
|
|
92
|
+
@all_contents = @visible_contents = nil
|
|
93
93
|
super
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
def first
|
|
98
|
-
|
|
98
|
+
contents.first
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
def last
|
|
102
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
11
|
-
return
|
|
12
|
-
|
|
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
|
|
16
|
-
@
|
|
15
|
+
def output_map
|
|
16
|
+
@outputs ||= supertype_outputs
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def
|
|
20
|
-
|
|
19
|
+
def output_list
|
|
20
|
+
output_map.values
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
51
|
-
supertype? && supertype.respond_to?(:
|
|
46
|
+
def supertype_outputs
|
|
47
|
+
supertype? && supertype.respond_to?(:outputs) ? supertype.output_map.dup : { :html => standard_output }
|
|
52
48
|
end
|
|
53
49
|
|
|
54
|
-
def
|
|
55
|
-
|
|
50
|
+
def standard_output
|
|
51
|
+
define_output(:html)
|
|
56
52
|
end
|
|
57
53
|
|
|
58
|
-
def
|
|
59
|
-
|
|
54
|
+
def default_output
|
|
55
|
+
output_list.first
|
|
60
56
|
end
|
|
61
57
|
|
|
62
58
|
def provides_format?(format)
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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
|
|
77
|
-
self.class.
|
|
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
|
|
81
|
-
self.class.
|
|
94
|
+
def provides_output?(format)
|
|
95
|
+
self.class.provides_output?(format)
|
|
82
96
|
end
|
|
83
97
|
|
|
84
|
-
def
|
|
85
|
-
|
|
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 =
|
|
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|
|