spontaneous 0.2.0.beta1 → 0.2.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.locat +42 -0
  4. data/.travis/gemfiles/Gemfile.empty +7 -0
  5. data/.travis.yml +18 -0
  6. data/Gemfile +12 -8
  7. data/LICENSE +1 -1
  8. data/Rakefile +15 -157
  9. data/Readme.markdown +1 -1
  10. data/application/css/core.css.scss +22 -146
  11. data/application/css/definitions.css.scss +7 -3
  12. data/application/css/dialogue.css.scss +26 -1
  13. data/application/css/editing.css.scss +70 -28
  14. data/application/css/font.css.scss +1 -1
  15. data/application/css/popover.css.scss +2 -0
  16. data/application/css/top.css.scss +231 -0
  17. data/application/js/add_alias_dialogue.js +1 -1
  18. data/application/js/add_home_dialogue.js +1 -1
  19. data/application/js/ajax.js +61 -31
  20. data/application/js/box.js +4 -4
  21. data/application/js/conflicted_field_dialogue.js +1 -1
  22. data/application/js/content.js +5 -5
  23. data/application/js/dom.js +5 -0
  24. data/application/js/edit_panel.js +1 -0
  25. data/application/js/editing.js +1 -1
  26. data/application/js/extensions.js +8 -0
  27. data/application/js/field/boolean.js +31 -0
  28. data/application/js/field/file.js +32 -4
  29. data/application/js/field/image.js +24 -9
  30. data/application/js/field/markdown.js +87 -59
  31. data/application/js/field/select.js +1 -1
  32. data/application/js/field/webvideo.js +6 -1
  33. data/application/js/init.js +2 -2
  34. data/application/js/jquery-selection-position.js +130 -0
  35. data/application/js/location.js +4 -25
  36. data/application/js/meta_view/user_admin.js +2 -2
  37. data/application/js/metadata.js +2 -2
  38. data/application/js/page_browser.js +1 -1
  39. data/application/js/panel/root_menu.js +0 -1
  40. data/application/js/popover.js +27 -12
  41. data/application/js/popover_view.js +20 -4
  42. data/application/js/preview.js +31 -16
  43. data/application/js/progress.js +22 -21
  44. data/application/js/publish.js +18 -7
  45. data/application/js/sharded_upload.js +9 -6
  46. data/application/js/spontaneous.js +3 -1
  47. data/application/js/top_bar.js +264 -173
  48. data/application/js/upload.js +12 -5
  49. data/application/js/upload_manager.js +4 -3
  50. data/application/js/user.js +1 -2
  51. data/application/js/views/box_view.js +1 -1
  52. data/application/js/views/page_view.js +16 -5
  53. data/application/js/views/piece_view.js +5 -4
  54. data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
  55. data/application/views/index.erb +6 -14
  56. data/application/views/login.erb +6 -25
  57. data/application/views/schema_modification_error.html.erb +3 -7
  58. data/db/migrations/20130114120000_create_revision_tables.rb +2 -2
  59. data/db/migrations/20130813111009_increase_path_length.rb +14 -0
  60. data/gem-public_cert.pem +20 -0
  61. data/lib/spontaneous/asset/app_compiler.rb +44 -0
  62. data/lib/spontaneous/asset/environment.rb +225 -0
  63. data/lib/spontaneous/asset.rb +2 -67
  64. data/lib/spontaneous/box.rb +0 -1
  65. data/lib/spontaneous/capistrano/deploy.rb +2 -2
  66. data/lib/spontaneous/capistrano/sync.rb +1 -1
  67. data/lib/spontaneous/cli/init.rb +36 -13
  68. data/lib/spontaneous/cli/server.rb +0 -1
  69. data/lib/spontaneous/cli/site.rb +2 -1
  70. data/lib/spontaneous/cli.rb +3 -1
  71. data/lib/spontaneous/collections/entry_set.rb +4 -12
  72. data/lib/spontaneous/collections/hash_with_fallback.rb +20 -0
  73. data/lib/spontaneous/collections/prototype_set.rb +6 -5
  74. data/lib/spontaneous/crypt.rb +2 -2
  75. data/lib/spontaneous/data_mapper/content_model/associations.rb +115 -63
  76. data/lib/spontaneous/data_mapper.rb +1 -1
  77. data/lib/spontaneous/errors.rb +6 -0
  78. data/lib/spontaneous/extensions/object_space.rb +6 -0
  79. data/lib/spontaneous/facet.rb +1 -0
  80. data/lib/spontaneous/field/base.rb +86 -13
  81. data/lib/spontaneous/field/boolean.rb +65 -0
  82. data/lib/spontaneous/field/file.rb +17 -6
  83. data/lib/spontaneous/field/html.rb +13 -0
  84. data/lib/spontaneous/field/image/size.rb +76 -0
  85. data/lib/spontaneous/field/image.rb +99 -414
  86. data/lib/spontaneous/field/tags.rb +36 -0
  87. data/lib/spontaneous/field/update.rb +1 -1
  88. data/lib/spontaneous/field/webvideo/fallback.rb +41 -0
  89. data/lib/spontaneous/field/webvideo/vimeo.rb +113 -0
  90. data/lib/spontaneous/field/webvideo/vine.rb +94 -0
  91. data/lib/spontaneous/field/webvideo/youtube.rb +133 -0
  92. data/lib/spontaneous/field/webvideo.rb +100 -250
  93. data/lib/spontaneous/field.rb +1 -1
  94. data/lib/spontaneous/generators/site/Gemfile.tt +5 -14
  95. data/lib/spontaneous/generators/site/assets/README.md +20 -0
  96. data/lib/spontaneous/generators/site/assets/css/site.scss +8 -0
  97. data/lib/spontaneous/generators/site/assets/js/site.js +6 -0
  98. data/lib/spontaneous/generators/site/config/deploy.rb.tt +9 -0
  99. data/lib/spontaneous/generators/site/config/user_levels.yml +14 -3
  100. data/lib/spontaneous/generators/site/public/README.md +12 -0
  101. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +2 -2
  102. data/lib/spontaneous/generators/site.rb +77 -35
  103. data/lib/spontaneous/layout.rb +6 -7
  104. data/lib/spontaneous/loader.rb +21 -13
  105. data/lib/spontaneous/media/file.rb +22 -9
  106. data/lib/spontaneous/media/image/attributes.rb +33 -0
  107. data/lib/spontaneous/media/image/format/gif.rb +4 -0
  108. data/lib/spontaneous/media/image/format/jpg.rb +17 -0
  109. data/lib/spontaneous/media/image/format/png.rb +4 -0
  110. data/lib/spontaneous/media/image/format/webp.rb +26 -0
  111. data/lib/spontaneous/media/image/format.rb +79 -0
  112. data/lib/spontaneous/media/image/optimizer.rb +69 -0
  113. data/lib/spontaneous/media/image/processor.rb +17 -0
  114. data/lib/spontaneous/media/image/renderable.rb +52 -0
  115. data/lib/spontaneous/media/image/skeptick.rb +70 -0
  116. data/lib/spontaneous/media/image.rb +50 -0
  117. data/lib/spontaneous/media/temp_file.rb +4 -0
  118. data/lib/spontaneous/media.rb +1 -0
  119. data/lib/spontaneous/model/core/aliases.rb +14 -8
  120. data/lib/spontaneous/model/core/boxes.rb +5 -2
  121. data/lib/spontaneous/model/core/entries.rb +4 -0
  122. data/lib/spontaneous/model/core/entry.rb +1 -0
  123. data/lib/spontaneous/model/core/fields.rb +5 -2
  124. data/lib/spontaneous/model/core/locks.rb +16 -0
  125. data/lib/spontaneous/model/core/media.rb +1 -15
  126. data/lib/spontaneous/model/core.rb +31 -1
  127. data/lib/spontaneous/model/page/controllers.rb +2 -2
  128. data/lib/spontaneous/model/page/formats.rb +1 -4
  129. data/lib/spontaneous/model/page/layouts.rb +6 -2
  130. data/lib/spontaneous/model/page/locks.rb +8 -2
  131. data/lib/spontaneous/model/page/page_tree.rb +2 -2
  132. data/lib/spontaneous/model/page/paths.rb +74 -9
  133. data/lib/spontaneous/model/page.rb +11 -3
  134. data/lib/spontaneous/model.rb +6 -6
  135. data/lib/spontaneous/output/context/render_cache.rb +23 -0
  136. data/lib/spontaneous/output/context.rb +56 -30
  137. data/lib/spontaneous/output/helpers/script_helper.rb +9 -53
  138. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +8 -40
  139. data/lib/spontaneous/output/template/renderer.rb +17 -5
  140. data/lib/spontaneous/output.rb +0 -1
  141. data/lib/spontaneous/paths.rb +6 -2
  142. data/lib/spontaneous/permissions/access_key.rb +18 -0
  143. data/lib/spontaneous/permissions/user.rb +1 -1
  144. data/lib/spontaneous/permissions.rb +4 -1
  145. data/lib/spontaneous/plugins/application/state.rb +19 -12
  146. data/lib/spontaneous/prototypes/field_prototype.rb +14 -8
  147. data/lib/spontaneous/published_revision.rb +7 -0
  148. data/lib/spontaneous/publishing/immediate.rb +43 -34
  149. data/lib/spontaneous/publishing/revision.rb +9 -6
  150. data/lib/spontaneous/rack/asset_server.rb +20 -0
  151. data/lib/spontaneous/rack/back/alias.rb +46 -0
  152. data/lib/spontaneous/rack/back/application_assets.rb +28 -0
  153. data/lib/spontaneous/rack/back/base.rb +34 -0
  154. data/lib/spontaneous/rack/back/changes.rb +19 -0
  155. data/lib/spontaneous/rack/back/content.rb +54 -0
  156. data/lib/spontaneous/rack/back/events.rb +38 -0
  157. data/lib/spontaneous/rack/back/field.rb +37 -0
  158. data/lib/spontaneous/rack/back/file.rb +118 -0
  159. data/lib/spontaneous/rack/back/helpers.rb +71 -0
  160. data/lib/spontaneous/rack/back/index.rb +16 -0
  161. data/lib/spontaneous/rack/back/login.rb +47 -0
  162. data/lib/spontaneous/rack/back/map.rb +24 -0
  163. data/lib/spontaneous/rack/back/page.rb +46 -0
  164. data/lib/spontaneous/rack/back/preview.rb +43 -0
  165. data/lib/spontaneous/rack/back/schema.rb +30 -0
  166. data/lib/spontaneous/rack/back/site.rb +25 -0
  167. data/lib/spontaneous/rack/back/site_assets.rb +13 -0
  168. data/lib/spontaneous/rack/back/unsupported_browser.rb +7 -0
  169. data/lib/spontaneous/rack/{user_admin.rb → back/user_admin.rb} +2 -5
  170. data/lib/spontaneous/rack/back.rb +85 -764
  171. data/lib/spontaneous/rack/cacheable_file.rb +3 -3
  172. data/lib/spontaneous/rack/front.rb +16 -9
  173. data/lib/spontaneous/rack/middleware/authenticate.rb +65 -0
  174. data/lib/spontaneous/rack/middleware/csrf.rb +66 -0
  175. data/lib/spontaneous/rack/middleware/reloader.rb +52 -0
  176. data/lib/spontaneous/rack/middleware/scope.rb +60 -0
  177. data/lib/spontaneous/rack/middleware.rb +6 -0
  178. data/lib/spontaneous/rack/page_controller.rb +18 -5
  179. data/lib/spontaneous/rack/public.rb +17 -11
  180. data/lib/spontaneous/rack.rb +34 -24
  181. data/lib/spontaneous/revision.rb +29 -2
  182. data/lib/spontaneous/schema/uid.rb +4 -3
  183. data/lib/spontaneous/schema/uid_map.rb +5 -24
  184. data/lib/spontaneous/schema.rb +1 -0
  185. data/lib/spontaneous/search/database.rb +8 -0
  186. data/lib/spontaneous/search/field.rb +1 -1
  187. data/lib/spontaneous/search/index.rb +3 -5
  188. data/lib/spontaneous/server.rb +1 -1
  189. data/lib/spontaneous/simultaneous.rb +1 -1
  190. data/lib/spontaneous/site/features.rb +4 -5
  191. data/lib/spontaneous/site/helpers.rb +22 -5
  192. data/lib/spontaneous/site/instance.rb +2 -2
  193. data/lib/spontaneous/site/selectors.rb +22 -3
  194. data/lib/spontaneous/storage/cloud.rb +13 -9
  195. data/lib/spontaneous/storage/local.rb +11 -6
  196. data/lib/spontaneous/style.rb +40 -23
  197. data/lib/spontaneous/utils/database/mysql_dumper.rb +1 -1
  198. data/lib/spontaneous/utils/smush_it.rb +1 -1
  199. data/lib/spontaneous/version.rb +1 -1
  200. data/lib/spontaneous.rb +35 -33
  201. data/spontaneous.gemspec +53 -787
  202. data/test/experimental/test_crypt.rb +56 -56
  203. data/test/experimental/test_features.rb +16 -27
  204. data/test/fixtures/assets/public1/css/data.css.scss +3 -0
  205. data/test/fixtures/assets/public1/css/image1.css.scss +4 -0
  206. data/test/fixtures/assets/public1/css/import.css.scss +1 -0
  207. data/test/fixtures/assets/public1/css/urlhash.css.scss +3 -0
  208. data/test/fixtures/assets/public1/js/a.js +1 -1
  209. data/test/fixtures/assets/public1/js/all.js +4 -0
  210. data/test/fixtures/assets/public1/js/{m.coffee → m.js.coffee} +1 -0
  211. data/test/fixtures/assets/public1/x.js +1 -0
  212. data/test/fixtures/assets/public2/css/all.css +4 -0
  213. data/test/fixtures/assets/public2/css/missing.css.scss +3 -0
  214. data/test/fixtures/assets/public2/i/y.png +0 -0
  215. data/test/fixtures/assets/public2/js/b.js +1 -1
  216. data/test/fixtures/assets/public2/js/c.js +1 -1
  217. data/test/fixtures/images/size.extended.webp +0 -0
  218. data/test/fixtures/images/size.lossless.webp +0 -0
  219. data/test/fixtures/images/size.lossy.webp +0 -0
  220. data/test/fixtures/schema/before.yml +4 -4
  221. data/test/fixtures/schema/schema.yml +1 -1
  222. data/test/fixtures/templates/aliases/aaa.html.cut +0 -0
  223. data/test/fixtures/templates/extended/partial_with_renderer.html.cut +1 -0
  224. data/test/fixtures/templates/extended/with_includes_and_renderer.html.cut +2 -0
  225. data/test/functional/test_application.rb +108 -106
  226. data/test/functional/test_back.rb +924 -930
  227. data/test/functional/test_front.rb +285 -238
  228. data/test/functional/test_user_manager.rb +75 -100
  229. data/test/integration/test_installation.rb +1 -1
  230. data/test/support/matchers.rb +12 -0
  231. data/test/support/minitest.rb +121 -0
  232. data/test/support/rack.rb +45 -0
  233. data/test/support/test_start_finish.rb +103 -0
  234. data/test/test_helper.rb +21 -68
  235. data/test/test_integration_helper.rb +1 -3
  236. data/test/unit/test_alias.rb +432 -408
  237. data/test/unit/test_asset_bundler.rb +58 -58
  238. data/test/unit/test_assets.rb +485 -155
  239. data/test/unit/test_async.rb +16 -37
  240. data/test/unit/test_authentication.rb +425 -457
  241. data/test/unit/test_boxes.rb +191 -191
  242. data/test/unit/test_changesets.rb +244 -254
  243. data/test/unit/test_config.rb +128 -142
  244. data/test/unit/test_content.rb +313 -359
  245. data/test/unit/test_content_inheritance.rb +29 -30
  246. data/test/unit/test_datamapper.rb +1205 -1080
  247. data/test/unit/test_datamapper_content.rb +49 -51
  248. data/test/unit/test_extensions.rb +23 -23
  249. data/test/unit/test_fields.rb +1488 -1180
  250. data/test/unit/test_formats.rb +158 -158
  251. data/test/unit/test_generators.rb +98 -40
  252. data/test/unit/test_helpers.rb +73 -76
  253. data/test/unit/test_image_size.rb +53 -22
  254. data/test/unit/test_images.rb +164 -165
  255. data/test/unit/test_layouts.rb +133 -122
  256. data/test/unit/test_logger.rb +14 -17
  257. data/test/unit/test_media.rb +69 -84
  258. data/test/unit/test_modifications.rb +513 -525
  259. data/test/unit/test_page.rb +462 -361
  260. data/test/unit/test_permissions.rb +379 -364
  261. data/test/unit/test_piece.rb +67 -75
  262. data/test/unit/test_plugins.rb +82 -89
  263. data/test/unit/test_prototype_set.rb +215 -216
  264. data/test/unit/test_prototypes.rb +114 -124
  265. data/test/unit/test_publishing.rb +252 -289
  266. data/test/unit/test_render.rb +167 -115
  267. data/test/unit/test_revisions.rb +436 -444
  268. data/test/unit/test_schema.rb +339 -309
  269. data/test/unit/test_search.rb +577 -574
  270. data/test/unit/test_serialisation.rb +136 -147
  271. data/test/unit/test_site.rb +252 -227
  272. data/test/unit/test_skeptick.rb +130 -0
  273. data/test/unit/test_storage.rb +46 -40
  274. data/test/unit/test_structure.rb +57 -66
  275. data/test/unit/test_styles.rb +104 -104
  276. data/test/unit/test_templates.rb +72 -57
  277. data/test/unit/test_type_hierarchy.rb +15 -16
  278. data/test/unit/test_visibility.rb +239 -257
  279. metadata +455 -326
  280. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +0 -283
  281. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +0 -30
  282. data/application/js/vendor/JS.Class-2.1.5/README +0 -30
  283. data/application/js/vendor/JS.Class-2.1.5/min/command.js +0 -1
  284. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +0 -1
  285. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +0 -1
  286. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +0 -1
  287. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +0 -1
  288. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +0 -1
  289. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +0 -1
  290. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +0 -1
  291. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +0 -1
  292. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +0 -1
  293. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +0 -1
  294. data/application/js/vendor/JS.Class-2.1.5/min/package.js +0 -1
  295. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +0 -1
  296. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +0 -1
  297. data/application/js/vendor/JS.Class-2.1.5/min/set.js +0 -1
  298. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +0 -1
  299. data/application/js/vendor/JS.Class-2.1.5/min/state.js +0 -1
  300. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +0 -16
  301. data/application/js/vendor/jquery-1.6.2.min.js +0 -18
  302. data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +0 -791
  303. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +0 -415
  304. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  305. data/application/static/select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png +0 -0
  306. data/bin/limit-upload +0 -5
  307. data/bin/unlimit-upload +0 -3
  308. data/lib/spontaneous/asset/file.rb +0 -25
  309. data/lib/spontaneous/asset/source.rb +0 -28
  310. data/lib/spontaneous/image_size.rb +0 -123
  311. data/lib/spontaneous/output/assets/compression.rb +0 -58
  312. data/lib/spontaneous/output/assets.rb +0 -32
  313. data/lib/spontaneous/rack/around_back.rb +0 -20
  314. data/lib/spontaneous/rack/around_front.rb +0 -27
  315. data/lib/spontaneous/rack/around_preview.rb +0 -22
  316. data/lib/spontaneous/rack/assets.rb +0 -126
  317. data/lib/spontaneous/rack/authentication.rb +0 -20
  318. data/lib/spontaneous/rack/cookie_authentication.rb +0 -38
  319. data/lib/spontaneous/rack/helpers.rb +0 -52
  320. data/lib/spontaneous/rack/http.rb +0 -18
  321. data/lib/spontaneous/rack/media.rb +0 -30
  322. data/lib/spontaneous/rack/query_authentication.rb +0 -35
  323. data/lib/spontaneous/rack/reloader.rb +0 -45
  324. data/lib/spontaneous/rack/user_helpers.rb +0 -28
  325. /data/{README → application/js/field/markdown/text_command.js} +0 -0
  326. /data/application/js/vendor/{JS.Class-2.1.5/min/core.js → js.class-2.1.5.min.js} +0 -0
  327. /data/test/fixtures/assets/public1/css/{a.scss → a.css.scss} +0 -0
  328. /data/{lib/spontaneous/generators/site/public/css/site.scss → test/fixtures/assets/public1/x.css} +0 -0
  329. /data/{lib/spontaneous/generators/site/public/js/.empty_directory → test/fixtures/assets/public1/x.png} +0 -0
  330. /data/test/fixtures/assets/public2/css/{b.scss → b.css.scss} +0 -0
  331. /data/test/fixtures/assets/public2/js/{n.coffee → n.js.coffee} +0 -0
  332. /data/test/fixtures/back/{public → assets}/css/sass_include.scss +0 -0
  333. /data/test/fixtures/back/{public → assets}/css/sass_template.scss +0 -0
  334. /data/test/fixtures/back/{public → assets}/js/coffeescript.coffee +0 -0
  335. /data/{lib/spontaneous/generators/site/public/js/site.js → test/fixtures/templates/aliases/aa_alias.html.cut} +0 -0
