spontaneous 0.2.0.alpha7 → 0.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (247) hide show
  1. data/Gemfile +10 -4
  2. data/Readme.markdown +1 -1
  3. data/application/css/definitions.css.scss +5 -0
  4. data/application/css/dialogue.css.scss +62 -0
  5. data/application/js/content.js +1 -1
  6. data/application/js/dom.js +1 -1
  7. data/application/js/event_source.js +3 -0
  8. data/application/js/{field_types/date_field.js → field/date.js} +2 -2
  9. data/application/js/{field_types/file_field.js → field/file.js} +2 -2
  10. data/application/js/{field_types/image_field.js → field/image.js} +54 -20
  11. data/application/js/{field_types/long_string_field.js → field/long_string.js} +2 -2
  12. data/application/js/{field_types/markdown_field.js → field/markdown.js} +2 -2
  13. data/application/js/{field_types/select_field.js → field/select.js} +2 -2
  14. data/application/js/{field_types/string_field.js → field/string.js} +21 -7
  15. data/application/js/{field_types/webvideo_field.js → field/webvideo.js} +2 -2
  16. data/application/js/field.js +2 -2
  17. data/application/js/publish.js +99 -19
  18. data/application/js/spontaneous.js +8 -8
  19. data/application/js/top_bar.js +6 -4
  20. data/db/migrations/20130109125023_add_page_publish_lock.rb +17 -0
  21. data/db/migrations/20130111161934_convert_bcrypt_passwords.rb +22 -0
  22. data/db/migrations/20130114120000_create_revision_tables.rb +106 -0
  23. data/db/migrations/20130116220423_add_index_to_archive.rb +9 -0
  24. data/lib/spontaneous/box.rb +53 -18
  25. data/lib/spontaneous/box_style.rb +2 -3
  26. data/lib/spontaneous/change.rb +39 -13
  27. data/lib/spontaneous/cli/fields.rb +29 -0
  28. data/lib/spontaneous/cli/init.rb +2 -2
  29. data/lib/spontaneous/cli/migrate.rb +0 -1
  30. data/lib/spontaneous/cli/server.rb +14 -10
  31. data/lib/spontaneous/cli/site.rb +20 -9
  32. data/lib/spontaneous/cli.rb +8 -6
  33. data/lib/spontaneous/collections/box_set.rb +11 -0
  34. data/lib/spontaneous/collections/field_set.rb +24 -1
  35. data/lib/spontaneous/concern.rb +37 -0
  36. data/lib/spontaneous/config.rb +3 -4
  37. data/lib/spontaneous/crypt/version.rb +130 -0
  38. data/lib/spontaneous/crypt.rb +84 -0
  39. data/lib/spontaneous/data_mapper/content_model/associations.rb +199 -0
  40. data/lib/spontaneous/data_mapper/content_model/column_accessors.rb +52 -0
  41. data/lib/spontaneous/data_mapper/content_model/instance_hooks.rb +34 -0
  42. data/lib/spontaneous/data_mapper/content_model/serialization.rb +54 -0
  43. data/lib/spontaneous/data_mapper/content_model/timestamps.rb +39 -0
  44. data/lib/spontaneous/data_mapper/content_model.rb +343 -0
  45. data/lib/spontaneous/data_mapper/content_table.rb +103 -0
  46. data/lib/spontaneous/data_mapper/dataset.rb +194 -0
  47. data/lib/spontaneous/data_mapper/scope.rb +195 -0
  48. data/lib/spontaneous/data_mapper.rb +161 -0
  49. data/lib/spontaneous/facet.rb +2 -2
  50. data/lib/spontaneous/field/base.rb +418 -0
  51. data/lib/spontaneous/field/date.rb +54 -0
  52. data/lib/spontaneous/{field_version.rb → field/field_version.rb} +1 -1
  53. data/lib/spontaneous/field/file.rb +100 -0
  54. data/lib/spontaneous/{field_types/image_field.rb → field/image.rb} +33 -33
  55. data/lib/spontaneous/{field_types/location_field.rb → field/location.rb} +2 -2
  56. data/lib/spontaneous/{field_types/long_string_field.rb → field/long_string.rb} +3 -3
  57. data/lib/spontaneous/field/markdown.rb +36 -0
  58. data/lib/spontaneous/{field_types/select_field.rb → field/select.rb} +4 -5
  59. data/lib/spontaneous/field/string.rb +17 -0
  60. data/lib/spontaneous/field/update.rb +156 -0
  61. data/lib/spontaneous/field/webvideo.rb +310 -0
  62. data/lib/spontaneous/field.rb +80 -0
  63. data/lib/spontaneous/generators/site/Gemfile.tt +2 -2
  64. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +1 -1
  65. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +1 -1
  66. data/lib/spontaneous/generators/site/lib/content.rb.tt +6 -0
  67. data/lib/spontaneous/generators/site/schema/box.rb.tt +3 -2
  68. data/lib/spontaneous/generators/site/schema/page.rb.tt +3 -1
  69. data/lib/spontaneous/generators/site/schema/piece.rb.tt +3 -1
  70. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +3 -1
  71. data/lib/spontaneous/generators/site.rb +4 -3
  72. data/lib/spontaneous/image_size.rb +8 -1
  73. data/lib/spontaneous/layout.rb +5 -1
  74. data/lib/spontaneous/loader.rb +2 -5
  75. data/lib/spontaneous/media/file.rb +11 -2
  76. data/lib/spontaneous/media/temp_file.rb +23 -0
  77. data/lib/spontaneous/media.rb +20 -39
  78. data/lib/spontaneous/{plugins → model/box}/allowed_types.rb +38 -17
  79. data/lib/spontaneous/model/box.rb +18 -0
  80. data/lib/spontaneous/{plugins → model/core}/aliases.rb +10 -14
  81. data/lib/spontaneous/{plugins → model/core}/boxes.rb +2 -2
  82. data/lib/spontaneous/{plugins → model/core}/content_groups.rb +2 -2
  83. data/lib/spontaneous/model/core/editor_class.rb +4 -0
  84. data/lib/spontaneous/{plugins → model/core}/entries.rb +19 -7
  85. data/lib/spontaneous/{plugins → model/core}/entry.rb +3 -3
  86. data/lib/spontaneous/{plugins → model/core}/fields.rb +38 -5
  87. data/lib/spontaneous/{plugins → model/core}/instance_code.rb +2 -2
  88. data/lib/spontaneous/{plugins → model/core}/media.rb +2 -12
  89. data/lib/spontaneous/{plugins → model/core}/modifications.rb +7 -6
  90. data/lib/spontaneous/model/core/page_search.rb +36 -0
  91. data/lib/spontaneous/{plugins → model/core}/permissions.rb +4 -4
  92. data/lib/spontaneous/{plugins → model/core}/prototypes.rb +4 -4
  93. data/lib/spontaneous/{plugins → model/core}/publishing.rb +93 -115
  94. data/lib/spontaneous/{plugins → model/core}/render.rb +2 -2
  95. data/lib/spontaneous/{plugins → model/core}/schema_hierarchy.rb +7 -11
  96. data/lib/spontaneous/model/core/schema_id.rb +65 -0
  97. data/lib/spontaneous/{plugins → model/core}/schema_title.rb +2 -2
  98. data/lib/spontaneous/{plugins → model/core}/serialisation.rb +2 -2
  99. data/lib/spontaneous/{plugins → model/core}/styles.rb +2 -2
  100. data/lib/spontaneous/{plugins → model/core}/supertype.rb +2 -2
  101. data/lib/spontaneous/{plugins → model/core}/visibility.rb +7 -48
  102. data/lib/spontaneous/model/core.rb +143 -0
  103. data/lib/spontaneous/{plugins → model/page}/controllers.rb +3 -3
  104. data/lib/spontaneous/{plugins → model}/page/formats.rb +2 -2
  105. data/lib/spontaneous/{plugins → model/page}/layouts.rb +2 -2
  106. data/lib/spontaneous/model/page/locks.rb +14 -0
  107. data/lib/spontaneous/{plugins → model/page}/page_tree.rb +3 -3
  108. data/lib/spontaneous/{plugins → model/page}/paths.rb +30 -12
  109. data/lib/spontaneous/{plugins → model}/page/request.rb +2 -2
  110. data/lib/spontaneous/{plugins → model/page}/site_map.rb +2 -2
  111. data/lib/spontaneous/model/page/site_timestamps.rb +44 -0
  112. data/lib/spontaneous/{page.rb → model/page.rb} +49 -28
  113. data/lib/spontaneous/{piece.rb → model/piece.rb} +7 -6
  114. data/lib/spontaneous/model.rb +97 -0
  115. data/lib/spontaneous/output/context.rb +1 -1
  116. data/lib/spontaneous/output/format.rb +4 -0
  117. data/lib/spontaneous/output/template/renderer.rb +2 -2
  118. data/lib/spontaneous/output.rb +2 -2
  119. data/lib/spontaneous/page_lock.rb +62 -0
  120. data/lib/spontaneous/page_piece.rb +1 -1
  121. data/lib/spontaneous/permissions/access_key.rb +9 -4
  122. data/lib/spontaneous/permissions/user.rb +19 -9
  123. data/lib/spontaneous/permissions.rb +2 -5
  124. data/lib/spontaneous/plugins/application/facets.rb +1 -2
  125. data/lib/spontaneous/plugins/application/features.rb +1 -1
  126. data/lib/spontaneous/plugins/application/paths.rb +1 -1
  127. data/lib/spontaneous/plugins/application/render.rb +1 -1
  128. data/lib/spontaneous/plugins/application/serialisation.rb +1 -1
  129. data/lib/spontaneous/plugins/application/state.rb +30 -1
  130. data/lib/spontaneous/plugins/application/system.rb +12 -12
  131. data/lib/spontaneous/prototypes/box_prototype.rb +1 -1
  132. data/lib/spontaneous/prototypes/field_prototype.rb +3 -6
  133. data/lib/spontaneous/prototypes/style_prototype.rb +1 -1
  134. data/lib/spontaneous/publishing/immediate.rb +77 -49
  135. data/lib/spontaneous/publishing/revision.rb +355 -0
  136. data/lib/spontaneous/publishing/simultaneous.rb +10 -49
  137. data/lib/spontaneous/publishing.rb +1 -0
  138. data/lib/spontaneous/rack/around_back.rb +1 -1
  139. data/lib/spontaneous/rack/around_front.rb +2 -4
  140. data/lib/spontaneous/rack/around_preview.rb +1 -1
  141. data/lib/spontaneous/rack/back.rb +80 -63
  142. data/lib/spontaneous/rack/cacheable_file.rb +2 -2
  143. data/lib/spontaneous/rack/cookie_authentication.rb +1 -1
  144. data/lib/spontaneous/rack/front.rb +1 -1
  145. data/lib/spontaneous/rack/helpers.rb +8 -9
  146. data/lib/spontaneous/{page_controller.rb → rack/page_controller.rb} +1 -1
  147. data/lib/spontaneous/rack/public.rb +3 -3
  148. data/lib/spontaneous/rack.rb +15 -15
  149. data/lib/spontaneous/schema/uid.rb +4 -1
  150. data/lib/spontaneous/schema.rb +57 -24
  151. data/lib/spontaneous/search/database.rb +12 -1
  152. data/lib/spontaneous/search/index.rb +34 -6
  153. data/lib/spontaneous/search/results.rb +1 -1
  154. data/lib/spontaneous/server.rb +3 -3
  155. data/lib/spontaneous/simultaneous.rb +53 -0
  156. data/lib/spontaneous/{plugins/site → site}/features.rb +2 -2
  157. data/lib/spontaneous/{plugins/site → site}/helpers.rb +2 -3
  158. data/lib/spontaneous/{plugins/site → site}/hooks.rb +2 -2
  159. data/lib/spontaneous/{plugins/site → site}/instance.rb +4 -6
  160. data/lib/spontaneous/{plugins/site → site}/level.rb +2 -2
  161. data/lib/spontaneous/{plugins/site → site}/map.rb +4 -4
  162. data/lib/spontaneous/{plugins/site → site}/paths.rb +2 -2
  163. data/lib/spontaneous/site/publishing.rb +89 -0
  164. data/lib/spontaneous/{plugins/site → site}/schema.rb +4 -4
  165. data/lib/spontaneous/{plugins/site → site}/search.rb +2 -2
  166. data/lib/spontaneous/{plugins/site → site}/selectors.rb +15 -7
  167. data/lib/spontaneous/{plugins/site → site}/state.rb +2 -2
  168. data/lib/spontaneous/{plugins/site → site}/storage.rb +2 -2
  169. data/lib/spontaneous/{plugins/site → site}/url.rb +2 -2
  170. data/lib/spontaneous/site.rb +31 -14
  171. data/lib/spontaneous/state.rb +5 -6
  172. data/lib/spontaneous/style.rb +3 -2
  173. data/lib/spontaneous/utils/database/mysql_dumper.rb +13 -0
  174. data/lib/spontaneous/utils/database/postgres_dumper.rb +5 -0
  175. data/lib/spontaneous/version.rb +1 -1
  176. data/lib/spontaneous.rb +34 -89
  177. data/spontaneous.gemspec +112 -114
  178. data/test/experimental/test_crypt.rb +158 -0
  179. data/test/experimental/test_features.rb +3 -3
  180. data/test/fixtures/example_application/config/environments/development.rb +1 -1
  181. data/test/fixtures/example_application/lib/content.rb +5 -0
  182. data/test/fixtures/example_application/schema/page.rb +2 -1
  183. data/test/fixtures/example_application/schema/piece.rb +3 -2
  184. data/test/fixtures/serialisation/class_hash.yaml.erb +5 -5
  185. data/test/fixtures/serialisation/root_hash.yaml.erb +8 -0
  186. data/test/functional/test_application.rb +12 -1
  187. data/test/functional/test_back.rb +80 -48
  188. data/test/functional/test_front.rb +39 -46
  189. data/test/functional/test_user_manager.rb +3 -9
  190. data/test/javascript/test_markdown.rb +2 -2
  191. data/test/test_helper.rb +78 -23
  192. data/test/unit/test_alias.rb +21 -15
  193. data/test/unit/test_asset_bundler.rb +3 -3
  194. data/test/unit/test_assets.rb +2 -2
  195. data/test/unit/test_async.rb +7 -6
  196. data/test/unit/test_authentication.rb +43 -37
  197. data/test/unit/test_boxes.rb +46 -21
  198. data/test/unit/test_changesets.rb +65 -20
  199. data/test/unit/test_config.rb +9 -9
  200. data/test/unit/test_content.rb +50 -51
  201. data/test/unit/test_content_inheritance.rb +6 -20
  202. data/test/unit/test_datamapper.rb +1330 -0
  203. data/test/unit/test_datamapper_content.rb +214 -0
  204. data/test/unit/test_fields.rb +543 -54
  205. data/test/unit/test_formats.rb +2 -3
  206. data/test/unit/test_generators.rb +6 -6
  207. data/test/unit/test_helpers.rb +1 -1
  208. data/test/unit/test_image_size.rb +10 -5
  209. data/test/unit/test_images.rb +17 -18
  210. data/test/unit/test_layouts.rb +18 -3
  211. data/test/unit/test_media.rb +74 -49
  212. data/test/unit/test_modifications.rb +43 -43
  213. data/test/unit/test_page.rb +7 -10
  214. data/test/unit/test_permissions.rb +3 -10
  215. data/test/unit/test_piece.rb +5 -6
  216. data/test/unit/test_plugins.rb +7 -14
  217. data/test/unit/test_prototypes.rb +3 -3
  218. data/test/unit/test_publishing.rb +49 -27
  219. data/test/unit/test_render.rb +46 -15
  220. data/test/unit/test_revisions.rb +124 -127
  221. data/test/unit/test_schema.rb +53 -58
  222. data/test/unit/test_search.rb +64 -16
  223. data/test/unit/test_serialisation.rb +4 -11
  224. data/test/unit/test_site.rb +11 -12
  225. data/test/unit/test_structure.rb +2 -5
  226. data/test/unit/test_styles.rb +22 -24
  227. data/test/unit/test_type_hierarchy.rb +7 -5
  228. data/test/unit/test_visibility.rb +79 -55
  229. metadata +128 -102
  230. data/lib/sequel/plugins/content_table_inheritance.rb +0 -203
  231. data/lib/sequel/plugins/scoped_table_name.rb +0 -54
  232. data/lib/spontaneous/content.rb +0 -129
  233. data/lib/spontaneous/field_types/date_field.rb +0 -56
  234. data/lib/spontaneous/field_types/field.rb +0 -302
  235. data/lib/spontaneous/field_types/file_field.rb +0 -68
  236. data/lib/spontaneous/field_types/markdown_field.rb +0 -38
  237. data/lib/spontaneous/field_types/string_field.rb +0 -19
  238. data/lib/spontaneous/field_types/webvideo_field.rb +0 -313
  239. data/lib/spontaneous/field_types.rb +0 -38
  240. data/lib/spontaneous/generators/site/lib/site.rb.tt +0 -4
  241. data/lib/spontaneous/plugins/field/editor_class.rb +0 -13
  242. data/lib/spontaneous/plugins/page/site_timestamps.rb +0 -28
  243. data/lib/spontaneous/plugins/page_search.rb +0 -63
  244. data/lib/spontaneous/plugins/schema_id.rb +0 -68
  245. data/lib/spontaneous/plugins/site/publishing.rb +0 -75
  246. data/lib/spontaneous/rack/fiber_pool.rb +0 -26
  247. data/test/unit/test_table_scoping.rb +0 -80
