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
@@ -0,0 +1,310 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'open-uri'
4
+ require 'nokogiri'
5
+
6
+ module Spontaneous::Field
7
+ class WebVideo < Base
8
+ has_editor
9
+
10
+ def outputs
11
+ [:type, :id]
12
+ end
13
+
14
+ def id
15
+ value(:id)
16
+ end
17
+
18
+ def video_type
19
+ value(:type)
20
+ end
21
+
22
+
23
+ def generate_outputs(input)
24
+ values = {}
25
+ values[:html] = escape_html(input)
26
+ case input
27
+ when "", nil
28
+ # ignore this
29
+ when /youtube\.com.*\?.*v=([^&]+)/, /youtu.be\/([^&]+)/
30
+ id = $1
31
+ values.update(retrieve_youtube_metadata(id))
32
+ values[:id] = id
33
+ values[:type] = "youtube"
34
+ when /vimeo\.com\/(\d+)/
35
+ id = $1
36
+ values[:type] = "vimeo"
37
+ values.update(retrieve_vimeo_metadata(id))
38
+ values[:id] = id.to_s
39
+ else
40
+ logger.warn "WebVideo field doesn't recognise the URL '#{input}'"
41
+ end
42
+ values
43
+ end
44
+
45
+
46
+ def render(format=:html, *args)
47
+ case format
48
+ when :html
49
+ to_html(*args)
50
+ when :json
51
+ to_json(*args)
52
+ else
53
+ value(format)
54
+ end
55
+ end
56
+
57
+
58
+ def to_html(*args)
59
+ opts = args.extract_options!
60
+ case video_type
61
+ when "youtube"
62
+ to_youtube_html(opts)
63
+ when "vimeo"
64
+ to_vimeo_html(opts)
65
+ else
66
+ value(:html)
67
+ end
68
+ end
69
+
70
+
71
+ def to_json(*args)
72
+ opts = args.extract_options!
73
+ params = \
74
+ case video_type
75
+ when "youtube"
76
+ youtube_attributes(opts)
77
+ when "vimeo"
78
+ vimeo_attributes(opts)
79
+ else
80
+ {:tagname => "iframe", :tag => "<iframe/>", :attr => {:src => value(:html)}}
81
+ end
82
+ Spontaneous.encode_json(params)
83
+ end
84
+
85
+ def src(opts = {})
86
+ case video_type
87
+ when "youtube"
88
+ youtube_src(opts)
89
+ when "vimeo"
90
+ vimeo_src(opts)
91
+ else
92
+ value(:html)
93
+ end
94
+ end
95
+
96
+ def ui_preview_value
97
+ # render(:html, :width => 480, :height => 270)
98
+ src
99
+ end
100
+
101
+ def retrieve_vimeo_metadata(id)
102
+ url = "http://vimeo.com/api/v2/video/%s.json" % id
103
+ response = \
104
+ begin
105
+ open(url).read
106
+ rescue => e
107
+ logger.error("Unable to retrieve metadata for video ##{id} from Vimeo: '#{e}'")
108
+ "[{}]"
109
+ end
110
+ metadata = Spontaneous.parse_json(response) rescue [{}]
111
+ metadata = metadata.first || {}
112
+ end
113
+
114
+ def retrieve_youtube_metadata(id)
115
+ url = "http://gdata.youtube.com/feeds/api/videos/%s?v=2" % id
116
+ begin
117
+ doc = Nokogiri::XML(open(url))
118
+ entry = doc.xpath("xmlns:entry")
119
+
120
+ { "title" => entry.xpath("xmlns:title").text.strip,
121
+ "description" => entry.xpath("media:group/media:description").text.strip,
122
+ "thumbnail_large" => entry.xpath('media:group/media:thumbnail[@yt:name="hqdefault"]').first["url"].strip,
123
+ "thumbnail_small" => entry.xpath('media:group/media:thumbnail[@yt:name="default"]').first["url"].strip,
124
+ "user_name" => entry.xpath("xmlns:author/xmlns:name").text.strip,
125
+ "upload_date" => Time.parse(entry.xpath("xmlns:published").text.strip).strftime("%Y-%m-%d %H:%M:%S"),
126
+ "tags" => entry.xpath("media:group/media:keywords").text.strip,
127
+ "duration" => entry.xpath("media:group/yt:duration").first['seconds'].to_i,
128
+ "stats_number_of_likes" => entry.xpath("yt:rating").first['numLikes'].to_i,
129
+ "stats_number_of_plays" => entry.xpath("yt:statistics").first['viewCount'].to_i,
130
+ "stats_number_of_comments" => entry.xpath("gd:comments/gd:feedLink").first['countHint'].to_i }
131
+ rescue
132
+ {}
133
+ end
134
+ end
135
+
136
+ def default_player_options
137
+ {
138
+ :width => 640,
139
+ :height => 360,
140
+ :fullscreen => true,
141
+ :api => false,
142
+ :autoplay => false,
143
+ :loop => false,
144
+ :showinfo => true
145
+ }.merge(prototype.options[:player] || {})
146
+ end
147
+
148
+
149
+ def to_vimeo_html(options = {})
150
+ params = vimeo_attributes(options)
151
+
152
+ attributes = make_html_attributes(params[:attr])
153
+ %(<iframe #{attributes}></iframe>)
154
+ end
155
+
156
+ def vimeo_attributes(options = {})
157
+
158
+ o = make_vimeo_options(options)
159
+
160
+ attributes = {
161
+ :type => "text/html",
162
+ :frameborder => "0",
163
+ :width => o.delete(:width),
164
+ :height => o.delete(:height)
165
+ }
166
+ attributes.update(:webkitAllowFullScreen => "yes", :allowFullScreen => "yes") if o[:fullscreen]
167
+
168
+ make_query_options!(o)
169
+ attributes[:src] = vimeo_src_with_options(o)
170
+
171
+ {:tagname => "iframe", :tag => "<iframe/>", :attr => attributes}
172
+ end
173
+
174
+ def make_vimeo_options(options = {})
175
+ o = default_player_options
176
+ vimeo_options = o.delete(:vimeo) || {}
177
+
178
+ o.merge!(vimeo_options)
179
+
180
+ if o.delete(:showinfo)
181
+ o[:portrait] = true
182
+ o[:title] = true
183
+ o[:byline] = true
184
+ else
185
+ o[:portrait] = false
186
+ o[:title] = false
187
+ o[:byline] = false
188
+ end
189
+
190
+ vimeo_options = options.delete(:vimeo) || {}
191
+
192
+ o = {
193
+ :portrait => true,
194
+ :title => true,
195
+ :byline => true,
196
+ :player_id => "vimeo#{owner.id}id#{value(:id)}"
197
+ }.merge(o).merge(vimeo_options).merge(options)
198
+ o
199
+ end
200
+
201
+ def vimeo_src(options = {})
202
+ o = make_vimeo_options(options)
203
+ make_query_options!(o)
204
+ vimeo_src_with_options(o)
205
+ end
206
+
207
+ def vimeo_src_with_options(o)
208
+ params = {
209
+ "title" => o[:title],
210
+ "byline" => o[:byline],
211
+ "portrait" => o[:portrait],
212
+ "autoplay" => o[:autoplay],
213
+ "loop" => o[:loop],
214
+ "api" => o[:api],
215
+ "player_id" => o[:player_id] }
216
+ params.update("color" => o[:color]) if o.key?(:color)
217
+ params = ::Rack::Utils.build_query(params)
218
+ "http://player.vimeo.com/video/#{value(:id)}?#{params}"
219
+ end
220
+
221
+ def to_youtube_html(options = {})
222
+ params = youtube_attributes(options)
223
+ attributes = make_html_attributes(params[:attr])
224
+ %(<iframe #{attributes}></iframe>)
225
+ end
226
+
227
+
228
+ def youtube_attributes(options = {})
229
+ o = make_youtube_options(options)
230
+
231
+ attributes = {
232
+ :type => "text/html",
233
+ :frameborder => "0",
234
+ :width => o.delete(:width),
235
+ :height => o.delete(:height)
236
+ }
237
+
238
+ make_query_options!(o)
239
+
240
+ attributes[:src] = youtube_src_with_options(o)
241
+
242
+ attributes.update(:webkitAllowFullScreen => "yes", :allowFullScreen => "yes") if o[:fullscreen]
243
+
244
+ {:tagname => "iframe", :tag => "<iframe/>", :attr => attributes}
245
+ end
246
+
247
+ def make_youtube_options(options = {})
248
+ o = default_player_options
249
+ youtube_options = o.delete(:youtube) || {}
250
+
251
+ o.merge!(youtube_options)
252
+
253
+ if o.delete(:showinfo)
254
+ o[:showinfo] = true
255
+ o[:showsearch] = true
256
+ else
257
+ o[:showinfo] = false
258
+ o[:showsearch] = false
259
+ end
260
+
261
+ youtube_options = options.delete(:youtube) || {}
262
+ o = {
263
+ :theme => "dark",
264
+ :hd => true,
265
+ :controls => true,
266
+ :showinfo => true,
267
+ :showsearch => true,
268
+ :autohide => 2,
269
+ :rel => true
270
+ }.merge(o).merge(youtube_options).merge(options)
271
+ end
272
+
273
+ def youtube_src(options = {})
274
+ o = make_youtube_options(options)
275
+ make_query_options!(o)
276
+ youtube_src_with_options(o)
277
+ end
278
+
279
+ def youtube_src_with_options(o)
280
+ params = ::Rack::Utils.build_query({
281
+ "modestbranding" => 1,
282
+ "theme" => o[:theme],
283
+ "hd" => o[:hd],
284
+ "fs" => o[:fullscreen],
285
+ "controls" => o[:controls],
286
+ "autoplay" => o[:autoplay],
287
+ "showinfo" => o[:showinfo],
288
+ "showsearch" => o[:showsearch],
289
+ "loop" => o[:loop],
290
+ "autohide" => o[:autohide],
291
+ "rel" => o[:rel],
292
+ "enablejsapi" => o[:api] })
293
+ "http://www.youtube.com/embed/#{value(:id)}?#{params}"
294
+ end
295
+
296
+ def make_html_attributes(attributes)
297
+ attributes.to_a.map { |name, value| "#{name}=\"#{escape_html(value)}\"" }.join(" ")
298
+ end
299
+
300
+
301
+ def make_query_options!(hash)
302
+ hash.each { |k, v|
303
+ hash[k] = 1 if v == true
304
+ hash[k] = 0 if v == false
305
+ }
306
+ end
307
+
308
+ self.register(:webvideo)
309
+ end
310
+ end
@@ -0,0 +1,80 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous
4
+ module Field
5
+ autoload :Base, "spontaneous/field/base"
6
+ autoload :FieldVersion, "spontaneous/field/field_version"
7
+ autoload :Update, "spontaneous/field/update"
8
+
9
+ @@type_map = {}
10
+
11
+ def self.register(klass, *labels)
12
+ labels.each do |label|
13
+ @@type_map[label.to_sym] = klass
14
+ end
15
+ end
16
+
17
+ def self.[](label)
18
+ @@type_map[label.to_sym] || String
19
+ end
20
+
21
+ def self.serialize_field(field)
22
+ [field.schema_id.to_s, field.version, field.unprocessed_value, field.processed_values]
23
+ end
24
+
25
+ def self.deserialize_field(serialized_field)
26
+ {
27
+ :id => serialized_field[0],
28
+ :version => serialized_field[1],
29
+ :unprocessed_value => serialized_field[2],
30
+ :processed_values => serialized_field[3]
31
+ }
32
+ end
33
+
34
+ # Used to test for the validity of asynchronous updates.
35
+ #
36
+ # A to-the-second resolution would actually probably be fine as
37
+ # real updates will come from the user in meat-space time but
38
+ # why not use the full resolution available...
39
+ def self.timestamp(time = Time.now)
40
+ (time.to_f * 10000000).to_i
41
+ end
42
+
43
+ def self.update(content, params, user, asynchronous = false)
44
+ fields = Hash[params.map { |sid, value| [content.fields.sid(sid), value] }]
45
+ Update.perform(fields, user, asynchronous)
46
+ end
47
+
48
+ def self.update_asynchronously(content, params, user)
49
+ update(content, params, user, true)
50
+ end
51
+
52
+ def self.set(field, value, user, asynchronous = false)
53
+ Update.perform({field => value}, user, asynchronous)
54
+ end
55
+
56
+ def self.set_asynchronously(field, value, user)
57
+ set(field, value, user, true)
58
+ end
59
+
60
+ def self.find(*ids)
61
+ fields = ids.map { |id| resolve_id(id) }.compact
62
+ return fields.first if ids.length == 1
63
+ fields
64
+ end
65
+
66
+ def self.resolve_id(id)
67
+ content_id, box_sid, field_sid = id.split("/")
68
+ field_sid, box_sid = box_sid, field_sid if field_sid.nil?
69
+ content = target = Spontaneous::Content.get(content_id)
70
+ return nil if target.nil?
71
+ target = content.boxes.sid(box_sid) if box_sid
72
+ return nil if target.nil?
73
+ target.fields.sid(field_sid)
74
+ end
75
+ end
76
+ end
77
+
78
+ [:string, :long_string, :file, :image, :date, :markdown, :location, :webvideo, :select].each do |type|
79
+ require "spontaneous/field/#{type}"
80
+ end
@@ -13,8 +13,8 @@ gem 'capistrano', '~> 2.9'
13
13
  # If you want to enable the built in search functionality then you must un-comment
14
14
  # the xapian-full & xapian-fu dependencies below. They are not included by default
15
15
  # because the xapian library takes a very long time to build.
16
- #gem 'xapian-full', "~> 1.2.3"
17
- #gem 'xapian-fu', "~> 1.3"
16
+ #gem 'xapian-ruby', "~> 1.2.12"
17
+ #gem 'xapian-fu', "~> 1.3"
18
18
 
19
19
  # group :production do
20
20
  # gem 'thin', '~> 1.3.1'
@@ -1,5 +1,5 @@
1
1
 
2
- publishing_method :simultaneous
2
+ background_mode :simultaneous
3
3
 
4
4
  simultaneous_connection "/tmp/simultaneous.<%= @site_name %>.sock"
5
5
 
@@ -1,5 +1,5 @@
1
1
 
2
- publishing_method :simultaneous
2
+ background_mode :simultaneous
3
3
 
4
4
  simultaneous_connection ENV["SIMULTANEOUS_SOCKET"]
5
5
  spontaneous_binary ENV["SPONTANEOUS_BINARY"]
@@ -0,0 +1,6 @@
1
+ # encoding: UTF-8
2
+
3
+ class Content < Spontaneous::Model(:content)
4
+ end
5
+
6
+ Site = Spontaneous.site(Content)
@@ -1,5 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- class Box < Spontaneous::Box
4
- end
3
+ require 'content'
5
4
 
5
+ class Box < Content::Box
6
+ end
@@ -1,6 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- class Page < Spontaneous::Page
3
+ require 'content'
4
+
5
+ class Page < Content::Page
4
6
  # pages must respond to the title method
5
7
  # so if you remove this 'title' field, then you must replace it with
6
8
  # a #title method
@@ -1,4 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- class Piece < Spontaneous::Piece
3
+ require 'content'
4
+
5
+ class Piece < Content::Piece
4
6
  end
@@ -12,7 +12,9 @@
12
12
  </head>
13
13
  <body>
14
14
  %{ block :content }
15
- <h2>Welcome to <%= @domain %></h2>
15
+ <h2>Welcome to <%= @domain %></h2>
16
+ ${ fields }
17
+ ${ boxes }
16
18
  %{ endblock :content }
17
19
  ${ scripts %w(/js/site) }
18
20
  </body>
@@ -42,20 +42,21 @@ module Spontaneous
42
42
  self.destination_root = self.destination_root / @site_name
43
43
  directory "config"
44
44
  directory "schema"
45
+ directory "lib"
45
46
  directory "templates"
46
47
  directory "public"
47
48
  template "Gemfile.tt", "Gemfile"
48
49
  template "Capfile.tt", "Capfile"
49
50
  template "Rakefile.tt", "Rakefile"
50
- template "lib/site.rb.tt", "lib/site.rb"
51
- empty_directory "lib/tasks"
51
+ # template "lib/site.rb.tt", "lib/site.rb"
52
+ # empty_directory "lib/tasks"
52
53
  empty_directory "log"
53
54
  empty_directory "tmp"
54
55
  empty_directory "cache/media"
55
56
  empty_directory "cache/tmp"
56
57
  empty_directory "cache/revisions"
57
58
  copy_file ".gitignore"
58
- template "lib/tasks/site.rake.tt", "lib/tasks/#{@site_name}.rake"
59
+ # template "lib/tasks/site.rake.tt", "lib/tasks/#{@site_name}.rake"
59
60
  else
60
61
  @valid = false
61
62
  say "Invalid database selection '#{options.database}'. Valid options are: #{self.class.available_dbs.keys.join(', ')}", :red
@@ -15,7 +15,6 @@ module Spontaneous
15
15
  else
16
16
  File.open(file, 'rb') { |io| read_size(io) }
17
17
  end
18
-
19
18
  end
20
19
 
21
20
  def read_size(file)
@@ -24,6 +23,7 @@ module Spontaneous
24
23
  end
25
24
 
26
25
  def image_type(file)
26
+ return Formats::EMPTY if file.size == 0
27
27
  img_top = file.read(16)
28
28
  bytes = img_top.unpack("C*")
29
29
  file.seek(0,0)
@@ -64,6 +64,13 @@ module Spontaneous
64
64
  end
65
65
  end
66
66
 
67
+ class EMPTY
68
+ def initialize(file)
69
+ end
70
+ def size
71
+ [0, 0]
72
+ end
73
+ end
67
74
  class GIF < Abstract
68
75
  def read_size
69
76
  @file.read_o(6)
@@ -7,8 +7,12 @@ module Spontaneous
7
7
  end
8
8
 
9
9
  class Default < Layout
10
+ # If no named layouts have been defined first look for a layout
11
+ # matching the class of our owner, then default to the 'standard'
12
+ # layout.
10
13
  def try_paths
11
- [["layouts", "standard"]]
14
+ named_layout = self.class.to_directory_name(owner)
15
+ [["layouts", named_layout], ["layouts", "standard"]]
12
16
  end
13
17
  end
14
18
 
@@ -98,7 +98,7 @@ module Spontaneous
98
98
  def is_site_page?(backtrace)
99
99
  path, line, context = backtrace.split(":")
100
100
  path = File.expand_path(path)
101
- root = Site.instance.root
101
+ root = Spontaneous::Site.instance.root
102
102
  path.start_with?(root)
103
103
  end
104
104
 
@@ -242,9 +242,6 @@ module Spontaneous
242
242
  # Removes the specified class and constant.
243
243
  #
244
244
  def remove_constant(const)
245
- # return if Padrino::Reloader.exclude_constants.any? { |base| (const.to_s =~ /^#{base}/ || const.superclass.to_s =~ /^#{base}/) } &&
246
- # !Padrino::Reloader.include_constants.any? { |base| (const.to_s =~ /^#{base}/ || const.superclass.to_s =~ /^#{base}/) }
247
-
248
245
  Spontaneous.schema.delete(const)
249
246
 
250
247
  parts = const.to_s.split("::")
@@ -378,7 +375,7 @@ module Spontaneous
378
375
  end
379
376
 
380
377
  def is_schema_class?(klass)
381
- (klass < Spontaneous::Page or klass < Spontaneous::Piece or klass < Spontaneous::Box)
378
+ (klass < Spontaneous::Content or klass < Content::Box)
382
379
  end
383
380
 
384
381
  def remove_constant(const)
@@ -23,6 +23,7 @@ module Spontaneous::Media
23
23
  def copy(existing_file)
24
24
  @source = existing_file.respond_to?(:path) ? existing_file.path : existing_file
25
25
  storage.copy(existing_file, storage_path, mimetype)
26
+ self
26
27
  end
27
28
 
28
29
  def url
@@ -46,11 +47,15 @@ module Spontaneous::Media
46
47
  end
47
48
 
48
49
  def padded_id
49
- owner.media_id.to_s.rjust(5, "0")
50
+ Spontaneous::Media.pad_id(owner.media_id)
50
51
  end
51
52
 
52
53
  def padded_revision
53
- Spontaneous::Site.working_revision.to_s.rjust(4, "0")
54
+ Spontaneous::Media.pad_revision(revision)
55
+ end
56
+
57
+ def revision
58
+ Spontaneous::Site.working_revision
54
59
  end
55
60
 
56
61
  def media_dir
@@ -74,5 +79,9 @@ module Spontaneous::Media
74
79
  end
75
80
 
76
81
  alias_method :filepath, :path
82
+
83
+ def serialize
84
+ { :url => url, :mimetype => mimetype, :path => path, :filename => filename }
85
+ end
77
86
  end
78
87
  end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'fileutils'
4
+
5
+ module Spontaneous::Media
6
+ # Represents a temporary file used to provide a media file that is visible
7
+ # publically under a /media/tmp/* URL for passing to file fields for
8
+ # asynchronous processing
9
+ class TempFile < File
10
+
11
+ def storage
12
+ Spontaneous::Site.default_storage
13
+ end
14
+
15
+ def media_dir
16
+ F.join("tmp", padded_id)
17
+ end
18
+
19
+ def storage_path
20
+ ["tmp", padded_id, filename]
21
+ end
22
+ end
23
+ end