spontaneous 0.2.0.beta9 → 0.2.0.beta10

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -0
  3. data/LICENSE +18 -17
  4. data/Rakefile +1 -1
  5. data/application/css/core.css.scss +1 -1
  6. data/application/css/dialogue.css.scss +8 -20
  7. data/application/js/preview.js +28 -7
  8. data/application/js/publish.js +15 -4
  9. data/application/js/top_bar.js +0 -16
  10. data/application/js/views/piece_view.js +1 -1
  11. data/lib/spontaneous/asset/environment.rb +16 -1
  12. data/lib/spontaneous/box.rb +68 -0
  13. data/lib/spontaneous/capistrano/deploy.rb +7 -4
  14. data/lib/spontaneous/capistrano/sync.rb +2 -2
  15. data/lib/spontaneous/cli/init.rb +70 -19
  16. data/lib/spontaneous/cli/init/db.rb +34 -55
  17. data/lib/spontaneous/cli/init/mysql.rb +5 -5
  18. data/lib/spontaneous/cli/init/postgresql.rb +8 -9
  19. data/lib/spontaneous/cli/init/sqlite.rb +1 -2
  20. data/lib/spontaneous/cli/migrate.rb +0 -1
  21. data/lib/spontaneous/cli/site.rb +4 -0
  22. data/lib/spontaneous/collections/entry_set.rb +11 -0
  23. data/lib/spontaneous/data_mapper/content_model.rb +2 -0
  24. data/lib/spontaneous/data_mapper/content_model/serialization.rb +2 -2
  25. data/lib/spontaneous/extensions/array.rb +12 -2
  26. data/lib/spontaneous/field/base.rb +10 -0
  27. data/lib/spontaneous/field/file.rb +32 -2
  28. data/lib/spontaneous/field/image.rb +24 -2
  29. data/lib/spontaneous/field/select.rb +8 -0
  30. data/lib/spontaneous/field/webvideo.rb +8 -0
  31. data/lib/spontaneous/generators/site/config/initializers/fields.rb +55 -0
  32. data/lib/spontaneous/json.rb +3 -2
  33. data/lib/spontaneous/logger.rb +2 -2
  34. data/lib/spontaneous/media/file.rb +3 -3
  35. data/lib/spontaneous/media/image/attributes.rb +72 -6
  36. data/lib/spontaneous/media/image/renderable.rb +53 -20
  37. data/lib/spontaneous/media/store.rb +3 -3
  38. data/lib/spontaneous/media/store/backend.rb +16 -0
  39. data/lib/spontaneous/media/store/cloud.rb +52 -12
  40. data/lib/spontaneous/media/store/local.rb +6 -3
  41. data/lib/spontaneous/model.rb +3 -0
  42. data/lib/spontaneous/model/core/entries.rb +34 -13
  43. data/lib/spontaneous/model/core/entry.rb +3 -1
  44. data/lib/spontaneous/model/page/controllers.rb +1 -2
  45. data/lib/spontaneous/model/page/paths.rb +18 -7
  46. data/lib/spontaneous/output/context.rb +0 -8
  47. data/lib/spontaneous/output/template/renderer.rb +2 -0
  48. data/lib/spontaneous/plugins/application/state.rb +0 -4
  49. data/lib/spontaneous/prototypes/field_prototype.rb +4 -0
  50. data/lib/spontaneous/publishing/immediate.rb +0 -5
  51. data/lib/spontaneous/publishing/progress.rb +2 -2
  52. data/lib/spontaneous/publishing/rerender.rb +1 -4
  53. data/lib/spontaneous/publishing/simultaneous.rb +19 -17
  54. data/lib/spontaneous/publishing/steps.rb +12 -3
  55. data/lib/spontaneous/rack.rb +2 -0
  56. data/lib/spontaneous/rack/asset_server.rb +5 -2
  57. data/lib/spontaneous/rack/back.rb +9 -1
  58. data/lib/spontaneous/rack/back/base.rb +1 -0
  59. data/lib/spontaneous/rack/back/changes.rb +5 -0
  60. data/lib/spontaneous/rack/back/preview.rb +4 -4
  61. data/lib/spontaneous/rack/back/private.rb +11 -0
  62. data/lib/spontaneous/rack/middleware/scope.rb +16 -4
  63. data/lib/spontaneous/rack/page_controller.rb +2 -2
  64. data/lib/spontaneous/rack/public.rb +52 -4
  65. data/lib/spontaneous/sequel.rb +10 -13
  66. data/lib/spontaneous/site.rb +28 -8
  67. data/lib/spontaneous/site/publishing.rb +1 -1
  68. data/lib/spontaneous/site/storage.rb +7 -4
  69. data/lib/spontaneous/tasks/environment.rake +3 -0
  70. data/lib/spontaneous/utils/database/postgres_dumper.rb +23 -2
  71. data/lib/spontaneous/version.rb +1 -1
  72. data/spontaneous.gemspec +7 -12
  73. data/test/fixtures/assets/public1/css/data.css.scss +1 -1
  74. data/test/functional/test_application.rb +15 -0
  75. data/test/functional/test_cli.rb +109 -3
  76. data/test/functional/test_front.rb +108 -10
  77. data/test/test_helper.rb +3 -3
  78. data/test/unit/fields/test_boolean_fields.rb +80 -0
  79. data/test/unit/fields/test_date_fields.rb +47 -0
  80. data/test/unit/fields/test_file_field.rb +210 -0
  81. data/test/unit/{test_images.rb → fields/test_image_fields.rb} +133 -15
  82. data/test/unit/fields/test_location_fields.rb +41 -0
  83. data/test/unit/fields/test_option_fields.rb +61 -0
  84. data/test/unit/fields/test_tag_list_fields.rb +45 -0
  85. data/test/unit/fields/test_text_fields.rb +124 -0
  86. data/test/unit/fields/test_web_video_fields.rb +198 -0
  87. data/test/unit/test_assets.rb +22 -22
  88. data/test/unit/test_boxes.rb +34 -13
  89. data/test/unit/test_changesets.rb +1 -0
  90. data/test/unit/test_extensions.rb +17 -0
  91. data/test/unit/test_fields.rb +20 -643
  92. data/test/unit/test_media.rb +9 -9
  93. data/test/unit/test_page.rb +47 -0
  94. data/test/unit/test_publishing_pipeline.rb +2 -2
  95. data/test/unit/test_serialisation.rb +37 -0
  96. data/test/unit/test_storage.rb +42 -3
  97. metadata +37 -17