@@ -4,458 +4,143 @@ require 'tempfile'
4
4
  require 'mini_magick'
5
5
  require 'delegate'
6
6
 
7
- module Spontaneous::Field
8
-
9
- class ImageOptimizer
10
- def self.run(source_image)
11
- self.new(source_image).run
12
- end
13
-
14
- def self.jpegtran_binary
15
- @jpegtran ||= find_binary("jpegtran")
16
- end
17
-
18
- def self.jpegoptim_binary
19
- @jpegoptim ||= find_binary("jpegoptim")
20
- end
21
7
 
22
- def self.find_binary(name)
23
- binary = `which #{name}`.chomp
24
- return nil if binary.length == 0
25
- binary
26
- end
27
-
28
- # def self.find_binary(name)
29
- # binaries = ["/usr/bin/env #{name}"]
30
- # puts "testing name #{name}"
31
- # binaries.detect { |bin| status = Spontaneous.system("#{bin} -h"); p status; status == 1 }.tap do |b|
32
- # puts "found #{b.inspect}"
33
- # end
34
- # end
35
-
36
- def initialize(source_image)
37
- @source_image = source_image
38
- end
39
-
40
- def run
41
- jpegoptim!(@source_image)
42
- jpegtran!(@source_image)
43
- end
8
+ module Spontaneous::Field
9
+ class Image < File
10
+ autoload :Size, 'spontaneous/field/image/size'
44
11
 
