spontaneous 0.2.0.alpha2 → 0.2.0.alpha3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. data/Gemfile +3 -40
  2. data/Rakefile +29 -41
  3. data/Readme.markdown +21 -8
  4. data/application/css/add_alias_dialogue.css.scss +79 -0
  5. data/application/css/{v2.scss → core.css.scss} +537 -550
  6. data/application/css/{definitions.scss → definitions.css.scss} +121 -33
  7. data/application/css/dialogue.css.scss +409 -0
  8. data/application/css/{editing.scss → editing.css.scss} +25 -262
  9. data/application/css/font.css.scss +8 -0
  10. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  11. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  12. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_flat_10_000000_40x100.png +0 -0
  13. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  14. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  15. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  16. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  17. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  18. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  19. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_222222_256x240.png +0 -0
  20. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_228ef1_256x240.png +0 -0
  21. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ef8c08_256x240.png +0 -0
  22. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffd27a_256x240.png +0 -0
  23. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffffff_256x240.png +0 -0
  24. data/application/css/jquery-ui-1.8.21.custom/ui-lightness.css.scss +565 -0
  25. data/application/css/{login.scss → login.css.scss} +4 -4
  26. data/application/css/meta.css.scss +331 -0
  27. data/application/css/{popover.scss → popover.css.scss} +9 -8
  28. data/application/css/{schema_error.scss → schema_error.css.scss} +4 -4
  29. data/application/css/spontaneous.css +5 -0
  30. data/application/css/unsupported.css.scss +42 -0
  31. data/application/js/add_alias_dialogue.js +72 -10
  32. data/application/js/ajax.js +50 -16
  33. data/application/js/compatibility.js +19 -15
  34. data/application/js/content.js +39 -36
  35. data/application/js/content_area.js +53 -5
  36. data/application/js/dialogue.js +17 -0
  37. data/application/js/dom.js +1 -1
  38. data/application/js/edit_panel.js +23 -8
  39. data/application/js/extensions.js +7 -2
  40. data/application/js/field_preview.js +2 -1
  41. data/application/js/field_types/date_field.js +11 -8
  42. data/application/js/field_types/file_field.js +188 -9
  43. data/application/js/field_types/image_field.js +46 -29
  44. data/application/js/field_types/markdown_field.js +57 -14
  45. data/application/js/field_types/select_field.js +72 -0
  46. data/application/js/field_types/string_field.js +8 -0
  47. data/application/js/field_types/webvideo_field.js +8 -0
  48. data/application/js/init.js +1 -7
  49. data/application/js/location.js +41 -13
  50. data/application/js/login.js +3 -0
  51. data/application/js/meta_view/user_admin.js +543 -0
  52. data/application/js/meta_view.js +1 -0
  53. data/application/js/metadata.js +20 -0
  54. data/application/js/page.js +17 -3
  55. data/application/js/page_browser.js +40 -30
  56. data/application/js/page_entry.js +4 -0
  57. data/application/js/panel/root_menu.js +66 -0
  58. data/application/js/popover.js +2 -2
  59. data/application/js/preview.js +1 -1
  60. data/application/js/publish.js +138 -30
  61. data/application/js/services.js +43 -0
  62. data/application/js/sharded_upload.js +2 -2
  63. data/application/js/spontaneous.js +64 -5
  64. data/application/js/state.js +20 -9
  65. data/application/js/top_bar.js +273 -150
  66. data/application/js/types.js +20 -15
  67. data/application/js/upload.js +1 -2
  68. data/application/js/user.js +18 -4
  69. data/application/js/vendor/date.js +104 -0
  70. data/application/js/vendor/jquery-ui-1.8.18.custom.min.js +356 -0
  71. data/application/js/views/box_view.js +15 -8
  72. data/application/js/views/page_piece_view.js +11 -8
  73. data/application/js/views/page_view.js +21 -3
  74. data/application/js/views/piece_view.js +19 -10
  75. data/application/js/views.js +3 -0
  76. data/application/static/chromelogo-200x52-45c7cbc93be080bea342df5fcda2ef8b.png +0 -0
  77. data/application/static/dot-texture-9eea29e4ac7ad9a772285252078ec127.png +0 -0
  78. data/application/static/editing-textarea-resize-s-b5af62365eb7e19ea4beccf7242d508e.png +0 -0
  79. data/application/static/editing-texture-1-42b06a3439752490988f30f2a06d5e7c.png +0 -0
  80. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  81. data/application/static/loop_alt1-white-7894b458528e92216196cae26b4c2c96.svg +12 -0
  82. data/application/static/spontaneous-states-e91ec89db525c62da0105b97cdd781ce.png +0 -0
  83. data/application/views/index.erb +2 -2
  84. data/application/views/login.erb +4 -8
  85. data/application/views/schema_modification_error.html.erb +1 -4
  86. data/application/views/unsupported.erb +9 -7
  87. data/bin/spot +1 -1
  88. data/db/migrations/20110209152710_users_and_groups.rb +10 -10
  89. data/db/migrations/20120305112647_site_modification_time.rb +11 -0
  90. data/db/migrations/20120418153903_add_ownership_of_content.rb +14 -0
  91. data/db/migrations/20120423175416_add_pending_modifications.rb +21 -0
  92. data/db/migrations/20120525164947_add_field_versions.rb +27 -0
  93. data/lib/sequel/plugins/scoped_table_name.rb +10 -1
  94. data/lib/spontaneous/asset/file.rb +25 -0
  95. data/lib/spontaneous/asset/source.rb +28 -0
  96. data/lib/spontaneous/asset.rb +75 -0
  97. data/lib/spontaneous/box.rb +6 -4
  98. data/lib/spontaneous/capistrano/deploy.rb +47 -0
  99. data/lib/spontaneous/capistrano/sync.rb +81 -0
  100. data/lib/spontaneous/capistrano.rb +13 -0
  101. data/lib/spontaneous/change.rb +60 -68
  102. data/lib/spontaneous/cli/assets.rb +29 -0
  103. data/lib/spontaneous/cli/base.rb +0 -48
  104. data/lib/spontaneous/cli/console.rb +1 -1
  105. data/lib/spontaneous/cli/server.rb +6 -4
  106. data/lib/spontaneous/cli/site.rb +28 -17
  107. data/lib/spontaneous/cli/user.rb +107 -0
  108. data/lib/spontaneous/cli.rb +100 -4
  109. data/lib/spontaneous/collections/entry_set.rb +2 -2
  110. data/lib/spontaneous/collections/field_set.rb +48 -22
  111. data/lib/spontaneous/collections/prototype_set.rb +20 -13
  112. data/lib/spontaneous/constants.rb +3 -0
  113. data/lib/spontaneous/content.rb +22 -5
  114. data/lib/spontaneous/errors.rb +3 -3
  115. data/lib/spontaneous/extensions/array.rb +12 -0
  116. data/lib/spontaneous/extensions/enumerable.rb +30 -0
  117. data/lib/spontaneous/extensions/nil.rb +3 -1
  118. data/lib/spontaneous/extensions/string.rb +16 -0
  119. data/lib/spontaneous/field_types/date_field.rb +45 -2
  120. data/lib/spontaneous/field_types/field.rb +42 -9
  121. data/lib/spontaneous/field_types/file_field.rb +68 -0
  122. data/lib/spontaneous/field_types/image_field.rb +63 -0
  123. data/lib/spontaneous/field_types/select_field.rb +109 -0
  124. data/lib/spontaneous/field_types/string_field.rb +6 -1
  125. data/lib/spontaneous/field_types/webvideo_field.rb +85 -27
  126. data/lib/spontaneous/field_types.rb +1 -1
  127. data/lib/spontaneous/field_version.rb +8 -0
  128. data/lib/spontaneous/generators/page.rb +1 -1
  129. data/lib/spontaneous/generators/site/Capfile.tt +1 -4
  130. data/lib/spontaneous/generators/site/Gemfile.tt +13 -6
  131. data/lib/spontaneous/generators/site/config/deploy.rb.tt +28 -0
  132. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +7 -2
  133. data/lib/spontaneous/generators/site.rb +1 -0
  134. data/lib/spontaneous/json.rb +34 -11
  135. data/lib/spontaneous/layout.rb +22 -0
  136. data/lib/spontaneous/media/file.rb +4 -0
  137. data/lib/spontaneous/output/assets/compression.rb +58 -0
  138. data/lib/spontaneous/output/assets.rb +32 -0
  139. data/lib/spontaneous/output/context.rb +179 -0
  140. data/lib/spontaneous/output/format/html.rb +5 -0
  141. data/lib/spontaneous/output/format/plain.rb +5 -0
  142. data/lib/spontaneous/output/format.rb +180 -0
  143. data/lib/spontaneous/output/helpers/classes_helper.rb +18 -0
  144. data/lib/spontaneous/{render/helpers/html_helper.rb → output/helpers/conditional_comment_helper.rb} +3 -12
  145. data/lib/spontaneous/output/helpers/script_helper.rb +73 -0
  146. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +61 -0
  147. data/lib/spontaneous/output/helpers.rb +28 -0
  148. data/lib/spontaneous/output/template/engine.rb +59 -0
  149. data/lib/spontaneous/output/template/renderer.rb +153 -0
  150. data/lib/spontaneous/output/template.rb +21 -0
  151. data/lib/spontaneous/output.rb +163 -0
  152. data/lib/spontaneous/page.rb +2 -1
  153. data/lib/spontaneous/paths.rb +6 -1
  154. data/lib/spontaneous/permissions/access_key.rb +5 -5
  155. data/lib/spontaneous/permissions/user.rb +81 -35
  156. data/lib/spontaneous/permissions/user_level.rb +26 -22
  157. data/lib/spontaneous/plugins/aliases.rb +76 -12
  158. data/lib/spontaneous/plugins/allowed_types.rb +60 -18
  159. data/lib/spontaneous/plugins/application/paths.rb +0 -28
  160. data/lib/spontaneous/plugins/application/system.rb +35 -0
  161. data/lib/spontaneous/plugins/boxes.rb +4 -0
  162. data/lib/spontaneous/plugins/content_groups.rb +16 -0
  163. data/lib/spontaneous/plugins/entries.rb +50 -30
  164. data/lib/spontaneous/plugins/fields.rb +15 -0
  165. data/lib/spontaneous/plugins/layouts.rb +8 -2
  166. data/lib/spontaneous/plugins/modifications.rb +228 -0
  167. data/lib/spontaneous/plugins/page/formats.rb +67 -42
  168. data/lib/spontaneous/plugins/page/request.rb +10 -0
  169. data/lib/spontaneous/plugins/page/site_timestamps.rb +28 -0
  170. data/lib/spontaneous/plugins/paths.rb +15 -3
  171. data/lib/spontaneous/plugins/publishing.rb +124 -45
  172. data/lib/spontaneous/plugins/render.rb +13 -8
  173. data/lib/spontaneous/plugins/schema_hierarchy.rb +18 -6
  174. data/lib/spontaneous/plugins/site/helpers.rb +53 -0
  175. data/lib/spontaneous/plugins/site/hooks.rb +50 -0
  176. data/lib/spontaneous/plugins/site/map.rb +1 -1
  177. data/lib/spontaneous/plugins/site/paths.rb +13 -0
  178. data/lib/spontaneous/plugins/site/publishing.rb +6 -2
  179. data/lib/spontaneous/plugins/site/{revisions.rb → state.rb} +5 -1
  180. data/lib/spontaneous/plugins/site/storage.rb +4 -0
  181. data/lib/spontaneous/plugins/site/url.rb +15 -0
  182. data/lib/spontaneous/plugins/site_map.rb +13 -3
  183. data/lib/spontaneous/plugins/styles.rb +5 -1
  184. data/lib/spontaneous/plugins/visibility.rb +39 -12
  185. data/lib/spontaneous/prototypes/box_prototype.rb +4 -0
  186. data/lib/spontaneous/prototypes/field_prototype.rb +15 -10
  187. data/lib/spontaneous/publishing/event_client.rb +46 -0
  188. data/lib/spontaneous/publishing/immediate.rb +81 -44
  189. data/lib/spontaneous/publishing/simultaneous.rb +23 -6
  190. data/lib/spontaneous/publishing.rb +4 -3
  191. data/lib/spontaneous/rack/around_back.rb +1 -5
  192. data/lib/spontaneous/rack/around_front.rb +4 -4
  193. data/lib/spontaneous/rack/around_preview.rb +4 -3
  194. data/lib/spontaneous/rack/assets.rb +81 -54
  195. data/lib/spontaneous/rack/authentication.rb +0 -1
  196. data/lib/spontaneous/rack/back.rb +160 -72
  197. data/lib/spontaneous/rack/cookie_authentication.rb +2 -2
  198. data/lib/spontaneous/rack/css.rb +18 -15
  199. data/lib/spontaneous/rack/event_source.rb +9 -21
  200. data/lib/spontaneous/rack/fiber_pool.rb +26 -0
  201. data/lib/spontaneous/rack/front.rb +12 -4
  202. data/lib/spontaneous/rack/helpers.rb +35 -13
  203. data/lib/spontaneous/rack/js.rb +41 -0
  204. data/lib/spontaneous/rack/public.rb +34 -44
  205. data/lib/spontaneous/rack/sse.rb +18 -0
  206. data/lib/spontaneous/rack/static.rb +3 -0
  207. data/lib/spontaneous/rack/user_admin.rb +100 -0
  208. data/lib/spontaneous/rack/user_helpers.rb +1 -1
  209. data/lib/spontaneous/rack.rb +6 -2
  210. data/lib/spontaneous/schema.rb +31 -4
  211. data/lib/spontaneous/search/index.rb +19 -3
  212. data/lib/spontaneous/search/results.rb +1 -1
  213. data/lib/spontaneous/sequel.rb +17 -0
  214. data/lib/spontaneous/site.rb +11 -4
  215. data/lib/spontaneous/state.rb +11 -0
  216. data/lib/spontaneous/storage/cloud.rb +4 -0
  217. data/lib/spontaneous/storage/local.rb +11 -0
  218. data/lib/spontaneous/style.rb +2 -2
  219. data/lib/spontaneous/tasks/database.rake +21 -22
  220. data/lib/spontaneous/utils/database/mysql_dumper.rb +4 -0
  221. data/lib/spontaneous/utils/database/postgres_dumper.rb +78 -0
  222. data/lib/spontaneous/utils/database.rb +6 -3
  223. data/lib/spontaneous/utils/smart_quotes.rb +499 -0
  224. data/lib/spontaneous/utils/smush_it.rb +66 -0
  225. data/lib/spontaneous/utils.rb +3 -1
  226. data/lib/spontaneous/version.rb +2 -2
  227. data/lib/spontaneous.rb +25 -29
  228. data/spontaneous.gemspec +186 -106
  229. data/test/experimental/test_features.rb +1 -1
  230. data/test/fixtures/asset_pipeline/application/css/basic.css.scss +4 -0
  231. data/test/fixtures/asset_pipeline/application/css/complex.css.scss.erb +6 -0
  232. data/test/fixtures/asset_pipeline/application/css/simple.css +3 -0
  233. data/test/fixtures/asset_pipeline/application/css/spontaneous.css +7 -0
  234. data/test/fixtures/asset_pipeline/application/css/subdir/complex.css.scss.erb +6 -0
  235. data/test/fixtures/asset_pipeline/application/css/subdir/library.css.scss +1 -0
  236. data/test/fixtures/asset_pipeline/application/css/subdir/simple.css +3 -0
  237. data/test/fixtures/asset_pipeline/application/js/basic.js.coffee +1 -0
  238. data/test/fixtures/asset_pipeline/application/js/complex.js.coffee.erb +1 -0
  239. data/test/fixtures/asset_pipeline/application/js/login.js +1 -0
  240. data/test/fixtures/asset_pipeline/application/js/require.js +1 -0
  241. data/test/fixtures/asset_pipeline/application/js/simple.js +1 -0
  242. data/test/fixtures/asset_pipeline/application/js/spontaneous.js +5 -0
  243. data/test/fixtures/asset_pipeline/application/js/subdir/complex.js.coffee.erb +1 -0
  244. data/test/fixtures/asset_pipeline/application/js/subdir/library.js.coffee +1 -0
  245. data/test/fixtures/asset_pipeline/application/js/subdir/simple.js +1 -0
  246. data/test/fixtures/asset_pipeline/application/js/vendor/jquery.js +1 -0
  247. data/test/fixtures/asset_pipeline/application/static/dot-texture.png +0 -0
  248. data/test/fixtures/asset_pipeline/application/static/subdir/px.gif +0 -0
  249. data/test/fixtures/assets/public1/css/a.scss +1 -0
  250. data/test/fixtures/assets/public1/js/a.js +1 -0
  251. data/test/fixtures/assets/public1/js/m.coffee +1 -0
  252. data/test/fixtures/assets/public2/css/b.scss +1 -0
  253. data/test/fixtures/assets/public2/css/c.css +1 -0
  254. data/test/fixtures/assets/public2/js/b.js +1 -0
  255. data/test/fixtures/assets/public2/js/c.js +1 -0
  256. data/test/fixtures/assets/public2/js/n.coffee +1 -0
  257. data/test/fixtures/back/config/user_levels.yml +3 -0
  258. data/test/fixtures/back/public/js/coffeescript.coffee +1 -0
  259. data/test/fixtures/back/templates/layouts/standard.css.cut +1 -0
  260. data/test/fixtures/back/templates/layouts/standard.js.cut +1 -0
  261. data/test/fixtures/example_application/config/database.yml +4 -4
  262. data/test/fixtures/helpers/templates/layouts/standard.html.cut +1 -0
  263. data/test/fixtures/helpers/templates/layouts/standard.mobile.cut +1 -0
  264. data/test/fixtures/images/vimlogo.pdf +0 -0
  265. data/test/fixtures/outputs/templates/layouts/standard.atom.cut +1 -0
  266. data/test/fixtures/permissions/config/user_levels.yml +6 -3
  267. data/test/fixtures/serialisation/class_hash.yaml.erb +1 -0
  268. data/test/fixtures/serialisation/root_hash.yaml.erb +2 -2
  269. data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
  270. data/test/fixtures/templates/extended/main.html.cut +5 -5
  271. data/test/fixtures/templates/extended/parent.html.cut +8 -8
  272. data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -1
  273. data/test/fixtures/templates/extended/with_includes.html.cut +6 -6
  274. data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +6 -7
  275. data/test/fixtures/templates/layouts/entries.html.cut +4 -4
  276. data/test/fixtures/templates/layouts/standard.html.cut +1 -0
  277. data/test/fixtures/templates/layouts/variables.html.cut +1 -1
  278. data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -1
  279. data/test/fixtures/templates/publishing/templates/layouts/static.rtf.cut +1 -0
  280. data/test/fixtures/templates/template_class/complex_template.html.cut +2 -2
  281. data/test/fixtures/templates/template_class/complex_template.pdf.cut +2 -2
  282. data/test/fixtures/templates/template_class/default_template_style.html.cut +1 -1
  283. data/test/fixtures/templates/template_class/images_with_template.html.cut +2 -2
  284. data/test/fixtures/templates/template_class/slots_template.html.cut +2 -2
  285. data/test/fixtures/templates/template_class/slots_template.pdf.cut +2 -2
  286. data/test/fixtures/user_manager/config/user_levels.yml +9 -0
  287. data/test/functional/test_application.rb +7 -7
  288. data/test/functional/test_back.rb +352 -97
  289. data/test/functional/test_front.rb +71 -20
  290. data/test/functional/test_user_manager.rb +284 -0
  291. data/test/javascript/env.js +13505 -0
  292. data/test/javascript/test_markdown.rb +43 -3
  293. data/test/support/custom_matchers.rb +3 -2
  294. data/test/test_helper.rb +50 -9
  295. data/test/test_javascript.rb +13 -13
  296. data/test/ui_helper.rb +1 -1
  297. data/test/unit/test_alias.rb +79 -8
  298. data/test/unit/test_asset_bundler.rb +220 -0
  299. data/test/unit/test_assets.rb +213 -0
  300. data/test/unit/test_async.rb +55 -0
  301. data/test/unit/test_authentication.rb +52 -39
  302. data/test/unit/test_boxes.rb +20 -15
  303. data/test/unit/test_changesets.rb +261 -0
  304. data/test/unit/test_content.rb +73 -33
  305. data/test/unit/test_content_inheritance.rb +18 -18
  306. data/test/unit/test_extensions.rb +26 -0
  307. data/test/unit/test_fields.rb +303 -16
  308. data/test/unit/test_formats.rb +267 -34
  309. data/test/unit/test_helpers.rb +79 -2
  310. data/test/unit/test_images.rb +10 -0
  311. data/test/unit/test_layouts.rb +21 -13
  312. data/test/unit/test_modifications.rb +648 -0
  313. data/test/unit/test_page.rb +6 -2
  314. data/test/unit/test_permissions.rb +101 -27
  315. data/test/unit/test_piece.rb +4 -4
  316. data/test/unit/test_plugins.rb +3 -2
  317. data/test/unit/test_publishing.rb +332 -0
  318. data/test/unit/test_render.rb +118 -67
  319. data/test/unit/test_revisions.rb +546 -0
  320. data/test/unit/test_schema.rb +83 -1
  321. data/test/unit/test_search.rb +59 -0
  322. data/test/unit/test_serialisation.rb +2 -47
  323. data/test/unit/test_site.rb +217 -108
  324. data/test/unit/test_storage.rb +26 -0
  325. data/test/unit/test_structure.rb +2 -2
  326. data/test/unit/test_styles.rb +90 -75
  327. data/test/unit/test_table_scoping.rb +21 -17
  328. data/test/unit/test_templates.rb +75 -69
  329. data/test/{slow → unit}/test_visibility.rb +78 -22
  330. metadata +528 -221
  331. data/application/css/add_alias_dialogue.scss +0 -27
  332. data/application/css/min/14c2a35812c443001b15d8b12a4780f88c678035.css +0 -1
  333. data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +0 -1
  334. data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +0 -1
  335. data/application/css/spontaneous.scss +0 -111
  336. data/application/css/unsupported.scss +0 -16
  337. data/application/css/variables.scss +0 -80
  338. data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +0 -3
  339. data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +0 -2
  340. data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +0 -3
  341. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +0 -2
  342. data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +0 -90
  343. data/application/static/diagonal-texture.png +0 -0
  344. data/application/static/editing-0-noise.png +0 -0
  345. data/application/static/editing-1-noise.png +0 -0
  346. data/application/static/editing-texture-1.png +0 -0
  347. data/application/static/editing-texture.png +0 -0
  348. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  349. data/application/static/editing-toolbar-shadow-top.png +0 -0
  350. data/application/static/inner-glow.png +0 -0
  351. data/application/static/item-buttons-highlight.png +0 -0
  352. data/application/static/item-buttons.png +0 -0
  353. data/application/static/paper-texture-dark.png +0 -0
  354. data/application/static/plus_alt.svg +0 -8
  355. data/application/static/select-arrow-root.png +0 -0
  356. data/application/static/slot-up-arrow.png +0 -0
  357. data/application/static/spontaneous.png +0 -0
  358. data/lib/cutaneous/context_helper.rb +0 -187
  359. data/lib/cutaneous/preview_context.rb +0 -32
  360. data/lib/cutaneous/preview_renderer.rb +0 -10
  361. data/lib/cutaneous/publish_context.rb +0 -10
  362. data/lib/cutaneous/publish_renderer.rb +0 -14
  363. data/lib/cutaneous/publish_template.rb +0 -62
  364. data/lib/cutaneous/publish_token_parser.rb +0 -8
  365. data/lib/cutaneous/renderer.rb +0 -124
  366. data/lib/cutaneous/request_context.rb +0 -9
  367. data/lib/cutaneous/request_renderer.rb +0 -15
  368. data/lib/cutaneous/request_template.rb +0 -11
  369. data/lib/cutaneous/request_token_parser.rb +0 -9
  370. data/lib/cutaneous/token_parser.rb +0 -125
  371. data/lib/cutaneous.rb +0 -48
  372. data/lib/spontaneous/render/context_base.rb +0 -143
  373. data/lib/spontaneous/render/development_renderer.rb +0 -14
  374. data/lib/spontaneous/render/engine.rb +0 -19
  375. data/lib/spontaneous/render/format/html.rb +0 -5
  376. data/lib/spontaneous/render/format.rb +0 -75
  377. data/lib/spontaneous/render/helpers/script_helper.rb +0 -17
  378. data/lib/spontaneous/render/helpers/stylesheet_helper.rb +0 -16
  379. data/lib/spontaneous/render/helpers.rb +0 -14
  380. data/lib/spontaneous/render/preview_context.rb +0 -8
  381. data/lib/spontaneous/render/preview_renderer.rb +0 -24
  382. data/lib/spontaneous/render/publish_context.rb +0 -22
  383. data/lib/spontaneous/render/published_renderer.rb +0 -53
  384. data/lib/spontaneous/render/publishing_renderer.rb +0 -16
  385. data/lib/spontaneous/render/render_cache.rb +0 -26
  386. data/lib/spontaneous/render/renderer.rb +0 -50
  387. data/lib/spontaneous/render/request_context.rb +0 -8
  388. data/lib/spontaneous/render.rb +0 -214
  389. data/test/experimental/test_cutaneous.rb +0 -309
  390. data/test/fixtures/application/css/test.less +0 -5
  391. data/test/slow/test_publishing.rb +0 -1006
  392. /data/application/css/{developer.scss → developer.css.scss} +0 -0
  393. /data/application/js/vendor/{jquery-1.7.1.min.js → jquery.js} +0 -0
  394. /data/application/static/{location-arrow.png → location-arrow-c1c1d3ca472481c61a0a5f8cb289d743.png} +0 -0
  395. /data/application/static/{missing.png → missing-911ce6dbd9f4602e0f3fbcd7e78846a2.png} +0 -0
  396. /data/application/static/{orange-down-arrow.png → orange-down-arrow-395ae1929e8662b2ff0977daf12c35bb.png} +0 -0
  397. /data/application/static/{page-browser-next.png → page-browser-next-ce781a242c23b980b99b9db7abc20b05.png} +0 -0
  398. /data/application/static/{plus-box.png → plus-box-dcde74a1e496f68298c9b443caa1c5d5.png} +0 -0
  399. /data/application/static/{select-arrow.png → select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png} +0 -0
  400. /data/application/static/{slot-down-arrow.png → slot-down-arrow-59ad5f5ee5b52a7ebd00bca4b3104194.png} +0 -0
  401. /data/application/static/{splash.png → splash-65b493a714df9b8b3ab170103401b53d.png} +0 -0
  402. /data/application/static/{spot.png → spot-71fab1d2f065034f5fc15e7bea2ad36c.png} +0 -0
  403. /data/application/static/{spot.svg → spot-8505041082d8d3bbe8d34c29dddb3b7d.svg} +0 -0
  404. /data/application/static/{texture.png → texture-03f7627e8264b1d607113ab32c593a58.png} +0 -0
