spontaneous 0.2.0.beta1 → 0.2.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.locat +42 -0
- data/.travis/gemfiles/Gemfile.empty +7 -0
- data/.travis.yml +18 -0
- data/Gemfile +12 -8
- data/LICENSE +1 -1
- data/Rakefile +15 -157
- data/Readme.markdown +1 -1
- data/application/css/core.css.scss +22 -146
- data/application/css/definitions.css.scss +7 -3
- data/application/css/dialogue.css.scss +26 -1
- data/application/css/editing.css.scss +70 -28
- data/application/css/font.css.scss +1 -1
- data/application/css/popover.css.scss +2 -0
- data/application/css/top.css.scss +231 -0
- data/application/js/add_alias_dialogue.js +1 -1
- data/application/js/add_home_dialogue.js +1 -1
- data/application/js/ajax.js +61 -31
- data/application/js/box.js +4 -4
- data/application/js/conflicted_field_dialogue.js +1 -1
- data/application/js/content.js +5 -5
- data/application/js/dom.js +5 -0
- data/application/js/edit_panel.js +1 -0
- data/application/js/editing.js +1 -1
- data/application/js/extensions.js +8 -0
- data/application/js/field/boolean.js +31 -0
- data/application/js/field/file.js +32 -4
- data/application/js/field/image.js +24 -9
- data/application/js/field/markdown.js +87 -59
- data/application/js/field/select.js +1 -1
- data/application/js/field/webvideo.js +6 -1
- data/application/js/init.js +2 -2
- data/application/js/jquery-selection-position.js +130 -0
- data/application/js/location.js +4 -25
- data/application/js/meta_view/user_admin.js +2 -2
- data/application/js/metadata.js +2 -2
- data/application/js/page_browser.js +1 -1
- data/application/js/panel/root_menu.js +0 -1
- data/application/js/popover.js +27 -12
- data/application/js/popover_view.js +20 -4
- data/application/js/preview.js +31 -16
- data/application/js/progress.js +22 -21
- data/application/js/publish.js +18 -7
- data/application/js/sharded_upload.js +9 -6
- data/application/js/spontaneous.js +3 -1
- data/application/js/top_bar.js +264 -173
- data/application/js/upload.js +12 -5
- data/application/js/upload_manager.js +4 -3
- data/application/js/user.js +1 -2
- data/application/js/views/box_view.js +1 -1
- data/application/js/views/page_view.js +16 -5
- data/application/js/views/piece_view.js +5 -4
- data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
- data/application/views/index.erb +6 -14
- data/application/views/login.erb +6 -25
- data/application/views/schema_modification_error.html.erb +3 -7
- data/db/migrations/20130114120000_create_revision_tables.rb +2 -2
- data/db/migrations/20130813111009_increase_path_length.rb +14 -0
- data/gem-public_cert.pem +20 -0
- data/lib/spontaneous/asset/app_compiler.rb +44 -0
- data/lib/spontaneous/asset/environment.rb +225 -0
- data/lib/spontaneous/asset.rb +2 -67
- data/lib/spontaneous/box.rb +0 -1
- data/lib/spontaneous/capistrano/deploy.rb +2 -2
- data/lib/spontaneous/capistrano/sync.rb +1 -1
- data/lib/spontaneous/cli/init.rb +36 -13
- data/lib/spontaneous/cli/server.rb +0 -1
- data/lib/spontaneous/cli/site.rb +2 -1
- data/lib/spontaneous/cli.rb +3 -1
- data/lib/spontaneous/collections/entry_set.rb +4 -12
- data/lib/spontaneous/collections/hash_with_fallback.rb +20 -0
- data/lib/spontaneous/collections/prototype_set.rb +6 -5
- data/lib/spontaneous/crypt.rb +2 -2
- data/lib/spontaneous/data_mapper/content_model/associations.rb +115 -63
- data/lib/spontaneous/data_mapper.rb +1 -1
- data/lib/spontaneous/errors.rb +6 -0
- data/lib/spontaneous/extensions/object_space.rb +6 -0
- data/lib/spontaneous/facet.rb +1 -0
- data/lib/spontaneous/field/base.rb +86 -13
- data/lib/spontaneous/field/boolean.rb +65 -0
- data/lib/spontaneous/field/file.rb +17 -6
- data/lib/spontaneous/field/html.rb +13 -0
- data/lib/spontaneous/field/image/size.rb +76 -0
- data/lib/spontaneous/field/image.rb +99 -414
- data/lib/spontaneous/field/tags.rb +36 -0
- data/lib/spontaneous/field/update.rb +1 -1
- data/lib/spontaneous/field/webvideo/fallback.rb +41 -0
- data/lib/spontaneous/field/webvideo/vimeo.rb +113 -0
- data/lib/spontaneous/field/webvideo/vine.rb +94 -0
- data/lib/spontaneous/field/webvideo/youtube.rb +133 -0
- data/lib/spontaneous/field/webvideo.rb +100 -250
- data/lib/spontaneous/field.rb +1 -1
- data/lib/spontaneous/generators/site/Gemfile.tt +5 -14
- data/lib/spontaneous/generators/site/assets/README.md +20 -0
- data/lib/spontaneous/generators/site/assets/css/site.scss +8 -0
- data/lib/spontaneous/generators/site/assets/js/site.js +6 -0
- data/lib/spontaneous/generators/site/config/deploy.rb.tt +9 -0
- data/lib/spontaneous/generators/site/config/user_levels.yml +14 -3
- data/lib/spontaneous/generators/site/public/README.md +12 -0
- data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +2 -2
- data/lib/spontaneous/generators/site.rb +77 -35
- data/lib/spontaneous/layout.rb +6 -7
- data/lib/spontaneous/loader.rb +21 -13
- data/lib/spontaneous/media/file.rb +22 -9
- data/lib/spontaneous/media/image/attributes.rb +33 -0
- data/lib/spontaneous/media/image/format/gif.rb +4 -0
- data/lib/spontaneous/media/image/format/jpg.rb +17 -0
- data/lib/spontaneous/media/image/format/png.rb +4 -0
- data/lib/spontaneous/media/image/format/webp.rb +26 -0
- data/lib/spontaneous/media/image/format.rb +79 -0
- data/lib/spontaneous/media/image/optimizer.rb +69 -0
- data/lib/spontaneous/media/image/processor.rb +17 -0
- data/lib/spontaneous/media/image/renderable.rb +52 -0
- data/lib/spontaneous/media/image/skeptick.rb +70 -0
- data/lib/spontaneous/media/image.rb +50 -0
- data/lib/spontaneous/media/temp_file.rb +4 -0
- data/lib/spontaneous/media.rb +1 -0
- data/lib/spontaneous/model/core/aliases.rb +14 -8
- data/lib/spontaneous/model/core/boxes.rb +5 -2
- data/lib/spontaneous/model/core/entries.rb +4 -0
- data/lib/spontaneous/model/core/entry.rb +1 -0
- data/lib/spontaneous/model/core/fields.rb +5 -2
- data/lib/spontaneous/model/core/locks.rb +16 -0
- data/lib/spontaneous/model/core/media.rb +1 -15
- data/lib/spontaneous/model/core.rb +31 -1
- data/lib/spontaneous/model/page/controllers.rb +2 -2
- data/lib/spontaneous/model/page/formats.rb +1 -4
- data/lib/spontaneous/model/page/layouts.rb +6 -2
- data/lib/spontaneous/model/page/locks.rb +8 -2
- data/lib/spontaneous/model/page/page_tree.rb +2 -2
- data/lib/spontaneous/model/page/paths.rb +74 -9
- data/lib/spontaneous/model/page.rb +11 -3
- data/lib/spontaneous/model.rb +6 -6
- data/lib/spontaneous/output/context/render_cache.rb +23 -0
- data/lib/spontaneous/output/context.rb +56 -30
- data/lib/spontaneous/output/helpers/script_helper.rb +9 -53
- data/lib/spontaneous/output/helpers/stylesheet_helper.rb +8 -40
- data/lib/spontaneous/output/template/renderer.rb +17 -5
- data/lib/spontaneous/output.rb +0 -1
- data/lib/spontaneous/paths.rb +6 -2
- data/lib/spontaneous/permissions/access_key.rb +18 -0
- data/lib/spontaneous/permissions/user.rb +1 -1
- data/lib/spontaneous/permissions.rb +4 -1
- data/lib/spontaneous/plugins/application/state.rb +19 -12
- data/lib/spontaneous/prototypes/field_prototype.rb +14 -8
- data/lib/spontaneous/published_revision.rb +7 -0
- data/lib/spontaneous/publishing/immediate.rb +43 -34
- data/lib/spontaneous/publishing/revision.rb +9 -6
- data/lib/spontaneous/rack/asset_server.rb +20 -0
- data/lib/spontaneous/rack/back/alias.rb +46 -0
- data/lib/spontaneous/rack/back/application_assets.rb +28 -0
- data/lib/spontaneous/rack/back/base.rb +34 -0
- data/lib/spontaneous/rack/back/changes.rb +19 -0
- data/lib/spontaneous/rack/back/content.rb +54 -0
- data/lib/spontaneous/rack/back/events.rb +38 -0
- data/lib/spontaneous/rack/back/field.rb +37 -0
- data/lib/spontaneous/rack/back/file.rb +118 -0
- data/lib/spontaneous/rack/back/helpers.rb +71 -0
- data/lib/spontaneous/rack/back/index.rb +16 -0
- data/lib/spontaneous/rack/back/login.rb +47 -0
- data/lib/spontaneous/rack/back/map.rb +24 -0
- data/lib/spontaneous/rack/back/page.rb +46 -0
- data/lib/spontaneous/rack/back/preview.rb +43 -0
- data/lib/spontaneous/rack/back/schema.rb +30 -0
- data/lib/spontaneous/rack/back/site.rb +25 -0
- data/lib/spontaneous/rack/back/site_assets.rb +13 -0
- data/lib/spontaneous/rack/back/unsupported_browser.rb +7 -0
- data/lib/spontaneous/rack/{user_admin.rb → back/user_admin.rb} +2 -5
- data/lib/spontaneous/rack/back.rb +85 -764
- data/lib/spontaneous/rack/cacheable_file.rb +3 -3
- data/lib/spontaneous/rack/front.rb +16 -9
- data/lib/spontaneous/rack/middleware/authenticate.rb +65 -0
- data/lib/spontaneous/rack/middleware/csrf.rb +66 -0
- data/lib/spontaneous/rack/middleware/reloader.rb +52 -0
- data/lib/spontaneous/rack/middleware/scope.rb +60 -0
- data/lib/spontaneous/rack/middleware.rb +6 -0
- data/lib/spontaneous/rack/page_controller.rb +18 -5
- data/lib/spontaneous/rack/public.rb +17 -11
- data/lib/spontaneous/rack.rb +34 -24
- data/lib/spontaneous/revision.rb +29 -2
- data/lib/spontaneous/schema/uid.rb +4 -3
- data/lib/spontaneous/schema/uid_map.rb +5 -24
- data/lib/spontaneous/schema.rb +1 -0
- data/lib/spontaneous/search/database.rb +8 -0
- data/lib/spontaneous/search/field.rb +1 -1
- data/lib/spontaneous/search/index.rb +3 -5
- data/lib/spontaneous/server.rb +1 -1
- data/lib/spontaneous/simultaneous.rb +1 -1
- data/lib/spontaneous/site/features.rb +4 -5
- data/lib/spontaneous/site/helpers.rb +22 -5
- data/lib/spontaneous/site/instance.rb +2 -2
- data/lib/spontaneous/site/selectors.rb +22 -3
- data/lib/spontaneous/storage/cloud.rb +13 -9
- data/lib/spontaneous/storage/local.rb +11 -6
- data/lib/spontaneous/style.rb +40 -23
- data/lib/spontaneous/utils/database/mysql_dumper.rb +1 -1
- data/lib/spontaneous/utils/smush_it.rb +1 -1
- data/lib/spontaneous/version.rb +1 -1
- data/lib/spontaneous.rb +35 -33
- data/spontaneous.gemspec +53 -787
- data/test/experimental/test_crypt.rb +56 -56
- data/test/experimental/test_features.rb +16 -27
- data/test/fixtures/assets/public1/css/data.css.scss +3 -0
- data/test/fixtures/assets/public1/css/image1.css.scss +4 -0
- data/test/fixtures/assets/public1/css/import.css.scss +1 -0
- data/test/fixtures/assets/public1/css/urlhash.css.scss +3 -0
- data/test/fixtures/assets/public1/js/a.js +1 -1
- data/test/fixtures/assets/public1/js/all.js +4 -0
- data/test/fixtures/assets/public1/js/{m.coffee → m.js.coffee} +1 -0
- data/test/fixtures/assets/public1/x.js +1 -0
- data/test/fixtures/assets/public2/css/all.css +4 -0
- data/test/fixtures/assets/public2/css/missing.css.scss +3 -0
- data/test/fixtures/assets/public2/i/y.png +0 -0
- data/test/fixtures/assets/public2/js/b.js +1 -1
- data/test/fixtures/assets/public2/js/c.js +1 -1
- data/test/fixtures/images/size.extended.webp +0 -0
- data/test/fixtures/images/size.lossless.webp +0 -0
- data/test/fixtures/images/size.lossy.webp +0 -0
- data/test/fixtures/schema/before.yml +4 -4
- data/test/fixtures/schema/schema.yml +1 -1
- data/test/fixtures/templates/aliases/aaa.html.cut +0 -0
- data/test/fixtures/templates/extended/partial_with_renderer.html.cut +1 -0
- data/test/fixtures/templates/extended/with_includes_and_renderer.html.cut +2 -0
- data/test/functional/test_application.rb +108 -106
- data/test/functional/test_back.rb +924 -930
- data/test/functional/test_front.rb +285 -238
- data/test/functional/test_user_manager.rb +75 -100
- data/test/integration/test_installation.rb +1 -1
- data/test/support/matchers.rb +12 -0
- data/test/support/minitest.rb +121 -0
- data/test/support/rack.rb +45 -0
- data/test/support/test_start_finish.rb +103 -0
- data/test/test_helper.rb +21 -68
- data/test/test_integration_helper.rb +1 -3
- data/test/unit/test_alias.rb +432 -408
- data/test/unit/test_asset_bundler.rb +58 -58
- data/test/unit/test_assets.rb +485 -155
- data/test/unit/test_async.rb +16 -37
- data/test/unit/test_authentication.rb +425 -457
- data/test/unit/test_boxes.rb +191 -191
- data/test/unit/test_changesets.rb +244 -254
- data/test/unit/test_config.rb +128 -142
- data/test/unit/test_content.rb +313 -359
- data/test/unit/test_content_inheritance.rb +29 -30
- data/test/unit/test_datamapper.rb +1205 -1080
- data/test/unit/test_datamapper_content.rb +49 -51
- data/test/unit/test_extensions.rb +23 -23
- data/test/unit/test_fields.rb +1488 -1180
- data/test/unit/test_formats.rb +158 -158
- data/test/unit/test_generators.rb +98 -40
- data/test/unit/test_helpers.rb +73 -76
- data/test/unit/test_image_size.rb +53 -22
- data/test/unit/test_images.rb +164 -165
- data/test/unit/test_layouts.rb +133 -122
- data/test/unit/test_logger.rb +14 -17
- data/test/unit/test_media.rb +69 -84
- data/test/unit/test_modifications.rb +513 -525
- data/test/unit/test_page.rb +462 -361
- data/test/unit/test_permissions.rb +379 -364
- data/test/unit/test_piece.rb +67 -75
- data/test/unit/test_plugins.rb +82 -89
- data/test/unit/test_prototype_set.rb +215 -216
- data/test/unit/test_prototypes.rb +114 -124
- data/test/unit/test_publishing.rb +252 -289
- data/test/unit/test_render.rb +167 -115
- data/test/unit/test_revisions.rb +436 -444
- data/test/unit/test_schema.rb +339 -309
- data/test/unit/test_search.rb +577 -574
- data/test/unit/test_serialisation.rb +136 -147
- data/test/unit/test_site.rb +252 -227
- data/test/unit/test_skeptick.rb +130 -0
- data/test/unit/test_storage.rb +46 -40
- data/test/unit/test_structure.rb +57 -66
- data/test/unit/test_styles.rb +104 -104
- data/test/unit/test_templates.rb +72 -57
- data/test/unit/test_type_hierarchy.rb +15 -16
- data/test/unit/test_visibility.rb +239 -257
- metadata +455 -326
- data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +0 -283
- data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +0 -30
- data/application/js/vendor/JS.Class-2.1.5/README +0 -30
- data/application/js/vendor/JS.Class-2.1.5/min/command.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/hash.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/loader.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/observable.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/package.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/set.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/state.js +0 -1
- data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +0 -16
- data/application/js/vendor/jquery-1.6.2.min.js +0 -18
- data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +0 -791
- data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +0 -415
- data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
- data/application/static/select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png +0 -0
- data/bin/limit-upload +0 -5
- data/bin/unlimit-upload +0 -3
- data/lib/spontaneous/asset/file.rb +0 -25
- data/lib/spontaneous/asset/source.rb +0 -28
- data/lib/spontaneous/image_size.rb +0 -123
- data/lib/spontaneous/output/assets/compression.rb +0 -58
- data/lib/spontaneous/output/assets.rb +0 -32
- data/lib/spontaneous/rack/around_back.rb +0 -20
- data/lib/spontaneous/rack/around_front.rb +0 -27
- data/lib/spontaneous/rack/around_preview.rb +0 -22
- data/lib/spontaneous/rack/assets.rb +0 -126
- data/lib/spontaneous/rack/authentication.rb +0 -20
- data/lib/spontaneous/rack/cookie_authentication.rb +0 -38
- data/lib/spontaneous/rack/helpers.rb +0 -52
- data/lib/spontaneous/rack/http.rb +0 -18
- data/lib/spontaneous/rack/media.rb +0 -30
- data/lib/spontaneous/rack/query_authentication.rb +0 -35
- data/lib/spontaneous/rack/reloader.rb +0 -45
- data/lib/spontaneous/rack/user_helpers.rb +0 -28
- /data/{README → application/js/field/markdown/text_command.js} +0 -0
- /data/application/js/vendor/{JS.Class-2.1.5/min/core.js → js.class-2.1.5.min.js} +0 -0
- /data/test/fixtures/assets/public1/css/{a.scss → a.css.scss} +0 -0
- /data/{lib/spontaneous/generators/site/public/css/site.scss → test/fixtures/assets/public1/x.css} +0 -0
- /data/{lib/spontaneous/generators/site/public/js/.empty_directory → test/fixtures/assets/public1/x.png} +0 -0
- /data/test/fixtures/assets/public2/css/{b.scss → b.css.scss} +0 -0
- /data/test/fixtures/assets/public2/js/{n.coffee → n.js.coffee} +0 -0
- /data/test/fixtures/back/{public → assets}/css/sass_include.scss +0 -0
- /data/test/fixtures/back/{public → assets}/css/sass_template.scss +0 -0
- /data/test/fixtures/back/{public → assets}/js/coffeescript.coffee +0 -0
- /data/{lib/spontaneous/generators/site/public/js/site.js → test/fixtures/templates/aliases/aa_alias.html.cut} +0 -0
@@ -1,7 +1,10 @@
|
|
1
1
|
|
2
2
|
module Spontaneous::Output::Context
|
3
|
+
autoload :RenderCache, 'spontaneous/output/context/render_cache'
|
4
|
+
|
3
5
|
module ContextCore
|
4
|
-
|
6
|
+
include RenderCache
|
7
|
+
attr_accessor :_renderer
|
5
8
|
|
6
9
|
def navigation(depth = 1, &block)
|
7
10
|
case depth
|
@@ -37,10 +40,36 @@ module Spontaneous::Output::Context
|
|
37
40
|
Spontaneous.development?
|
38
41
|
end
|
39
42
|
|
43
|
+
def development?
|
44
|
+
Spontaneous.development?
|
45
|
+
end
|
46
|
+
|
40
47
|
def root
|
41
48
|
Spontaneous::Site.root
|
42
49
|
end
|
43
50
|
|
51
|
+
def site_page(path)
|
52
|
+
Spontaneous::Site[path]
|
53
|
+
end
|
54
|
+
|
55
|
+
def asset_environment
|
56
|
+
_with_render_cache('asset.environment') do
|
57
|
+
Spontaneous::Asset::Environment.new(self)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def asset_path(path, options = {})
|
62
|
+
asset_environment.find(path, options).try(:first)
|
63
|
+
end
|
64
|
+
|
65
|
+
def asset_url(path, options = {})
|
66
|
+
"url(#{asset_path(path, options)})"
|
67
|
+
end
|
68
|
+
|
69
|
+
def site
|
70
|
+
Spontaneous::Site.instance
|
71
|
+
end
|
72
|
+
|
44
73
|
def publishing?
|
45
74
|
false
|
46
75
|
end
|
@@ -57,6 +86,10 @@ module Spontaneous::Output::Context
|
|
57
86
|
content.map { |c| yield(c) } if block_given?
|
58
87
|
end
|
59
88
|
|
89
|
+
def this
|
90
|
+
__target
|
91
|
+
end
|
92
|
+
|
60
93
|
def content
|
61
94
|
__target.iterable
|
62
95
|
end
|
@@ -87,6 +120,17 @@ module Spontaneous::Output::Context
|
|
87
120
|
__target.owner.pieces.last == self
|
88
121
|
end
|
89
122
|
|
123
|
+
# template takes an existing first-pass template, converts it to a second pass template
|
124
|
+
# and then returns the result for inclusion.
|
125
|
+
# This lets you share templates between the publish step and the request step.
|
126
|
+
# Useful for things like search results where you want to list the results using the same
|
127
|
+
# layout that you used in the static list
|
128
|
+
def template(template_path)
|
129
|
+
__loader.template(template_path).convert(Spontaneous::Output::Template::RequestSyntax)
|
130
|
+
end
|
131
|
+
|
132
|
+
alias_method :defer, :template
|
133
|
+
|
90
134
|
def __format
|
91
135
|
__loader.format
|
92
136
|
end
|
@@ -109,37 +153,14 @@ module Spontaneous::Output::Context
|
|
109
153
|
# use of shared caches that are held by it.
|
110
154
|
def __render_content(content)
|
111
155
|
if content.respond_to?(:render_using)
|
112
|
-
content.render_using(
|
156
|
+
content.render_using(_renderer, __format, self)
|
113
157
|
else
|
114
158
|
content.render(__format, self)
|
115
159
|
end
|
116
160
|
end
|
117
161
|
end
|
118
162
|
|
119
|
-
module RenderCache
|
120
|
-
def _render_cache_value(key)
|
121
|
-
__renderer.render_cache[key]
|
122
|
-
end
|
123
|
-
|
124
|
-
def _render_cache_set_value(key, value)
|
125
|
-
__renderer.render_cache[key] = value
|
126
|
-
end
|
127
|
-
|
128
|
-
def _render_cache_key?(key)
|
129
|
-
__renderer.render_cache.key?(key)
|
130
|
-
end
|
131
|
-
|
132
|
-
def _with_render_cache(key, &value_block)
|
133
|
-
if _render_cache_key?(key)
|
134
|
-
_render_cache_value(key)
|
135
|
-
else
|
136
|
-
_render_cache_set_value(key, yield)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
163
|
module PublishContext
|
142
|
-
include RenderCache
|
143
164
|
|
144
165
|
def root
|
145
166
|
_with_render_cache("site.root") do
|
@@ -147,15 +168,21 @@ module Spontaneous::Output::Context
|
|
147
168
|
end
|
148
169
|
end
|
149
170
|
|
150
|
-
def
|
171
|
+
def site_page(path)
|
172
|
+
_with_render_cache("site_page.#{path}") do
|
173
|
+
super
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def scripts(*scripts)
|
151
178
|
_with_render_cache(scripts.join(",")) do
|
152
|
-
super
|
179
|
+
super
|
153
180
|
end
|
154
181
|
end
|
155
182
|
|
156
|
-
def
|
183
|
+
def stylesheets(*stylesheets)
|
157
184
|
_with_render_cache(stylesheets.join(",")) do
|
158
|
-
super
|
185
|
+
super
|
159
186
|
end
|
160
187
|
end
|
161
188
|
|
@@ -175,5 +202,4 @@ module Spontaneous::Output::Context
|
|
175
202
|
|
176
203
|
module RequestContext
|
177
204
|
end
|
178
|
-
|
179
205
|
end
|
@@ -7,67 +7,23 @@ module Spontaneous::Output::Helpers
|
|
7
7
|
extend self
|
8
8
|
|
9
9
|
def scripts(*args)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
script_urls(*args).map { |script|
|
11
|
+
script_tag(script)
|
12
|
+
}.join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
def script_urls(*args)
|
16
|
+
options = args.extract_options!
|
17
|
+
options.update(:development => development?)
|
18
|
+
asset_environment.js(args.flatten, options)
|
15
19
|
end
|
16
20
|
|
17
21
|
alias_method :script, :scripts
|
18
22
|
|
19
23
|
def script_tag(src)
|
20
|
-
src = "#{src}.js" unless src =~ /\.js$/o
|
21
24
|
%(<script type="text/javascript" src="#{src}"></script>)
|
22
25
|
end
|
23
26
|
|
24
|
-
def convert_coffeescript(url)
|
25
|
-
S::Output::Assets.compile_coffeescript(url)
|
26
|
-
end
|
27
|
-
|
28
|
-
def compressed_scripts(scripts)
|
29
|
-
file_paths = scripts.map { |script| [script, S::Output::Assets.find_file("#{script}.js", "#{script}.coffee")] }
|
30
|
-
invalid, file_paths = file_paths.partition { |url, path| path.nil? }
|
31
|
-
|
32
|
-
tags = []
|
33
|
-
unless file_paths.empty?
|
34
|
-
# in order to compile coffeescript efficiently, avoiding multiple anonymous function wrappers
|
35
|
-
# but keeping the files in the correct order
|
36
|
-
# first partition files into js & coffee groups:
|
37
|
-
types = file_paths.slice_between { |(purl, ppath), (url, path)| File.extname(ppath) != File.extname(path) }
|
38
|
-
# then iterate through each group to concatenate the source into a single string (src)
|
39
|
-
js = types.map { |type|
|
40
|
-
ext = nil
|
41
|
-
src = type.map { |url, path|
|
42
|
-
ext = File.extname(path)
|
43
|
-
File.read(path)
|
44
|
-
}.join
|
45
|
-
# then compile the concatenated src if it's coffeescript
|
46
|
-
case ext
|
47
|
-
when ".coffee"
|
48
|
-
CoffeeScript.compile src
|
49
|
-
else
|
50
|
-
src
|
51
|
-
end
|
52
|
-
}.join
|
53
|
-
|
54
|
-
compressed, hash = compress_js_string(js)
|
55
|
-
output_path = Spontaneous::Output::Assets.path_for(revision, "#{hash}.js")
|
56
|
-
|
57
|
-
FileUtils.mkdir_p(File.dirname(output_path))
|
58
|
-
File.open(output_path, "w") { |file| file.write(compressed) }
|
59
|
-
|
60
|
-
tags = [script_tag(Spontaneous::Output::Assets.url(hash))]
|
61
|
-
end
|
62
|
-
|
63
|
-
tags.concat invalid.map { |src, path| script_tag(src) }
|
64
|
-
tags.join("\n")
|
65
|
-
end
|
66
|
-
|
67
|
-
def compress_js_string(js_string)
|
68
|
-
Spontaneous::Output::Assets::Compression.shine_compress_string(js_string, :js)
|
69
|
-
end
|
70
|
-
|
71
27
|
Spontaneous::Output::Helpers.register_helper(self, :html)
|
72
28
|
end
|
73
29
|
end
|
@@ -7,55 +7,23 @@ module Spontaneous::Output::Helpers
|
|
7
7
|
extend self
|
8
8
|
|
9
9
|
def stylesheets(*args)
|
10
|
-
|
11
|
-
options = stylesheets.extract_options!
|
12
|
-
compress_stylesheets = (live? or (publishing? and options[:force_compression]))
|
13
|
-
|
14
|
-
return compressed_stylesheets(stylesheets) if compress_stylesheets
|
15
|
-
|
16
|
-
stylesheets.map do |stylesheet|
|
10
|
+
stylesheet_urls(*args).map { |stylesheet|
|
17
11
|
stylesheet_tag(stylesheet)
|
18
|
-
|
12
|
+
}.join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
def stylesheet_urls(*args)
|
16
|
+
options = args.extract_options!
|
17
|
+
options.update(:development => development?)
|
18
|
+
asset_environment.css(args.flatten, options)
|
19
19
|
end
|
20
20
|
|
21
21
|
alias_method :stylesheet, :stylesheets
|
22
22
|
|
23
23
|
def stylesheet_tag(href)
|
24
|
-
href = "#{href}.css" unless href =~ /\.css$/o
|
25
24
|
%(<link rel="stylesheet" href="#{href}" />)
|
26
25
|
end
|
27
26
|
|
28
|
-
def compressed_stylesheets(stylesheets)
|
29
|
-
file_paths = stylesheets.map { |style| [style, S::Output::Assets.find_file("#{style}.scss", "#{style}.css")] }
|
30
|
-
invalid, file_paths = file_paths.partition { |url, path| path.nil? }
|
31
|
-
roots = Spontaneous.instance.paths.expanded(:public)
|
32
|
-
|
33
|
-
tags = []
|
34
|
-
css = file_paths.map { |url, path|
|
35
|
-
case path
|
36
|
-
when /\.scss$/o
|
37
|
-
load_paths = roots + [File.dirname(path), File.dirname(path) / "sass"]
|
38
|
-
::Sass::Engine.for_file(path, {
|
39
|
-
:load_paths => load_paths,
|
40
|
-
:cache => false,
|
41
|
-
:style => :compressed
|
42
|
-
}).render
|
43
|
-
else
|
44
|
-
File.read(path)
|
45
|
-
end
|
46
|
-
}.join
|
47
|
-
compressed, hash = compress_css_string(css)
|
48
|
-
output_path = Spontaneous::Output::Assets.path_for(revision, "#{hash}.css")
|
49
|
-
FileUtils.mkdir_p(File.dirname(output_path))
|
50
|
-
File.open(output_path, "w") { |file| file.write(compressed) }
|
51
|
-
tags = [stylesheet_tag(Spontaneous::Output::Assets.url(hash))]
|
52
|
-
tags.join("\n")
|
53
|
-
end
|
54
|
-
|
55
|
-
def compress_css_string(css_string)
|
56
|
-
Spontaneous::Output::Assets::Compression.shine_compress_string(css_string, :css)
|
57
|
-
end
|
58
|
-
|
59
27
|
Spontaneous::Output::Helpers.register_helper(self, :html)
|
60
28
|
end
|
61
29
|
end
|
@@ -18,24 +18,32 @@ module Spontaneous::Output::Template
|
|
18
18
|
|
19
19
|
def render(output, params = {})
|
20
20
|
output.model.with_visible do
|
21
|
-
engine.render(output.content, context(output, params), output.name
|
21
|
+
engine.render(output.content, context(output, params), output.name)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
def render_string(template_string, output, params = {})
|
26
26
|
output.model.with_visible do
|
27
|
-
engine.render_string(template_string, context(output, params), output.name
|
27
|
+
engine.render_string(template_string, context(output, params), output.name)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def context(output, params)
|
32
32
|
context_class(output).new(output.content, params).tap do |context|
|
33
|
-
context.
|
33
|
+
context._renderer = renderer_for_context
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
def renderer_for_context
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
37
41
|
def context_class(output)
|
38
|
-
|
42
|
+
if Spontaneous.development?
|
43
|
+
generate_context_class(output)
|
44
|
+
else
|
45
|
+
context_cache[output.name] ||= generate_context_class(output)
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
def context_cache
|
@@ -146,8 +154,12 @@ module Spontaneous::Output::Template
|
|
146
154
|
request_renderer.render_string(rendered, output, params)
|
147
155
|
end
|
148
156
|
|
157
|
+
def renderer_for_context
|
158
|
+
@renderer_for_context ||= PublishRenderer.new(@cache)
|
159
|
+
end
|
160
|
+
|
149
161
|
def request_renderer
|
150
|
-
@request_renderer ||= RequestRenderer.new
|
162
|
+
@request_renderer ||= RequestRenderer.new(@cache)
|
151
163
|
end
|
152
164
|
end
|
153
165
|
end
|
data/lib/spontaneous/output.rb
CHANGED
data/lib/spontaneous/paths.rb
CHANGED
@@ -4,17 +4,21 @@ require 'pathname'
|
|
4
4
|
|
5
5
|
module Spontaneous
|
6
6
|
class Paths < ::Hash
|
7
|
+
# TODO: Move this kind of stuff into the Revision class
|
8
|
+
# Instead of throwing around revision numbers we should
|
9
|
+
# be throwing around Revision instances. It is fecking OO
|
10
|
+
# after all...
|
7
11
|
def self.pad_revision_number(revision)
|
8
12
|
revision.to_s.rjust(5, "0")
|
9
13
|
end
|
10
14
|
|
11
15
|
def initialize(root)
|
12
16
|
@root = File.expand_path(root)
|
13
|
-
super()
|
17
|
+
super() { |hash, key| hash[key] = [] }
|
14
18
|
end
|
15
19
|
|
16
20
|
def add(category, *paths)
|
17
|
-
self[category]
|
21
|
+
self[category].concat(paths)
|
18
22
|
end
|
19
23
|
|
20
24
|
def expanded(category)
|
@@ -36,5 +36,23 @@ module Spontaneous::Permissions
|
|
36
36
|
def access!(ip_address = nil)
|
37
37
|
self.update(:last_access_at => Time.now, :last_access_ip => ip_address)
|
38
38
|
end
|
39
|
+
|
40
|
+
CSFR_SEP = ":".freeze
|
41
|
+
|
42
|
+
def generate_csrf_token
|
43
|
+
salt = Spontaneous::Permissions.random_string(32)
|
44
|
+
[salt, generate_csrf_hash(salt)].join(CSFR_SEP)
|
45
|
+
end
|
46
|
+
|
47
|
+
def csrf_token_valid?(token)
|
48
|
+
return false if token.nil?
|
49
|
+
salt, fingerprint = token.split(CSFR_SEP)
|
50
|
+
generate_csrf_hash(salt) == fingerprint
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate_csrf_hash(salt)
|
54
|
+
fingerprint = [salt, key_id].join(CSFR_SEP)
|
55
|
+
Spontaneous::Permissions.crypto_hash(fingerprint)
|
56
|
+
end
|
39
57
|
end
|
40
58
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require 'base58'
|
4
3
|
require 'securerandom'
|
5
4
|
|
6
5
|
module Spontaneous
|
@@ -29,6 +28,10 @@ module Spontaneous
|
|
29
28
|
def random_string(length)
|
30
29
|
SecureRandom.urlsafe_base64(length)[0...(length)]
|
31
30
|
end
|
31
|
+
|
32
|
+
def crypto_hash(string, algorithm = Digest::SHA1)
|
33
|
+
algorithm.new.update(string).hexdigest
|
34
|
+
end
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -5,19 +5,26 @@ module Spontaneous::Plugins::Application
|
|
5
5
|
extend Spontaneous::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
+
@@semaphore = Mutex.new
|
9
|
+
|
8
10
|
def init(options={})
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
@@semaphore.synchronize do
|
12
|
+
self.environment = (options.delete(:environment) || ENV["SPOT_ENV"] || :development)
|
13
|
+
self.mode = options.delete(:mode) || ENV["SPOT_MODE"] || :back
|
14
|
+
root = options.delete(:root) || ENV["SPOT_ROOT"] || Dir.pwd
|
15
|
+
site = Spontaneous::Site.instantiate(root, environment, mode)
|
16
|
+
lib = File.expand_path(File.join(root, "lib"))
|
17
|
+
$:.push(lib) unless $:.include?(lib)
|
18
|
+
Spontaneous::Logger.setup(:log_level => options[:log_level], :logfile => options[:logfile], :cli => options[:cli])
|
19
|
+
site.initialize!
|
20
|
+
site.schema.validate! if self.mode == :console
|
21
|
+
if site.config.auto_login && mode == :back
|
22
|
+
logger.warn "Auto login is enabled and set to '#{site.config.auto_login}'.\n" \
|
23
|
+
" Please ensure this is disabled in production mode by removing the\n" \
|
24
|
+
" 'auto_login' setting from your environment file."
|
25
|
+
end
|
26
|
+
Thread.current[:spontaneous_loaded] = true
|
27
|
+
end
|
21
28
|
end
|
22
29
|
|
23
30
|
# This is called after definition of the Content model.
|
@@ -10,13 +10,15 @@ module Spontaneous::Prototypes
|
|
10
10
|
@name = name
|
11
11
|
@extend = [blocks].flatten.push(block).compact
|
12
12
|
|
13
|
-
parse_options(options)
|
14
|
-
|
15
13
|
# if the type is nil then try the name, this will assign sensible defaults
|
16
14
|
# to fields like 'image' or 'date'
|
17
15
|
@base_class = Spontaneous::Field[type || name]
|
18
16
|
|
19
|
-
|
17
|
+
parse_options(@base_class, options)
|
18
|
+
|
19
|
+
|
20
|
+
field_class_name = "#{name.to_s.camelize}Field"
|
21
|
+
owner.const_set(field_class_name, instance_class)
|
20
22
|
|
21
23
|
self
|
22
24
|
end
|
@@ -52,11 +54,12 @@ module Spontaneous::Prototypes
|
|
52
54
|
@name.to_s.titleize
|
53
55
|
end
|
54
56
|
|
55
|
-
def parse_options(options)
|
56
|
-
@options =
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
def parse_options(field_class, options)
|
58
|
+
@options = default_options(field_class).merge(options)
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_options(field_class)
|
62
|
+
{:default => '', :comment => false }.merge(field_class.default_options)
|
60
63
|
end
|
61
64
|
|
62
65
|
def instance_class
|
@@ -96,6 +99,9 @@ module Spontaneous::Prototypes
|
|
96
99
|
@options[:comment]
|
97
100
|
end
|
98
101
|
|
102
|
+
def fallback
|
103
|
+
@options[:fallback]
|
104
|
+
end
|
99
105
|
|
100
106
|
# default read level is None, i.e. every logged in user can read the field
|
101
107
|
def read_level
|
@@ -87,15 +87,13 @@ module Spontaneous
|
|
87
87
|
abort_publish_at_exit
|
88
88
|
}
|
89
89
|
before_publish
|
90
|
-
|
91
|
-
|
92
|
-
render_revision
|
93
|
-
end
|
94
|
-
after_publish
|
95
|
-
rescue ::Exception => e
|
96
|
-
abort_publish(e)
|
97
|
-
raise(e)
|
90
|
+
@content_model.publish(revision, modified_page_list) do
|
91
|
+
render_revision
|
98
92
|
end
|
93
|
+
after_publish
|
94
|
+
rescue ::Exception => e # Catch even interrupts because we definitely need to cleanup
|
95
|
+
abort_publish(e)
|
96
|
+
raise(e)
|
99
97
|
end
|
100
98
|
|
101
99
|
def render_revision
|
@@ -215,21 +213,25 @@ module Spontaneous
|
|
215
213
|
public_dirs.each do |public_src|
|
216
214
|
next unless public_src.exist?
|
217
215
|
public_src = public_src.realpath
|
218
|
-
Dir[public_src.to_s / "**/*"].each do |
|
219
|
-
|
220
|
-
# insert facet namespace in front of path to keep URLs consistent across
|
221
|
-
# the back & front servers
|
222
|
-
dest = [facet.file_namespace, src.relative_path_from(public_src).to_s].compact
|
223
|
-
dest = (public_dest + File.join(dest))
|
224
|
-
if src.directory?
|
225
|
-
dest.mkpath
|
226
|
-
else
|
227
|
-
copy_public_file(src, dest)
|
228
|
-
end
|
216
|
+
Dir[public_src.to_s / "**/*"].each do |file|
|
217
|
+
copy_facet_public_dir(facet, file, public_src, public_dest)
|
229
218
|
end
|
230
219
|
end
|
231
220
|
end
|
232
221
|
|
222
|
+
def copy_facet_public_dir(facet, original, public_src, public_dest)
|
223
|
+
original = Pathname.new(original)
|
224
|
+
# insert facet namespace in front of path to keep URLs consistent across
|
225
|
+
# the back & front servers
|
226
|
+
dest = File.join [facet.file_namespace, original.relative_path_from(public_src).to_s].compact
|
227
|
+
dest = public_dest + dest
|
228
|
+
if original.directory?
|
229
|
+
dest.mkpath
|
230
|
+
else
|
231
|
+
copy_public_file(original, dest)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
233
235
|
def copy_public_file(src, dest)
|
234
236
|
# TODO: Add coffeescript compilation.
|
235
237
|
# Should be implemented using sprockets
|
@@ -286,27 +288,34 @@ module Spontaneous
|
|
286
288
|
|
287
289
|
def after_publish
|
288
290
|
update_progress("finalising")
|
289
|
-
S::Revision.create(:revision => revision, :published_at => now)
|
290
|
-
Spontaneous::Site.send(:set_published_revision, revision)
|
291
|
-
tmp = Spontaneous.revision_dir(revision) / "tmp"
|
292
|
-
FileUtils.mkdir_p(tmp) unless ::File.exists?(tmp)
|
293
|
-
write_revision(revision)
|
294
|
-
|
295
291
|
begin
|
296
|
-
Spontaneous
|
297
|
-
|
298
|
-
|
292
|
+
tmp = Spontaneous.revision_dir(revision) / "tmp"
|
293
|
+
FileUtils.mkdir_p(tmp) unless ::File.exists?(tmp)
|
294
|
+
activate_revision
|
299
295
|
update_progress("complete")
|
300
|
-
rescue
|
296
|
+
rescue => e
|
301
297
|
# if a post publish hook raises an exception then we want to roll everything back
|
302
|
-
|
303
|
-
Spontaneous::Site.send(:set_published_revision, @previous_revision)
|
304
|
-
write_revision(@previous_revision)
|
305
|
-
abort_publish(e)
|
298
|
+
deactivate_revision
|
306
299
|
raise e
|
307
300
|
end
|
308
301
|
end
|
309
302
|
|
303
|
+
def activate_revision
|
304
|
+
S::PublishedRevision.create(:revision => revision, :published_at => now)
|
305
|
+
Spontaneous::Site.send(:set_published_revision, revision)
|
306
|
+
write_revision(revision)
|
307
|
+
Spontaneous::Site.trigger(:after_publish, revision)
|
308
|
+
Spontaneous::Site.send(:pending_revision=, nil)
|
309
|
+
Spontaneous::Content.cleanup_revisions(revision, keep_revisions)
|
310
|
+
end
|
311
|
+
|
312
|
+
def deactivate_revision
|
313
|
+
S::PublishedRevision.filter(:revision => revision).delete
|
314
|
+
Spontaneous::Site.send(:set_published_revision, @previous_revision)
|
315
|
+
write_revision(@previous_revision)
|
316
|
+
abort_publish(e)
|
317
|
+
end
|
318
|
+
|
310
319
|
# Makes the revision live on the filesystem by symlinking the revisions/current
|
311
320
|
# directory to the revision directory and writing the current revision to the
|
312
321
|
# revisions/REVISION file.
|
@@ -324,7 +333,7 @@ module Spontaneous
|
|
324
333
|
end
|
325
334
|
|
326
335
|
def abort_publish(exception)
|
327
|
-
if r = S::Site.pending_revision
|
336
|
+
if (r = S::Site.pending_revision)
|
328
337
|
update_progress("aborting")
|
329
338
|
FileUtils.rm_r(Spontaneous.revision_dir(revision)) if File.exists?(Spontaneous.revision_dir(revision))
|
330
339
|
Spontaneous::Site.send(:pending_revision=, nil)
|
@@ -28,7 +28,7 @@ module Spontaneous::Publishing
|
|
28
28
|
yield if block_given?
|
29
29
|
end
|
30
30
|
set_source_timestamps
|
31
|
-
rescue
|
31
|
+
rescue => e
|
32
32
|
@revision.delete
|
33
33
|
raise e
|
34
34
|
end
|
@@ -157,11 +157,9 @@ module Spontaneous::Publishing
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def self.delete_all(model)
|
160
|
-
revisions = tables(model).
|
161
|
-
map { |table| revision_from_table(model, table) }.
|
162
|
-
map { |r| new(model, r) }
|
160
|
+
revisions = tables(model).map { |table| for_table(model, table) }
|
163
161
|
|
164
|
-
# Don't call the full #delete because it is much more efficient
|
162
|
+
# Don't call the full Revision#delete because it is much more efficient
|
165
163
|
# to delete the contents of the revision tables in a single
|
166
164
|
# command rather than revision by revision
|
167
165
|
revisions.each(&:delete_table)
|
@@ -191,6 +189,11 @@ module Spontaneous::Publishing
|
|
191
189
|
ds.filter(:revision => revision, &block)
|
192
190
|
end
|
193
191
|
|
192
|
+
def self.for_table(model, table)
|
193
|
+
r = revision_from_table(model, table)
|
194
|
+
new(model, r)
|
195
|
+
end
|
196
|
+
|
194
197
|
def self.revision_from_table(model, table)
|
195
198
|
model.mapper.revision_from_table(table)
|
196
199
|
end
|
@@ -345,7 +348,7 @@ module Spontaneous::Publishing
|
|
345
348
|
end
|
346
349
|
|
347
350
|
def archive_dataset(&block)
|
348
|
-
_dataset(
|
351
|
+
_dataset(archive_table, &block)
|
349
352
|
end
|
350
353
|
|
351
354
|
def _dataset(table, &block)
|