@@ -4,8 +4,7 @@ require 'tempfile'
4
4
  require 'mini_magick'
5
5
  require 'delegate'
6
6
 
7
- module Spontaneous
8
- module FieldTypes
7
+ module Spontaneous::Field
9
8
 
10
9
  class ImageOptimizer
11
10
  def self.run(source_image)
@@ -63,7 +62,7 @@ module Spontaneous
63
62
 
64
63
  def render(format=:html, *args)
65
64
  case format
66
- when :html
65
+ when "html", :html
67
66
  to_html(*args)
68
67
  else
69
68
  value
@@ -108,8 +107,8 @@ module Spontaneous
108
107
  end
109
108
  end
110
109
 
111
- class ImageField < Field
112
- include Spontaneous::Plugins::Field::EditorClass
110
+ class Image < File
111
+ has_editor
113
112
  include ImageFieldUtilities
114
113
 
115
114
  def self.accepts
@@ -137,7 +136,13 @@ module Spontaneous
137
136
  end
138
137
 
139
138
  def self.size_definitions
140
- @size_definitions ||= superclass.respond_to?(:size_definitions) ? superclass.size_definitions.dup : {}
139
+ @size_definitions ||= superclass.respond_to?(:size_definitions) ? superclass.size_definitions.dup : { :__ui__ => ui_preview_size }
140
+ end
141
+
142
+ def self.ui_preview_size
143
+ Proc.new {
144
+ width 300
145
+ }
141
146
  end