@@ -27,6 +27,7 @@ module Spontaneous
27
27
  say "Generating '#{domain}'...", :bold
28
28
  @domain = domain
29
29
  @site_name = domain.to_s.gsub(/\./, "_")
30
+ @username = domain.split(/\./).first
30
31
  self.destination_root = options[:root]
31
32
  empty_directory(@site_name)
32
33
  self.destination_root = self.destination_root / @site_name
@@ -1,25 +1,48 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ require 'oj'
4
+
5
+ Oj.default_options = {
6
+ symbol_keys: true,
7
+ mode: :compat
8
+ } if defined?(Oj)
9
+
3
10
  module Spontaneous
4
11
  module JSON
5
- module ModuleMethods
6
- def parser
7
- Yajl::Parser.new(:symbolize_keys => true)
8
- end
9
- def encoder
10
- Yajl::Encoder.new
11
- end
12
-
12
+ module OjParser
13
13
  def parse(json_string)
14
- parser.parse(json_string)
14
+ ::Oj.load(json_string)
15
+ rescue
16
+ nil
15
17
  end
16
18
 
17
19
  def encode(object)
18
- encoder.encode(object)
20
+ ::Oj.dump(object)
21
+ end
22
+ end
23
+
24
+ if defined?(Yajl)
25
+ module YajlParser
26
+ def parser
27
+ Yajl::Parser.new(:symbolize_keys => true)
28
+ end
29
+ def encoder
30
+ Yajl::Encoder.new
31
+ end
32
+
33
+ def parse(json_string)
34
+ parser.parse(json_string)
35
+ rescue
36
+ nil
37
+ end
38
+
39
+ def encode(object)
40
+ encoder.encode(object)
41
+ end
19
42
  end