@@ -53,6 +53,12 @@ module Spontaneous
53
53
  def export(user)
54
54
  {}
55
55
  end
56
+
57
+ # Allows for field type classes to map a human readable default value
58
+ # to the correct serialized value
59
+ def make_default_value(instance, value)
60
+ value
61
+ end
56
62
  end
57
63
 
58
64
  extend ClassMethods
@@ -380,6 +386,10 @@ module Spontaneous
380
386
  self.prototype.owner
381
387
  end
382
388
 
389
+ def site
390
+ owner.try(:site)
391
+ end
392
+
383
393
  def owner_sid
384
394
  schema_owner.schema_id
385
395
  end
@@ -7,6 +7,12 @@ module Spontaneous::Field
7
7
  class File < Base
8
8
  has_editor
9
9
 
10
+ def blank?
11
+ values[:path].blank?
12
+ end
13
+
14
+ alias_method :empty?, :blank?
15
+
10
16
  # In the case of clearing the field we will have been given a pending_value of ""
11
17
  # we don't want that to run asynchronously
12
18
  def asynchronous?
@@ -15,7 +21,7 @@ module Spontaneous::Field
15
21
  end
16
22
 
17
23
  def outputs
18
- [:html, :path, :filesize, :filename]
24
+ [:html, :path, :filesize, :filename, :storage_name]
19
25
  end
20
26
 
21
27
  def set_pending_value(value, site)
@@ -115,6 +121,17 @@ module Spontaneous::Field
115
121
  generate_path(input, site)
116
122
  end
117
123
 
124
+ def generate_storage_name(input, site)
125
+ if (storage = input.try(:storage))
126
+ return storage.name
127
+ end
128
+ nil
129
+ end
130
+
131
+ def storage
132
+ site.storage(storage_name)
133
+ end
134
+
118
135
  def export(user = nil)