142
147
 
143
148
  def image?
@@ -153,6 +158,16 @@ module Spontaneous
153
158
  value
154
159
  end
155
160
 
161
+ def serialize_pending_file(file)
162
+ attrs = ImageProcessor.new(file).serialize
163
+ attrs.delete(:path)
164
+ attrs.merge(super)
165
+ end
166
+
167
+ def page_lock_description
168
+ "Processing image '#{pending_value[:value][:filename]}'"
169
+ end
170
+
156
171
  # original is special and should always be defined
157
172
  def original
158
173
  @original ||= sizes[:original]
@@ -180,15 +195,20 @@ module Spontaneous
180
195
 
181
196
  # formats are irrelevant to image/file fields
182
197
  def outputs
183
- [:original].concat(self.class.size_definitions.map { |name, process| name })
198
+ [:original, :__ui__].concat(self.class.size_definitions.map { |name, process| name })
184
199
  end
185
200
 
186
201
  def value(format=:html, *args)
187
202
  sizes[:original].src
188
203
  end
189
204
 
205
+ def set_value!(value, process = true)
206
+ @sizes = nil
207
+ super
208
+ end
209
+
190
210
  def generate(output, media_file)
191
- return { :src => media_file } if media_file.is_a?(String)#File.exist?(image_path)
211
+ return { :src => media_file } if media_file.is_a?(::String)#File.exist?(image_path)
192
212
  image = ImageProcessor.new(media_file)