20
43
  end
21
44
 
22
- extend ModuleMethods
45
+ extend OjParser
23
46
 
24
47
  def parse_json(json_string)
25
48
  Spontaneous::JSON.parse(json_string)
@@ -11,5 +11,27 @@ module Spontaneous
11
11
  [["layouts", "standard"]]
12
12
  end
13
13
  end
14
+
15
+ class Anonymous
16
+ def initialize(template_proc)
17
+ @template_proc = template_proc
18
+ end
19
+
20
+ def template(format = :html)
21
+ @template_proc
22
+ end
23
+
24
+ def exists?(format = :html)
25
+ true
26
+ end
27
+
28
+ def name
29
+ nil
30
+ end
31
+
32
+ def schema_id
33
+ nil
34
+ end
35
+ end
14
36
  end
15
37
  end
@@ -37,6 +37,10 @@ module Spontaneous::Media
37
37
  F.extname(filename)
38
38
  end
39
39
 
40
+ def filesize
41
+ F.size(source)
42
+ end
43
+
40
44
  def storage
41
45
  @storage ||= Spontaneous::Site.storage(mimetype)
42
46
  end
@@ -0,0 +1,58 @@
1
+ require 'shine'
2
+ require 'sass'
3
+
4
+ module Spontaneous
5
+ module Output
6
+ module Assets
7
+ module Compression
8
+ extend self
9
+
10
+ def compress_js(filelist, options={})
11
+ shine_compress_files(filelist, :js, options)
12
+ end
13
+
14
+ def compress_js_string(js, options={})
15
+ shine_compress_string(js, :js, options)
16
+ end
17
+
18
+ def compress_css(filelist, options={})
19
+ # compress_files(filelist, :css, options)
20
+ opts = {
21
+ :load_paths => [Spontaneous.css_dir],
22
+ # :filename => sass_template,
23
+ :cache => false,
24
+ :style => :compressed
25
+ }.merge(options)
26
+ css = filelist.map do |path|
27
+ Sass::Engine.for_file(path, opts).render
28
+ end.join("\n")
29
+ hash = digest(css)
30
+ [css, hash]
31
+ end
32
+
33
+ def shine_compress_string(string, format, options = {})
34
+ compressed = Shine::compress_string(string, format, options).force_encoding("UTF-8")
35
+ hash = digest(compressed)
36
+ [compressed, hash]
37
+ end
38
+
39
+ def shine_compress_files(filelist, format, options = {})
40
+ original_size = filesize(filelist)
41
+ compressed = Shine::compress_files(filelist, format, options).force_encoding("UTF-8")
42
+ logger.info("Compressed #{filelist.length} files. Original size #{original_size}, compressed size #{compressed.length}, ratio #{(100*compressed.length.to_f/original_size.to_f).round}%")
43
+ hash = digest(compressed)
44
+ [compressed, hash]
45
+ end
46
+
47
+ def digest(str)
48
+ hash = Digest::SHA1.new.update(str).hexdigest
49
+ end
50
+
51
+
52
+ def filesize(paths)
53
+ paths.compact.inject(0) { |sum, path| sum += File.size(path) }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,32 @@
1
+ module Spontaneous
2
+ module Output
3
+ module Assets
4
+ extend self
5
+
6
+ def compress_js(file_paths, options={})
7
+ Compression.compress_js(file_paths, options)
8
+ end
9
+
10
+ def url(file = nil)
11
+ Spontaneous::Output.asset_url(file)
12
+ end
13
+
14
+ def path_for(revision, path = nil)
15
+ File.join [Spontaneous::Output.asset_path(revision), path].compact
16
+ end
17
+
18
+ def find_file(*relative_paths)
19
+ relative_paths.flatten!
20
+ Spontaneous.instance.paths.expanded(:public).each do |root|
21
+ relative_paths.each do |relative_path|
22
+ path = root / relative_path
23
+ return path if ::File.exist?(path)
24
+ end
25
+ end
26
+ nil
27
+ end
28
+
29
+ autoload :Compression, "spontaneous/output/assets/compression"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,179 @@
1
+
2
+ module Spontaneous::Output::Context
3
+ module ContextCore
4
+ attr_accessor :__renderer
5
+
6
+ def navigation(depth = 1, &block)
7
+ case depth
8
+ when 0, :root
9
+ root
10
+ when 1, :section
11
+ navigation_at_depth(1, &block)
12
+ else
13
+ navigation_at_depth(depth, &block)
14
+ end
15
+ end
16
+
17
+ def navigation_at_depth(depth = 1)
18
+ current_page = __target.page
19
+ __pages_at_depth(current_page, depth).each do |p|
20
+ yield(p, current_page.active?(p))
21
+ end
22
+ end
23
+
24
+ def __pages_at_depth(origin_page, depth)
25
+ origin_page.at_depth(depth)
26
+ end
27
+
28
+ def page
29
+ __target.page
30
+ end
31
+
32
+ def live?
33
+ Spontaneous.production? && publishing?
34
+ end
35
+
36
+ def show_errors?
37
+ Spontaneous.development?
38
+ end
39
+
40
+ def root
41
+ Spontaneous::Site.root
42
+ end
43
+
44
+ def publishing?
45
+ false
46
+ end
47
+
48
+ def each
49
+ content.each { |c| yield(c) } if block_given?
50
+ end
51
+
52
+ def each_with_index
53
+ content.each_with_index { |c, i| yield(c, i) } if block_given?
54
+ end
55
+
56
+ def map
57
+ content.map { |c| yield(c) } if block_given?
58
+ end
59
+
60
+ def content
61
+ __target.iterable
62
+ end
63
+
64
+ def pieces
65
+ content
66
+ end
67
+
68
+ def render_content
69
+ __target.map do |c|
70
+ __render_content(c)
71
+ end.join("\n")
72
+ end
73
+
74
+ def first
75
+ content.first
76
+ end
77
+
78
+ def last
79
+ content.last
80
+ end
81
+
82
+ def first?
83
+ __target.owner.pieces.first == self
84
+ end
85
+
86
+ def last?
87
+ __target.owner.pieces.last == self
88
+ end
89
+
90
+ def __format
91
+ __loader.format
92
+ end
93
+
94
+ def __decode_params(param)
95
+ unless param.is_a?(String)
96
+ @_render_method ||= "to_#{__loader.format}".to_sym
97
+ if param.respond_to?(@_render_method)
98
+ param = param.send(@_render_method)
99
+ else
100
+ if param.respond_to?(:render)
101
+ param = __render_content(param) #render(param, param.template)
102
+ end
103
+ end
104
+ end
105
+ param.to_s
106
+ end
107
+
108
+ # Has to be routed through the top-level renderer so as to make
109
+ # use of shared caches that are held by it.
110
+ def __render_content(content)
111
+ if content.respond_to?(:render_using)
112
+ content.render_using(__renderer, __format, self)
113
+ else
114
+ content.render(__format, self)
115
+ end
116
+ end
117
+ end
118
+
119
+ module RenderCache
120
+ def _render_cache_value(key)
121
+ __renderer.render_cache[key]
122
+ end
123
+
124
+ def _render_cache_set_value(key, value)
125
+ __renderer.render_cache[key] = value
126
+ end
127
+
128
+ def _render_cache_key?(key)
129
+ __renderer.render_cache.key?(key)
130
+ end
131
+
132
+ def _with_render_cache(key, &value_block)
133
+ if _render_cache_key?(key)
134
+ _render_cache_value(key)
135
+ else
136
+ _render_cache_set_value(key, yield)
137
+ end
138
+ end
139
+ end
140
+
141
+ module PublishContext
142
+ include RenderCache
143
+
144
+ def root
145
+ _with_render_cache("site.root") do
146
+ super
147
+ end
148
+ end
149
+
150
+ def compressed_scripts(scripts)
151
+ _with_render_cache(scripts.join(",")) do
152
+ super(scripts)
153
+ end
154
+ end
155
+
156
+ def compressed_stylesheets(stylesheets)
157
+ _with_render_cache(stylesheets.join(",")) do
158
+ super(stylesheets)
159
+ end
160
+ end
161
+
162
+ def __pages_at_depth(origin_page, depth)
163
+ _with_render_cache("pages_at_depth.#{origin_page.id}.#{depth}") do
164
+ super
165
+ end
166
+ end
167
+
168
+ def publishing?
169
+ true
170
+ end
171
+ end
172
+
173
+ module PreviewContext
174
+ end
175
+
176
+ module RequestContext
177
+ end
178
+
179
+ end
@@ -0,0 +1,5 @@
1
+ module Spontaneous::Output
2
+ class HTML < Spontaneous::Output::Format
3
+ provides_format :html
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Spontaneous::Output
2
+ class Plain < Spontaneous::Output::Format
3
+ provides_format :plain
4
+ end
5
+ end
@@ -0,0 +1,180 @@
1
+
2
+ module Spontaneous::Output
3
+ class Format
4
+ module ClassMethods
5
+ # class_attribute :template_engine
6
+
7
+ def inherited(subclass)
8
+ subclass.helper_formats.concat helper_formats
9
+ end
10
+
11
+ def provides_format(*formats)
12
+ helper_formats.concat formats
13
+ Spontaneous::Output.register_format(self, *formats)
14
+ end
15
+
16
+ def helper_formats
17
+ @helper_formats ||= []
18
+ end
19
+
20
+ def configure(output_name, options)
21
+ format = options[:format]
22
+ extension = options[:extension]
23
+ language = options[:language]
24
+ mimetype = options[:mimetype] || options[:mime_type] || calculate_mimetype(format)
25
+ options.update({
26
+ :format => format.to_sym,
27
+ :mimetype => mimetype,
28
+ :extension => extension,
29
+ :language => language
30
+ })
31
+ @name = output_name.to_sym
32
+ @options = default_options.merge(options)
33
+ end
34
+
35
+ def calculate_mimetype(format)
36
+ ::Rack::Mime.mime_type(".#{format}", nil) || inherited_mimetype
37
+ end
38
+
39
+ def default_options
40
+ { :private => false,
41
+ :dynamic => false }
42
+ end
43
+
44
+ def inherited_mimetype
45
+ ::Rack::Mime.mime_type(".#{helper_formats.first}")
46
+ end
47
+
48
+ def mimetype
49
+ return inherited_mimetype if @options.nil?
50
+ @options[:mimetype]
51
+ end
52
+
53
+ alias_method :mime_type, :mimetype
54
+ def format
55
+ @options[:format]
56
+ end
57
+
58
+ def name
59
+ @name
60
+ end
61
+
62
+ alias_method :extension, :name
63
+
64
+ def to_sym
65
+ @name
66
+ end
67
+
68
+ def extension(is_dynamic = false, dynamic_extension = Spontaneous::Output::Template.extension)
69
+ if (override = @options[:extension])
70
+ return normalise_extension(override.to_s)
71
+ end
72
+ ext = normalise_extension(name.to_s)
73
+ ext << ".#{self.dynamic_extension(dynamic_extension)}" if (is_dynamic or self.dynamic?)
74
+ ext
75
+ end
76
+
77
+ def normalise_extension(ext)
78
+ ext = "." << ext unless ext.start_with?(".")
79
+ ext
80
+ end
81
+
82
+ def dynamic_extension(default_extension)
83
+ @options[:language] || default_extension
84
+ end
85
+
86
+ def private?
87
+ @options[:private]
88
+ end
89
+
90
+ def public?
91
+ !self.private?
92
+ end
93
+
94
+ def dynamic?
95
+ @options[:dynamic]
96
+ end
97
+
98
+ def postprocess
99
+ @options[:postprocess]
100
+ end
101
+
102
+ def context
103
+ Spontaneous::Site.context (helper_formats + [name]).uniq.compact
104
+ end
105
+ end
106
+
107
+ extend ClassMethods
108
+ extend Forwardable
109
+
110
+ attr_reader :page
111
+ attr_accessor :content
112
+
113
+ def_delegators "self.class", :format, :dynamic?, :extension, :to_sym, :mimetype, :mime_type, :public?, :private?, :context, :name, :extension
114
+
115
+ def initialize(page, content = nil)
116
+ @page, @content = page, content
117
+ @content ||= page
118
+ end
119
+
120
+ def render(params = {}, *args)
121
+ render_using(default_renderer, params, *args)
122
+ end
123
+
124
+ def render_using(renderer, params, *args)
125
+ before_render
126
+ output = render_page(renderer, params, *args)
127
+ output = postprocess(output)
128
+ after_render(output)
129
+ output
130
+ end
131
+
132
+ def default_renderer
133
+ Spontaneous::Output.renderer
134
+ end
135
+
136
+ def before_render
137
+ end
138
+
139
+ def after_render(output)
140
+ end
141
+
142
+ def postprocess(output)
143
+ if (process = self.class.postprocess) && (process.is_a?(Proc))
144
+ output = process.call(@page, output)
145
+ end
146
+ output
147
+ end
148
+
149
+ def render_page(renderer, params = {}, *args)
150
+ renderer.render(self, params, *args)
151
+ end
152
+
153
+ def publish_page(renderer, revision)
154
+ rendered = render_using(renderer, {:revision => revision})
155
+ path = output_path(revision, rendered)
156
+ File.open(path, 'w') do |file|
157
+ case rendered
158
+ when IO
159
+ IO.copy_stream(rendered, file)
160
+ else
161
+ file.write(rendered.to_s)
162
+ end
163
+ end
164
+ end
165
+
166
+ def output_path(revision, render)
167
+ ext = nil
168
+ template_dynamic = Spontaneous::Output::Template.is_dynamic?(render)
169
+ path = Spontaneous::Output.output_path(revision, self, template_dynamic)
170
+
171
+ dir = File.dirname(path)
172
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
173
+ path
174
+ end
175
+ end
176
+ end
177
+
178
+ Dir[File.join(File.dirname(__FILE__), 'format', '*.rb')].each do |format|
179
+ require format
180
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ module Spontaneous::Output::Helpers
4
+ module ClassesHelper
5
+ extend self
6
+
7
+ def classes(*args)
8
+ args = args.flatten
9
+ optional = args.extract_options!
10
+ optional.each do |class_name, active|
11
+ args << class_name if active
12
+ end
13
+ return "" if args.empty?
14
+ %(class="#{args.join(" ")}")
15
+ end
16
+ Spontaneous::Output::Helpers.register_helper(self, :html)
17
+ end
18
+ end
@@ -1,19 +1,9 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module Spontaneous::Render::Helpers
4
- module HTMLHelper
3
+ module Spontaneous::Output::Helpers
4
+ module ConditionalCommentHelper
5
5
  extend self
