spontaneous 0.2.0.beta9 → 0.2.0.beta10

Sign up to get free protection for your applications and to get access to all the features.
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