193
213
  # Create a tempfile here that will be kept open for the duration of the block
194
214
  # this is used in #apply to hold a copy of the processed image data rather than
@@ -205,32 +225,14 @@ module Spontaneous
205
225
  result.serialize
206
226
  end
207
227
 
208
- def preprocess(image_path)
209
- filename = mimetype = nil
210
- case image_path
211
- when Hash
212
- mimetype = image_path[:type]
213
- filename = image_path[:filename]
214
- image_path = image_path[:tempfile].path
215
- when String
216
- # return image_path unless File.exist?(image_path)
217
- filename = ::File.basename(image_path)
218
- end
219
- return image_path unless File.exist?(image_path)
220
- # media_path = owner.make_media_file(image_path, filename)
221
- media_file = Spontaneous::Media::File.new(owner, filename, mimetype)
222
- media_file.copy(image_path)
223
- set_unprocessed_value(File.expand_path(media_file.filepath))
224
- # media_path
225
- # image_path
226
- media_file
227
- end
228
228
 
229
229
  def export(user = nil)
230
230
  super(user).merge({
231
231
  :processed_value => processed_values
232
232
  })
233
233
  end
234
+
235
+ self.register(:image, :photo)
234
236
  end
235
237
 
236
238
 
@@ -314,7 +316,7 @@ module Spontaneous
314
316
  end