6
6
 
7
- def classes(*args)
8
- args = args.flatten
9
- optional = args.extract_options!
10
- optional.each do |class_name, active|
11
- args << class_name if active
12
- end
13
- return "" if args.empty?
14
- %(class="#{args.join(" ")}")
15
- end
16
-
17
7
  def ie_only(version = nil)
18
8
  ie_conditional_comment(version)
19
9
  end
@@ -65,5 +55,6 @@ module Spontaneous::Render::Helpers
65
55
  end
66
56
  end
67
57
 
58
+ Spontaneous::Output::Helpers.register_helper(self, :html)
68
59
  end
69
60
  end
@@ -0,0 +1,73 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'coffee-script'
4
+
5
+ module Spontaneous::Output::Helpers
6
+ module ScriptHelper
7
+ extend self
8
+
9
+ def scripts(*args)
10
+ scripts = args.flatten
11
+ options = scripts.extract_options!
12
+ compress = (live? or (publishing? and options[:force_compression]))
13
+ return compressed_scripts(scripts) if compress
14
+ scripts.map { |script| script_tag(script) }.join("\n")
15
+ end
16
+
17
+ alias_method :script, :scripts
18
+
19
+ def script_tag(src)
20
+ src = "#{src}.js" unless src =~ /\.js$/o
21
+ %(<script type="text/javascript" src="#{src}"></script>)
22
+ end
23
+
24
+ def convert_coffeescript(url)
25
+ S::Output::Assets.compile_coffeescript(url)
26
+ end
27
+
28
+ def compressed_scripts(scripts)
29
+ file_paths = scripts.map { |script| [script, S::Output::Assets.find_file("#{script}.js", "#{script}.coffee")] }
30
+ invalid, file_paths = file_paths.partition { |url, path| path.nil? }
31
+
32
+ tags = []
33
+ unless file_paths.empty?
34
+ # in order to compile coffeescript efficiently, avoiding multiple anonymous function wrappers
35
+ # but keeping the files in the correct order
36
+ # first partition files into js & coffee groups:
37
+ types = file_paths.slice_between { |(purl, ppath), (url, path)| File.extname(ppath) != File.extname(path) }
38
+ # then iterate through each group to concatenate the source into a single string (src)
39
+ js = types.map { |type|
40
+ ext = nil
41
+ src = type.map { |url, path|
42
+ ext = File.extname(path)
43
+ File.read(path)
44
+ }.join
45
+ # then compile the concatenated src if it's coffeescript
46
+ case ext
47
+ when ".coffee"
48
+ CoffeeScript.compile src
49
+ else
50
+ src
51
+ end
52
+ }.join
53
+
54
+ compressed, hash = compress_js_string(js)
55
+ output_path = Spontaneous::Output::Assets.path_for(revision, "#{hash}.js")
56
+
57
+ FileUtils.mkdir_p(File.dirname(output_path))
58
+ File.open(output_path, "w") { |file| file.write(compressed) }
59
+
60
+ tags = [script_tag(Spontaneous::Output::Assets.url(hash))]
61
+ end
62
+
63
+ tags.concat invalid.map { |src, path| script_tag(src) }
64
+ tags.join("\n")
65
+ end
66
+
67
+ def compress_js_string(js_string)
68
+ Spontaneous::Output::Assets::Compression.shine_compress_string(js_string, :js)
69
+ end
70
+
71
+ Spontaneous::Output::Helpers.register_helper(self, :html)
72
+ end
73
+ end