45
- def jpegoptim!(input)
46
- run_optimization(self.class.jpegoptim_binary, "-o -q --strip-all --preserve --force #{input} 2>&1 1>/dev/null")
47
- end
12
+ include Spontaneous::Media::Image::Renderable
48
13
 
49
- def jpegtran!(input)
50
- run_optimization(self.class.jpegtran_binary, "-optimize -progressive -copy none -outfile #{input} #{input}")
51
- end
14
+ has_editor
52
15
 
53
- def run_optimization(binary, args)
54
- return unless binary
55
- command = [binary, args].join(" ")
56
- Spontaneous.system(command)
57
- end
16
+ def self.accepts
17
+ %w{image/(png|jpeg|gif)}
58
18
  end
59
19
 
60
- module ImageFieldUtilities
61
- attr_accessor :template_params
20
+ class TemplateParameters < DelegateClass(S::Media::Image::Attributes)
21
+ attr_reader :image
62
22
 
63
- def render(format=:html, *args)
64
- case format
65
- when "html", :html
66
- to_html(*args)
67
- else
68
- value
69
- end
23
+ def initialize(image, args)
24
+ super(image)
25
+ @image, @args = image, args.extract_options!
70
26
  end
71
27
 
72
- def to_html(attr={})
73
- default_attr = {
74
- :src => src,
75
- :width => width,
76
- :height => height,
77
- :alt => ""
78
- }
79
- default_attr.delete(:width) if width.nil?
80
- default_attr.delete(:height) if height.nil?
81
- if template_params && template_params.length > 0 && template_params[0].is_a?(Hash)
82
- attr = template_params[0].merge(attr)
83
- end
84
- if attr.key?(:width) || attr.key?(:height)
85
- default_attr.delete(:width)
86
- default_attr.delete(:height)
87
- if (attr.key?(:width) && !attr[:width]) || (attr.key?(:height) && !attr[:height])
88
- attr.delete(:width)
89
- attr.delete(:height)
90
- end
91
- end
92
- attr = default_attr.merge(attr)
93
- params = []
94
- attr.each do |name, value|
95
- params << %(#{name}="#{value.to_s.escape_html}")
96
- end
97
- %(<img #{params.join(' ')} />)
98
- end
99
-
100
- def to_s
101
- src
102
- end
103
-
104
- def /(value)
105
- return value if self.blank?
106
- self
28
+ def to_html(attributes = {})
29
+ @image.to_html(@args.merge(attributes))
107
30
  end
108
31
  end
109
32
 
110
- class Image < File
111
- has_editor
112
- include ImageFieldUtilities
113
-
114
- def self.accepts
115
- %w{image/(png|jpeg|gif)}
116
- end
117
-
118
- def self.size(name, &process)
119
- self.sizes[name.to_sym] = process
120
-
121
- unless method_defined?(name)
122
- class_eval <<-IMAGE
123
- def #{name}
124
- sizes[:#{name}]
125
- end
126
- IMAGE
127
- end
128
- end
129
-
130
- def self.sizes
131
- size_definitions
132
- end
133
-
134
- def self.validate_sizes(sizes)
135
- sizes
136
- end
137
-
138
- def self.size_definitions
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
- }
146
- end
147
-
148
- def image?
149
- true
150
- end
151
-
152
- def sizes
153
- @sizes ||= Hash.new { |hash, key| hash[key] = ImageAttributes.new(processed_values[key]) }
154
- end
155
-
156
- # value used to show conflicts between the current value and the value they're attempting to enter
157
- def conflicted_value
158
- value
159
- end
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
-
171
- # original is special and should always be defined
172
- def original
173
- @original ||= sizes[:original]
174
- end
175
-
176
- def width
177
- original.width
178
- end
179
-
180
- def height
181
- original.height
182
- end
183
-
184
- def filesize
185
- original.filesize
33
+ def self.size(name, options = {}, &process)
34
+ self.sizes[name.to_sym] = [options, process]
35
+ unless method_defined?(name)
36
+ class_eval "def #{name}(*args); TemplateParameters.new(sizes[:#{name}], args); end"
186
37
  end
38
+ end
187
39
 
188
- def src
189
- original.src
190
- end
191
-
192
- def filepath
193
- unprocessed_value
194
- end
195
-
196
- # formats are irrelevant to image/file fields
197
- def outputs
198
- [:original, :__ui__].concat(self.class.size_definitions.map { |name, process| name })
199
- end
200
-
201
- def value(format=:html, *args)
202
- sizes[:original].src
203
- end
204
-
205
- def set_value!(value, process = true)
206
- @sizes = nil
207
- super
208
- end
209
-
210
- def generate(output, media_file)
211
- return { :src => media_file } if media_file.is_a?(::String)#File.exist?(image_path)
212
- image = ImageProcessor.new(media_file)
213
- # Create a tempfile here that will be kept open for the duration of the block
214
- # this is used in #apply to hold a copy of the processed image data rather than
215
- # rely on the minimagick generated tempfiles which can get closed
216
- result = Tempfile.open("image_#{output}") do |tempfile|
217
- case output
218
- when :original
219
- image
220
- else
221
- process = self.class.size_definitions[output]
222
- image.apply(process, output, tempfile)
223
- end
224
- end
225
- result.serialize
226
- end
227
-
228
-
229
- def export(user = nil)
230
- super(user).merge({
231
- :processed_value => processed_values
232
- })
233
- end
40
+ def self.sizes
41
+ size_definitions
42
+ end
234
43
 
235
- self.register(:image, :photo)
44
+ def self.validate_sizes(sizes)
45
+ sizes
236
46
  end
237
47
 
48
+ def self.size_definitions
49
+ @size_definitions ||= superclass.respond_to?(:size_definitions) ? superclass.size_definitions.dup : default_size_definitions
50
+ end
238
51
 
239
- class ImageAttributes
240
- include ImageFieldUtilities
52
+ def self.default_size_definitions
53
+ { :original => original_size, :__ui__ => ui_preview_size }
54
+ end
241
55
 
242
- attr_reader :src, :width, :height, :filesize, :filepath
56
+ def self.original_size
57
+ [ {} ]
58
+ end
243
59
 
244
- def initialize(params={})
245
- params ||= {}
246
- @src, @width, @height, @filesize, @filepath = params[:src], params[:width], params[:height], params[:filesize], params[:path]
247
- end
60
+ def self.ui_preview_size
61
+ [ {}, proc { width 300 } ]
62
+ end
248
63
 
249
- def serialize
250
- {
251
- :src => src,
252
- :width => width,
253
- :height => height,
254
- :filesize => filesize,
255
- :path => filepath
256
- }
257
- end
64
+ def image?
65
+ true
66
+ end
258
67
 
259
- def inspect
260
- %(<#{self.class.name}: src=#{src.inspect} width="#{width}" height="#{height}">)
261
- end
68
+ def sizes
69
+ @sizes ||= Hash.new { |hash, key| hash[key] = S::Media::Image::Attributes.new(processed_values[key]) }
70
+ end
262
71
 
263
- def blank?
264
- src.blank?
265
- end
72
+ # value used to show conflicts between the current value and the value they're attempting to enter
73
+ def conflicted_value
74
+ value
75
+ end
266
76
 
267
- alias_method :empty?, :blank?
77
+ # I want to merge the file info available in the media file
78
+ # with the image details (width, height etc)
79
+ def serialize_pending_file(file)
80
+ attrs = file.serialize
81
+ url = attrs.delete(:url)
82
+ image = Spontaneous::Media::Image.new(file.path)
83
+ attrs.merge(image.serialize).merge(super)
268
84
  end
269
85
 
270
- class ImageProcessor
271
- include ImageFieldUtilities
272
-
273
- class ImageDelegator < SimpleDelegator
274
-
275
- def initialize(image)
276
- super(image)
277
- end
278
-
279
- alias_method :image, :__getobj__
280
-
281
- def format(*args, &block)
282
- image.format(*args, &block)
283
- end
284
-
285
- def fit(width, height)
286
- image.combine_options do |c|
287
- c.add_command(:geometry, "#{width}x#{height}>")
288
- end
289
- end
290
-
291
- def crop(width, height)
292
- image.combine_options do |c|
293
- dimensions = "#{width}x#{height}"
294
- c.add_command(:geometry, "#{dimensions}^")
295
- c.add_command(:gravity, "center")
296
- c.add_command(:crop, "#{dimensions}+0+0!")
297
- end
298
- end
299
-
300
- def width(width)
301
- image.combine_options do |c|
302
- c.add_command(:geometry, "#{width}x>")
303
- end
304
- end
305
-
306
- def height(height)
307
- image.combine_options do |c|
308
- c.add_command(:geometry, "x#{height}>")
309
- end
310
- end
311
-
312
- def greyscale
313
- image.combine_options do |c|
314
- c.add_command(:type, "Grayscale")
315
- end
316
- end
317
-
318
- def composite(other_image_path, output_extension = "jpg", &block)
319
- ::File.open(other_image_path) do |other_image|
320
- new_image = image.composite(other_image, output_extension, &block)
321
- image.path = new_image.path
322
- end
323
- end
324
-
325
- def smush_it!
326
- ::Spontaneous::Utils::SmushIt.smush!(image.path, current_image_format)
327
- end
328
-
329
- def optimize!
330
- ImageOptimizer.run(image.path) if current_image_format == "jpg"
331
- end
332
-
333
- def border_radius(radius, bg_color = nil)
334
- @image.format('png') if bg_color.nil? or bg_color == 'transparent'
335
- puts @image.path
336
- c = MiniMagick::CommandBuilder.new('convert')
337
- c << @image.path
338
- c.add_command(:format, "roundrectangle 0,0 %[fx:w-1],%[fx:h-1], 10,10")
339
- c.add_command(:write, "info:tmp.mvg")
340
- c << @image.path
341
-
342
- puts c.command
343
- # @image.run(c)
344
- sub = Subexec.run(c.command, :timeout => MiniMagick.timeout)
345
-
346
- c = MiniMagick::CommandBuilder.new('convert')
347
-
348
- c << @image.path
349
- # c.add_command(:write, "info:tmp.mvg")
350
- c.add_command(:matte)
351
- c.add_command(:bordercolor, "none")
352
- c.add_command(:border, "0")
353
- c.push('\\(')
354
- c.push("+clone")
355
- c.add_command(:alpha, 'transparent')
356
- c.add_command(:background, 'white')
357
- c.add_command(:fill, 'white')
358
- c.add_command(:stroke, 'none')
359
- c.add_command(:strokewidth, '0')
360
- c.add_command(:draw, "@tmp.mvg")
361
- c.push('\\)')
362
- c.add_command(:compose, 'DstIn')
363
- c.add_command(:composite)
364
- c << @image.path
365
- puts c.command
366
- @image.run(c)
367
-
368
- end
369
-
370
-
371
- def __run__(process)
372
- instance_eval(&process)
373
- end
374
-
375
- def method_missing(method, *args, &block)
376
- params = args.map(&:to_s)
377
- if image.respond_to?(method)
378
- image.__send__(method, *params, &block)
379
- else
380
- image.method_missing(method, *params, &block)
381
- end
382
- end
383
-
384
- def current_image_format
385
- image[:format].downcase.gsub(/^jpeg$/, "jpg")
386
- end
387
- end
86
+ def page_lock_description
87
+ "Processing image '#{pending_value[:value][:filename]}'"
88
+ end
388
89
 
389
- MAX_DIM = 2 ** ([42].pack('i').size * 8) - 1 unless defined?(MAX_DIM)
90
+ # original is special and should always be defined
91
+ def original
92
+ @original ||= sizes[:original]
93
+ end
390
94
 
391
- attr_reader :path
95
+ def width
96
+ original.width
97
+ end
392
98
 
393
- def initialize(media_file)
394
- @media_file = media_file
395
- @path = media_file.source
396
- end
99
+ def height
100
+ original.height
101
+ end
397
102
 
398
- def src
399
- @media_file.url
400
- end
103
+ def filesize
104
+ original.filesize
105
+ end
401
106
 
402
- def filesize
403
- ::File.size(path)
404
- end
107
+ def src
108
+ original.src
109
+ end
405
110
 
406
- def width
407
- dimensions[0]
408
- end
111
+ def filepath
112
+ unprocessed_value
113
+ end
409
114
 
410
- def height
411
- dimensions[1]
412
- end
115
+ # formats are irrelevant to image/file fields
116
+ def outputs
117
+ [:original, :__ui__].concat(self.class.size_definitions.map { |name, process| name })
118
+ end
413
119
 
414
- def dimensions
415
- @dimensions ||= Spontaneous::ImageSize.read(path)
416
- end
120
+ def value(format=:html, *args)
121
+ sizes[:original].src
122
+ end
417
123
 
418
- def apply(process, name, tempfile)
419
- image = ::MiniMagick::Image.open(path)
420
- processor = ImageProcessor::ImageDelegator.new(image)
421
- processor.__run__(process)
422
- file = @media_file.rename(filename_for_size(name, image))
423
- # copy the image into the tempfile provided by the parent #generate call
424
- # this stops us from using a tempfile that is out of our control and can
425
- # be closed before we're done
426
- FileUtils.cp(image.path, tempfile.path)
427
- file.copy(tempfile)
428
-
429
- ImageProcessor.new(file)
430
- end
124
+ def set_value!(value, process = true)
125
+ @sizes = nil
126
+ super
127
+ end
431
128
 
432
- def filename_for_size(name, image)
433
- original_filename = @media_file.filename
434
- parts = original_filename.split('.')
435
-
436
- # use the image format for the extension because tempfiles generated by
437
- # mini_magick don't have extensions
438
- # I hate the "jpeg" extension though
439
- ext = image[:format].downcase.gsub(/^jpeg$/, "jpg")
440
- base = parts[0..-2].join('.')
441
- filename = [base, name, ext].join('.')
442
- filename
443
- end
129
+ def generate(name, media_file)
130
+ return { :src => media_file } if media_file.is_a?(::String)
131
+ options, process = self.class.size_definitions[name]
132
+ size = Size.new(media_file, name, options, process)
133
+ size.generate
134
+ end
444
135
 
445
- def serialize
446
- {
447
- :src => src,
448
- :width => width,
449
- :height => height,
450
- :filesize => filesize,
451
- :path => @media_file.path
452
- }
453
- end
454
136
 
455
- def inspect
456
- %(#<ImageProcessor:#{self.object_id} @media_file=#{@media_file.inspect}>)
457
- end
137
+ def export(user = nil)
138
+ super(user).merge({
139
+ :processed_value => processed_values
140
+ })
458
141
  end
459
142
 
460
-
143
+ self.register(:image, :photo)
144
+ end
461
145
  end
146
+
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Field
4
+ class Tags < Base
5
+ # Just use the standard String editor for now.
6
+ # TODO: This should be replaced with a tags specific one asap.
7
+ has_editor "Spontaneous.Field.String"
8
+
9
+ include Enumerable
10
+
11
+ def outputs
12
+ [:html, :tags]
13
+ end
14
+
15
+ def generate_html(value)
16
+ value
17
+ end
18
+
19
+ TAG_PARSER_RE = /"([^"]+)"|([^ ]+)/
20
+
21
+ def generate_tags(value)
22
+ return [] if value.blank?
23
+ (value).scan(TAG_PARSER_RE).flatten.compact
24
+ end
25
+
26
+ def taglist
27
+ values[:tags] || []
28
+ end
29
+
30
+ def each(&block)
31
+ taglist.each(&block)
32
+ end
33
+
34
+ self.register
35
+ end
36
+ end
@@ -97,7 +97,7 @@ module Spontaneous::Field
97
97
  # updater are re-serialized.
98
98
  #
99
99
  def save
100
- valid_fields = @fields.reject { |field| field.conflicted_update? }
100
+ valid_fields = @fields.reject { |field| field.invalid_update? || field.conflicted_update? }
101
101
  remove_update_lock(valid_fields)
102
102
  field_map = valid_fields.group_by { |f| f.owner }
103
103
  field_map.each do |owner, fields|
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Field
4
+ class WebVideo
5
+ class Fallback < Provider
6
+ def self.id
7
+ "fallback"
8
+ end
9
+
10
+ def to_html(options = {})
11
+ params = player_attributes(options)
12
+ attributes = hash_to_attributes(params[:attr])
13
+ %(<iframe #{attributes}></iframe>)
14
+ end
15
+
16
+ def player_attributes(options = {})
17
+ o = player_options(options)
18
+
19
+ attributes = {
20
+ :type => "text/html",
21
+ :frameborder => "0",
22
+ :width => o.delete(:width),
23
+ :height => o.delete(:height)
24
+ }
25
+
26
+ make_query_options!(o)
27
+
28
+ attributes[:src] = @field.unprocessed_value
29
+
30
+ attributes.update(:webkitAllowFullScreen => "yes", :allowFullScreen => "yes") if o[:fullscreen]
31
+
32
+ {:tagname => "iframe", :tag => "<iframe/>", :attr => attributes}
33
+ end
34
+
35
+ def player_options(options = {})
36
+ default_player_options.merge(options)
37
+ end
38
+ end
39
+ Spontaneous::Field::WebVideo.provider Fallback
40
+ end
41
+ end