315
317
 
316
318
  def composite(other_image_path, output_extension = "jpg", &block)
317
- File.open(other_image_path) do |other_image|
319
+ ::File.open(other_image_path) do |other_image|
318
320
  new_image = image.composite(other_image, output_extension, &block)
319
321
  image.path = new_image.path
320
322
  end
@@ -398,7 +400,7 @@ module Spontaneous
398
400
  end
399
401
 
400
402
  def filesize
401
- File.size(path)
403
+ ::File.size(path)
402
404
  end
403
405
 
404
406
  def width
@@ -446,7 +448,7 @@ module Spontaneous
446
448
  :width => width,
447
449
  :height => height,
448
450
  :filesize => filesize,
449
- :path => path
451
+ :path => @media_file.path
450
452
  }
451
453
  end
452
454
 
@@ -455,7 +457,5 @@ module Spontaneous
455
457
  end
456
458
  end
457
459
 
458
- ImageField.register(:image, :photo)
459
460
 
460
- end
461
461
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'open-uri'
4
4
 
5
- module Spontaneous::FieldTypes
6
- class LocationField < StringField
5
+ module Spontaneous::Field
6
+ class Location < String
7
7
 
8
8
  def outputs
9
9
  [:html, :lat, :lng]
@@ -1,8 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Spontaneous::FieldTypes
4
- class LongStringField < Field
5
- include Spontaneous::Plugins::Field::EditorClass
3
+ module Spontaneous::Field
4
+ class LongString < Base
5
+ has_editor
6
6
 