119
136
  super(user).merge({
120
137
  :processed_value => processed_values
@@ -133,8 +150,21 @@ module Spontaneous::Field
133
150
  @file_info ||= Spontaneous::JSON.parse(unprocessed_value)
134
151
  end
135
152
 
153
+ def value(format = :html)
154
+ case format
155
+ when :html, "html"
156
+ path
157
+ else
158
+ super
159
+ end
160
+ end
161
+
136
162
  def path
137
- value(:html)
163
+ storage.to_url(super)
164
+ end
165
+
166
+ def url
167
+ path
138
168
  end
139
169
 
140
170
  self.register
@@ -46,12 +46,26 @@ module Spontaneous::Field
46
46
  [ {}, proc { width 300 } ]
47
47
  end
48
48
 
49
+ def self.default_attributes
50
+ @default_attributes ||= {}
51
+ end
52
+
53
+ def self.default_attributes=(default_attributes = {})
54
+ @default_attributes = default_attributes
55
+ end
56
+
49
57
  def image?
50
58
  true
51
59
  end
52
60
 
61
+ def blank?
62
+ original.blank?
63
+ end
64
+
53
65
  def sizes
54
- @sizes ||= Hash.new { |hash, key| hash[key] = S::Media::Image::Attributes.new(processed_values[key]) }
66
+ @sizes ||= Hash.new { |hash, key|
67
+ hash[key] = S::Media::Image::Attributes.new(site, processed_values[key])
68
+ }
55
69
  end
56
70
 
57
71
  # value used to show conflicts between the current value and the value they're attempting to enter
@@ -93,6 +107,10 @@ module Spontaneous::Field
93
107
  original.src
94
108
  end
95
109
 
110
+ def url
111
+ original.url
112
+ end
113
+
96
114
  def filepath
97
115
  unprocessed_value
98
116
  end
@@ -122,8 +140,12 @@ module Spontaneous::Field
122
140
 
123
141
 
124
142
  def export(user = nil)
143
+ processed = Hash[outputs.map { |size|
144
+ [size, sizes[size].export(user)]
145
+ }]
146
+ processed.update(__pending__: pending_value) if has_pending_value?
125
147
  super(user).merge({
126
- :processed_value => processed_values
148
+ processed_value: processed
127
149
  })
128
150
  end
129
151
 
@@ -78,6 +78,14 @@ module Spontaneous::Field
78
78
  end
79
79
  end
80
80
 
81
+ # Maps a configured default value to the appropriate JSON encoded [value, label] array
82
+ def self.make_default_value(instance, value)
83
+ return nil if value.blank?
84
+ option = option_list(instance.owner).detect { |opt, label| opt == value }
85
+ return nil if option.nil?
86
+ Spontaneous::JSON.encode option
87
+ end
88
+
81
89
  def option_list
82
90
  self.class.option_list(self.owner)
83
91
  end
@@ -75,6 +75,10 @@ module Spontaneous::Field
75
75
  hash[k] = 0 if v == false
76
76
  }
77
77
  end
78
+
79
+ def name
80
+ self.class.id
81
+ end
78
82
  end
79
83
 
80
84
  def self.providers
@@ -151,6 +155,10 @@ module Spontaneous::Field
151
155
  src
152
156
  end
153
157
 
158
+ def aspect_ratio
159
+ values.fetch(:width, 1).to_f / values.fetch(:height, 1).to_f
160
+ end
161
+
154
162
  self.register(:webvideo)
155
163
  end
156
164
  end
@@ -0,0 +1,55 @@
1
+ # The following controls the default render output or image fields.
2
+ #
3
+ # By default inserting an image field instance into a template like this:
4
+ #
5
+ # ${ image }
6
+ #
7
+ # will output an `img` tag with the image's `src` attribute and an empty `alt`
8
+ # value:
9
+ #
10
+ # <img src="/path/to/image.jpg" alt="" />
11
+ #
12
+ # You can override the default attributes by setting an options hash here:
13
+ #
14
+ Spontaneous::Field::Image.default_attributes = {
15
+ # Include the image's natural width & height by default when rendering an image field
16
+ # size: true,
17
+
18
+ # Include only the images’ natural width
19
+ # `true`, `:auto` or `'auto'` are equivalent
20
+
21
+ # width: true,
22
+
23
+ # Force all images to render at a fixed width (odd but possible)
24
+
25
+ # width: 42,
26
+
27
+ # Or the same for the image height:
28
+
29
+ # height: true,
30
+ # height: 42,
31
+
32
+ # Set a default alt attribute (not generally recommended)
33
+
34
+ # alt: 'Inappropriate',
35
+
36
+ # Or, more usefully, if you want to use a dynamic value based on the field
37
+ # being rendered then pass a proc
38
+
39
+ # alt: proc { |field| field.page.title },
40
+
41
+ # Or you can set any attribute you want by just adding it in here:
42
+
43
+ # crossorigin: 'crossorigin',
44
+
45
+ # If you want to set data attributes then you can pass a hash, e.g. to add a data-id attribute
46
+ # based on the images’ owning page e.g.
47
+ #
48
+ # <img src="..." alt="..." data-id="1234" />
49
+ #
50
+ # You would set a data attribute thusly:
51
+
52
+ # data: {
53
+ # id: proc { |field| field.owner.page.id }
54
+ # },
55
+ }
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'yajl'
3
+ # require 'yajl'
4
+ require 'oj'
4
5
 
5
6
  Oj.default_options = { mode: :compat } if defined?(Oj)
6
7
 
@@ -23,7 +24,7 @@ module Spontaneous
23
24
  if defined?(::Yajl)
24
25
  module YajlParser
25
26
  def parser
26
- Yajl::Parser.new(:symbolize_keys => true)
27
+ Yajl::Parser.new(symbolize_keys: true)
27
28
  end
28
29
  def encoder
29
30
  Yajl::Encoder.new
@@ -136,8 +136,8 @@ module Spontaneous
136
136
  # Setup a new logger with options
137
137
  #
138
138
  def self.setup(options = {})
139
- config_level = (SPOT_LOG_LEVEL || Spontaneous.env || :test).to_sym # need this for SPOT_LOG_LEVEL
140
- config = Config[config_level]
139
+ config_level = (SPOT_LOG_LEVEL || Spontaneous.env || :production).to_sym # need this for SPOT_LOG_LEVEL
140
+ config = Config[config_level] || Config[:production] # default to a production level
141
141
  stream = \
142
142
  if logfile = options[:logfile]
143
143
  FileUtils.mkdir_p(File.dirname(logfile)) unless File.directory?(File.dirname(logfile))
@@ -41,7 +41,7 @@ module Spontaneous::Media
41
41
  end
42
42
 
43
43
  def url
44
- storage.public_url(storage_path)
44
+ storage.url_path(storage_path)
45
45
  end
46
46
 
47
47
  def mimetype
@@ -59,7 +59,7 @@ module Spontaneous::Media
59
59
  end
60
60
 
61
61
  def storage
62
- @storage ||= @site.storage(mimetype)
62
+ @storage ||= @site.storage_for_mimetype(mimetype)
63
63
  end
64
64
 
65
65
  def padded_id
@@ -95,7 +95,7 @@ module Spontaneous::Media
95
95
  end
96
96
 
97
97
  def serialize
98
- { :url => url, :type => mimetype, :filename => filename }
98
+ { url: url, type: mimetype, filename: filename, storage_name: storage.name }
99
99
  end
100
100
  end
101
101
  end
@@ -3,15 +3,19 @@ module Spontaneous::Media
3
3
  class Attributes
4
4
  include Renderable
5
5
 
6
- attr_reader :src, :width, :height, :filesize, :filepath
6
+ attr_reader :storage, :filepath, :storage
7
7
 
8
- def initialize(params={})
9
- params ||= {}
10
- @src, @width, @height, @filesize, @filepath = params.values_at(:src, :width, :height, :filesize, :path)
8
+ def initialize(site, params={})
9
+ @params = params.try(:dup) || {}
10
+ @storage = site.storage(storage_name)
11
11
  end
12
12
 
13
13
  def serialize
14
- { :src => src, :width => width, :height => height, :filesize => filesize }
14
+ { src: src, width: width, height: height, dimensions: dimensions, filesize: filesize, storage_name: storage_name }
15
+ end
16
+
17
+ def export(user = nil)
18
+ serialize.delete_if { |k, v| v.nil? }
15
19
  end
16
20
 
17
21
  def inspect
@@ -19,7 +23,69 @@ module Spontaneous::Media
19
23
  end
20
24
 
21
25
  def blank?
22
- src.blank?
26
+ @params[:src].blank?
27
+ end
28
+
29
+ alias_method :empty?, :blank?
30
+
31
+ def src
32
+ storage.to_url(@params[:src])
33
+ end
34
+
35
+ alias_method :url, :src
36
+
37
+ def storage_name
38
+ @params[:storage_name]
39
+ end
40
+
41
+ def width
42
+ @params[:width]
43
+ end
44
+
45
+ def height
46
+ @params[:height]
47
+ end
48
+
49
+ def filesize
50
+ @params[:filesize]
51
+ end
52
+
53
+ def dimensions
54
+ @params[:dimensions]
55
+ end
56
+
57
+ def filepath
58
+ @params[:path]
59
+ end
60
+
61
+ def src
62
+ storage.to_url(@params[:src])
63
+ end
64
+
65
+ alias_method :url, :src
66
+
67
+ def storage_name
68
+ @params[:storage_name]
69
+ end
70
+
71
+ def width
72
+ @params[:width]
73
+ end
74
+
75
+ def height
76
+ @params[:height]
77
+ end
78
+
79
+ def filesize
80
+ @params[:filesize]
81
+ end
82
+
83
+ def dimensions
84
+ @params[:dimensions]
85
+ end
86
+
87
+ def filepath
88
+ @params[:path]
23
89
  end
24
90
 
25
91
  # Will only work for files in local storage
@@ -14,32 +14,65 @@ module Spontaneous::Media::Image
14
14
 
15
15
  alias_method :render_inline, :render
16
16
 
17
- def to_html(attr={})
18
- default_attr = {
19
- :src => src,
20
- :width => width,
21
- :height => height,
22
- :alt => ""
23
- }
24
- default_attr.delete(:width) if (width.nil? || width == 0)
25
- default_attr.delete(:height) if (height.nil? || height == 0)
17
+ DEFAULT_SIZE_FLAGS = ['auto'.freeze, :auto, true].freeze
18
+
19
+ def to_html(opts={})
20
+ default_attr = { src: src, alt: "" }
21
+ attrs = Spontaneous::Field::Image.default_attributes.merge(opts)
22
+
26
23
  if template_params && template_params.length > 0 && template_params[0].is_a?(Hash)
27
- attr = template_params[0].merge(attr)
24
+ attrs = template_params[0].merge(attrs)
25
+ end
26
+
27
+ case attrs.delete(:size)
28
+ when true, :auto, 'auto'
29
+ attrs[:width] = width if has_width?
30
+ attrs[:height] = height if has_height?
28
31
  end
29
- if attr.key?(:width) || attr.key?(:height)
30
- default_attr.delete(:width)
31
- default_attr.delete(:height)
32
- if (attr.key?(:width) && !attr[:width]) || (attr.key?(:height) && !attr[:height])
33
- attr.delete(:width)
34
- attr.delete(:height)
32
+
33
+ if attrs.key?(:width) || attrs.key?(:height)
34
+ attrs.delete(:width) if (attrs.key?(:width) && !attrs[:width])
35
+ attrs.delete(:height) if (attrs.key?(:height) && !attrs[:height])
36
+ if has_width? && DEFAULT_SIZE_FLAGS.include?(attrs[:width])
37
+ attrs[:width] = width
38
+ end
39
+ if has_height? && DEFAULT_SIZE_FLAGS.include?(attrs[:height])
40
+ attrs[:height] = height
35
41
  end
36
42
  end
37
- attr = default_attr.merge(attr)
43
+
44
+ attrs = default_attr.merge(attrs)
45
+ params = parameterize_attributes(attrs)
46
+ %(<img #{params} />)
47
+ end
48
+
49
+ def parameterize_attributes(attrs, namespace = [])
38
50
  params = []
39
- attr.each do |name, value|
40
- params << %(#{name}="#{value.to_s.escape_html}")
51
+ attrs.each do |name, value|
52
+ key = (namespace + [name])
53
+ v = case value
54
+ when Hash
55
+ parameterize_attributes(value, key)
56
+ when Proc
57
+ %(#{key.join('-')}="#{value.call(self).to_s.escape_html}")
58
+ else
59
+ %(#{key.join('-')}="#{value.to_s.escape_html}")
60
+ end
61
+ params << v
41
62
  end
42
- %(<img #{params.join(' ')} />)
63
+ params.join(' ')
64
+ end
65
+
66
+ def has_height?
67
+ has_dim?(height)
68
+ end
69
+
70
+ def has_width?
71
+ has_dim?(width)
72
+ end
73
+
74
+ def has_dim?(dim)
75
+ !(dim.nil? || dim == 0)
43
76
  end
44
77
 
45
78
  def to_s