7
7
  def generate_html(value)
8
8
  escape_html(value).gsub(/[\r\n]+/, "<br />")
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'kramdown'
4
+
5
+ module Spontaneous::Field
6
+ class Markdown < Base
7
+ has_editor
8
+
9
+ def outputs
10
+ [:html]
11
+ end
12
+
13
+ def generate_html(input)
14
+ input.to_html
15
+ end
16
+
17
+ def preprocess(input)
18
+ # convert lines ending with newlines into a <br/>
19
+ # as official Markdown syntax isn't suitable for
20
+ # casual users
21
+ # code taken from:
22
+ # http://github.github.com/github-flavored-markdown/
23
+ output = input.gsub(/^[\w\<][^\n]*\n+/) do |x|
24
+ x =~ /\n{2}/ ? x : (x.strip!; x << " \n")
25
+ end
26
+
27
+ # prevent foo_bar_baz from ending up with an italic word in the middle
28
+ output.gsub!(/(^(?! {4}|\t)\w+_\w+_\w[\w_]*)/) do |x|
29
+ x.gsub('_', '\_') if x.split('').sort.to_s[0..1] == '__'
30
+ end
31
+ Kramdown::Document.new(output)
32
+ end
33
+
34
+ self.register(:markdown, :text, :richtext)
35
+ end
36
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Spontaneous::FieldTypes
3
+ module Spontaneous::Field
4
4
  # Provides a select field in the UI.
5
5
  #
6
6
  # Options for the select are provided by passing an :options value in the field config.
@@ -35,8 +35,8 @@ module Spontaneous::FieldTypes
35
35
  # To retrieve the associated label use `field.value(:label)` or `field.label`
36
36
  # ("Value 1" or "Value 2" in the exampel above).
37
37
  #
38
- class SelectField < Field
39
- include Spontaneous::Plugins::Field::EditorClass
38
+ class Select < Base
39
+ has_editor
40
40
 
41
41
  def self.static_option_list?
42
42
  return false if configured_option_list.is_a?(Proc)
@@ -104,6 +104,5 @@ module Spontaneous::FieldTypes
104
104
  end
105
105
 
106
106
  self.register
107
- end # OptionsField
107
+ end # Select
108
108
  end
109
-
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Field
4
+ class String < Base
5
+ has_editor
6
+
7
+ def preprocess(value)
8
+ Spontaneous::Utils::SmartQuotes.smarten(value.to_s)
9
+ end
10
+
11
+ def generate_html(value)
12
+ escape_html(value)
13
+ end
14
+
15
+ self.register :string, :title
16
+ end
17
+ end
@@ -0,0 +1,156 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Field
4
+
5
+ class Update
6
+ def self.perform(fields, user, asynchronous = false)
7
+ self.new(fields, user).run(asynchronous)
8
+ end
9
+
10
+
11
+ def self.asynchronous_update_class
12
+ Spontaneous::Site.resolve_background_mode(self)
13
+ end
14
+
15
+ def initialize(fields, user)
16
+ @fields, @user = fields, user
17
+ end
18
+
19
+ def run(asynchronous = false)
20
+ fields.each do |field, value|
21
+ field.pending_value = value
22
+ end
23
+
24
+ immediate, asynchronous = partition_fields(asynchronous)
25
+
26
+ Immediate.process(immediate)
27
+
28
+ launch_asynchronous_update(asynchronous)
29
+ end
30
+
31
+ def partition_fields(asynchronous)
32
+ fields = self.fields.keys
33
+ return [fields, []] unless asynchronous
34
+ filter = proc { |f| f.asynchronous? }
35
+ async = fields.select(&filter)
36
+ immediate = fields.reject(&filter)
37
+ [immediate, async]
38
+ end
39
+
40
+ def fields
41
+ writable_fields
42
+ end
43
+
44
+ def owners(fields)
45
+ fields.map(&:owner).uniq
46
+ end
47
+
48
+ def writable_fields
49
+ @fields.reject { |f, v| !f.writable?(@user)}
50
+ end
51
+
52
+ def launch_asynchronous_update(fields)
53
+ return if fields.empty?
54
+ # Keep the saving command here rather than in the field
55
+ # because all the fields most probably belong to
56
+ # the same owner
57
+ owners(fields).each(&:save_fields)
58
+ fields.each do |field|
59
+ prepare_asynchronous_update(field)
60
+ end
61
+ updater = self.class.asynchronous_update_class
62
+ updater.process(fields)
63
+ end
64
+
65
+ def prepare_asynchronous_update(field)
66
+ field.before_asynchronous_update
67
+ Spontaneous::PageLock.lock_field(field)
68
+ end
69
+
70
+ class Immediate
71
+ def self.process(fields)
72
+ self.new(fields).run
73
+ end
74
+
75
+ def initialize(fields)
76
+ @fields = Array(fields)
77
+ end
78
+
79
+ def run
80
+ @fields.each do |field|
81
+ field.process_pending_value
82
+ end
83
+ save
84
+ end
85
+
86
+ # This is made more complex by the need to verify that:
87
+ #
88
+ # a. this update has not been superceded by a more recent one and
89
+ # b. other fields on the owner have not been updated synchronously since
90
+ # this update was launched.
91
+ #
92
+ # (a) is verified by only saving fields that pass the #validate_update!
93
+ # test.
94
+ #
95
+ # (b) by calling Content#save_fields on a reloaded version of the owner
96
+ # and by the fact that only the fields that have been modified by this
97
+ # updater are re-serialized.
98
+ #
99
+ def save
100
+ valid_fields = @fields.reject { |field| field.conflicted_update? }
101
+ remove_update_lock(valid_fields)
102
+ field_map = valid_fields.group_by { |f| f.owner }
103
+ field_map.each do |owner, fields|
104
+ reload(owner).save_fields(fields)
105
+ end
106
+ end
107
+
108
+ # We need to save against a fresh version of the owning content
109
+ # because with long-running updates (video transcoding for example)
110
+ # it's quite likely that some non-asynchronous fields have been modified
111
+ # during the processing period.
112
+ #
113
+ # The #save_fields method only re-serializes the fields it's passed
114
+ # so we can update the fields we have updated without over-writing the db
115
+ # versions of any other fields.
116
+ def reload(owner)
117
+ Spontaneous::Content.scope! do
118
+ o = Spontaneous::Content.get(owner.content_instance.id)
119
+ return o.boxes[owner.box_name] if Spontaneous::Box === owner
120
+ o
121
+ end
122
+ end
123
+
124
+
125
+ def remove_update_lock(fields)
126
+ fields.each do |field|
127
+ Spontaneous::PageLock.unlock_field(field)
128
+ end
129
+ end
130
+
131
+ def owners
132
+ @fields.map(&:owner).uniq.compact
133
+ end
134
+
135
+ # Load these everytime to ensure they are updated with their
136
+ # correct lock status
137
+ def pages
138
+ page_ids = owners.map(&:page).uniq.compact.map(&:id)
139
+ page_ids.map { |id| Spontaneous::Content.get(id) }
140
+ end
141
+ end
142
+
143
+ class Simultaneous < Immediate
144
+ def run
145
+ params = { "fields" => @fields.map { |f| f.id } }
146
+ begin
147
+ Spontaneous::Simultaneous.fire(:update_fields, params)
148
+ rescue Spontaneous::Simultaneous::Error
149
+ Immediate.process(@fields)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ Spontaneous::Simultaneous.register(:update_fields, "field update", :logfile => "log/fields.log")