cmsimple 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. data/.gitignore +31 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +16 -0
  4. data/Gemfile +20 -0
  5. data/Gemfile.ci +5 -0
  6. data/LICENSE +19 -0
  7. data/README.md +118 -0
  8. data/Rakefile +47 -0
  9. data/app/assets/javascripts/cmsimple.js +61 -0
  10. data/app/assets/javascripts/cmsimple/controllers/editor.coffee +102 -0
  11. data/app/assets/javascripts/cmsimple/lib/namespaces.coffee +3 -0
  12. data/app/assets/javascripts/cmsimple/lib/support.coffee +4 -0
  13. data/app/assets/javascripts/cmsimple/mercury/config.js +462 -0
  14. data/app/assets/javascripts/cmsimple/mercury/handlers.coffee +9 -0
  15. data/app/assets/javascripts/cmsimple/models/image.coffee +49 -0
  16. data/app/assets/javascripts/cmsimple/models/page.coffee +106 -0
  17. data/app/assets/javascripts/cmsimple/models/path.coffee +31 -0
  18. data/app/assets/javascripts/cmsimple/models/version.coffee +29 -0
  19. data/app/assets/javascripts/cmsimple/panels/images/index.coffee +2 -0
  20. data/app/assets/javascripts/cmsimple/panels/images/list.coffee +48 -0
  21. data/app/assets/javascripts/cmsimple/panels/images/panel.coffee +69 -0
  22. data/app/assets/javascripts/cmsimple/panels/images/selection.coffee +52 -0
  23. data/app/assets/javascripts/cmsimple/panels/page_metadata.coffee +42 -0
  24. data/app/assets/javascripts/cmsimple/panels/publish.coffee +32 -0
  25. data/app/assets/javascripts/cmsimple/panels/redirects/form.coffee +51 -0
  26. data/app/assets/javascripts/cmsimple/panels/redirects/index.coffee +2 -0
  27. data/app/assets/javascripts/cmsimple/panels/redirects/list.coffee +34 -0
  28. data/app/assets/javascripts/cmsimple/panels/redirects/panel.coffee +39 -0
  29. data/app/assets/javascripts/cmsimple/panels/sitemap/index.coffee +2 -0
  30. data/app/assets/javascripts/cmsimple/panels/sitemap/panel.coffee +40 -0
  31. data/app/assets/javascripts/cmsimple/panels/sitemap/sortable.coffee +55 -0
  32. data/app/assets/javascripts/cmsimple/panels/sitemap/tree.coffee +61 -0
  33. data/app/assets/javascripts/cmsimple/panels/versions/index.coffee +2 -0
  34. data/app/assets/javascripts/cmsimple/panels/versions/list.coffee +51 -0
  35. data/app/assets/javascripts/cmsimple/panels/versions/panel.coffee +53 -0
  36. data/app/assets/javascripts/cmsimple/views/image_library/_item.jst.hamlc +24 -0
  37. data/app/assets/javascripts/cmsimple/views/image_library/list.jst.hamlc +8 -0
  38. data/app/assets/javascripts/cmsimple/views/redirects/_path.jst.hamlc +6 -0
  39. data/app/assets/javascripts/cmsimple/views/redirects/list.jst.hamlc +19 -0
  40. data/app/assets/javascripts/cmsimple/views/sitemap/_page.jst.hamlc +9 -0
  41. data/app/assets/javascripts/cmsimple/views/sitemap/tree.jst.hamlc +5 -0
  42. data/app/assets/javascripts/cmsimple/views/versions/_item.jst.hamlc +6 -0
  43. data/app/assets/javascripts/cmsimple/views/versions/list.jst.hamlc +4 -0
  44. data/app/assets/stylesheets/cmsimple.css +15 -0
  45. data/app/assets/stylesheets/cmsimple/forms.css +10 -0
  46. data/app/assets/stylesheets/cmsimple/panels.css +399 -0
  47. data/app/assets/stylesheets/cmsimple/toolbar-images.css +27 -0
  48. data/app/assets/stylesheets/mercury_overrides.css +2 -0
  49. data/app/controllers/cmsimple/front_controller.rb +38 -0
  50. data/app/controllers/cmsimple/images_controller.rb +28 -0
  51. data/app/controllers/cmsimple/mercury_controller.rb +7 -0
  52. data/app/controllers/cmsimple/pages_controller.rb +89 -0
  53. data/app/controllers/cmsimple/paths_controller.rb +23 -0
  54. data/app/controllers/cmsimple/snippets_controller.rb +23 -0
  55. data/app/controllers/cmsimple/versions_controller.rb +17 -0
  56. data/app/helpers/cmsimple/regions_helper.rb +38 -0
  57. data/app/models/cmsimple/image.rb +19 -0
  58. data/app/models/cmsimple/page.rb +203 -0
  59. data/app/models/cmsimple/path.rb +63 -0
  60. data/app/models/cmsimple/region.rb +43 -0
  61. data/app/models/cmsimple/snippet.rb +64 -0
  62. data/app/models/cmsimple/version.rb +18 -0
  63. data/app/uploaders/image_attachment_uploader.rb +53 -0
  64. data/app/views/cmsimple/images/_form.html.haml +13 -0
  65. data/app/views/cmsimple/images/new.html.haml +5 -0
  66. data/app/views/cmsimple/pages/_form.html.haml +49 -0
  67. data/app/views/cmsimple/pages/_form_extras.html.haml +2 -0
  68. data/app/views/cmsimple/pages/edit.html.haml +3 -0
  69. data/app/views/cmsimple/pages/new.html.haml +3 -0
  70. data/app/views/cmsimple/pages/publish.html.haml +12 -0
  71. data/app/views/cmsimple/snippets/index.html.haml +5 -0
  72. data/app/views/cmsimple/templates/default.html.haml +4 -0
  73. data/app/views/layouts/editor.html.haml +12 -0
  74. data/app/views/layouts/panel.html.haml +9 -0
  75. data/cmsimple.gemspec +44 -0
  76. data/config.ru +4 -0
  77. data/config/application.rb +1 -0
  78. data/config/cucumber.yml +8 -0
  79. data/config/environment.rb +2 -0
  80. data/config/routes.rb +34 -0
  81. data/db/migrate/20120201221410_create_cmsimple_pages.rb +10 -0
  82. data/db/migrate/20120222185901_add_title_parent_id_and_position_to_pages.rb +10 -0
  83. data/db/migrate/20120229185214_add_slug_to_pages.rb +7 -0
  84. data/db/migrate/20120323200439_add_is_root_to_page.rb +5 -0
  85. data/db/migrate/20120328174339_add_meta_info_to_cmsimple_pages.rb +9 -0
  86. data/db/migrate/20120329172857_create_cmsimple_path.rb +11 -0
  87. data/db/migrate/20120407024752_create_cmsimple_images.rb +13 -0
  88. data/db/migrate/20120410041105_add_timestamps_to_cmsimple_pages.rb +7 -0
  89. data/db/migrate/20120425211937_add_published_at_to_cmsimple_pages.rb +6 -0
  90. data/db/migrate/20120430175047_create_cmsimple_versions.rb +13 -0
  91. data/db/migrate/20120831233927_rename_path_to_current_uri_on_paths.rb +5 -0
  92. data/features/create.feature +18 -0
  93. data/features/delete.feature +12 -0
  94. data/features/edit.feature +54 -0
  95. data/features/publishing.feature +31 -0
  96. data/features/redirects.feature +27 -0
  97. data/features/step_definitions/mercury_steps.rb +440 -0
  98. data/features/step_definitions/page_steps.rb +269 -0
  99. data/features/step_definitions/web_steps.rb +254 -0
  100. data/features/support/env.rb +77 -0
  101. data/features/support/mercury_content.rb +25 -0
  102. data/features/support/mercury_selectors.rb +148 -0
  103. data/features/support/paths.rb +16 -0
  104. data/features/support/selectors.rb +26 -0
  105. data/features/support/utils.rb +18 -0
  106. data/features/versioning.feature +27 -0
  107. data/features/visit.feature +7 -0
  108. data/lib/cmsimple.rb +22 -0
  109. data/lib/cmsimple/configuration.rb +65 -0
  110. data/lib/cmsimple/exts/to_bool.rb +25 -0
  111. data/lib/cmsimple/page_responder.rb +46 -0
  112. data/lib/cmsimple/rails.rb +5 -0
  113. data/lib/cmsimple/regions_proxy.rb +32 -0
  114. data/lib/cmsimple/template_resolver.rb +14 -0
  115. data/lib/cmsimple/template_responder.rb +12 -0
  116. data/lib/cmsimple/version.rb +3 -0
  117. data/lib/generators/cmsimple/install/install_generator.rb +46 -0
  118. data/lib/generators/cmsimple/install/templates/default.html.erb +10 -0
  119. data/lib/generators/cmsimple/install/templates/default.html.haml +6 -0
  120. data/lib/generators/cmsimple/install/templates/initializer.rb +22 -0
  121. data/lib/generators/cmsimple/snippet/snippet_generator.rb +56 -0
  122. data/lib/generators/cmsimple/snippet/templates/cell.rb +18 -0
  123. data/lib/generators/cmsimple/snippet/templates/display.html.erb +14 -0
  124. data/lib/generators/cmsimple/snippet/templates/display.html.haml +11 -0
  125. data/lib/generators/cmsimple/snippet/templates/options.html.erb +18 -0
  126. data/lib/generators/cmsimple/snippet/templates/options.html.haml +12 -0
  127. data/script/app +2 -0
  128. data/script/migrate +2 -0
  129. data/script/rails +8 -0
  130. data/spec/fixtures/rails.png +0 -0
  131. data/spec/helpers/regions_helper_spec.rb +62 -0
  132. data/spec/javascripts/controllers/editor_spec.coffee +57 -0
  133. data/spec/javascripts/models/image_geometry_spec.coffee +64 -0
  134. data/spec/javascripts/models/image_spec.coffee +4 -0
  135. data/spec/javascripts/models/page_spec.coffee +121 -0
  136. data/spec/javascripts/models/path_spec.coffee +39 -0
  137. data/spec/javascripts/models/version_spec.coffee +31 -0
  138. data/spec/javascripts/panels/images/selection_spec.coffee +104 -0
  139. data/spec/javascripts/panels/sitemap/panel_spec.coffee +10 -0
  140. data/spec/javascripts/panels/sitemap/sortable_spec.coffee +63 -0
  141. data/spec/javascripts/panels/sitemap/tree_spec.coffee +62 -0
  142. data/spec/javascripts/spec_helper.coffee +25 -0
  143. data/spec/javascripts/support/stubs.coffee +16 -0
  144. data/spec/lib/page_responder_spec.rb +58 -0
  145. data/spec/lib/regions_proxy_spec.rb +47 -0
  146. data/spec/models/image_spec.rb +46 -0
  147. data/spec/models/page_spec.rb +237 -0
  148. data/spec/models/path_spec.rb +71 -0
  149. data/spec/models/region_spec.rb +14 -0
  150. data/spec/models/snippet_spec.rb +57 -0
  151. data/spec/models/version_spec.rb +7 -0
  152. data/spec/rails_app/.gitignore +33 -0
  153. data/spec/rails_app/Rakefile +7 -0
  154. data/spec/rails_app/app/assets/images/rails.png +0 -0
  155. data/spec/rails_app/app/assets/javascripts/application.js +9 -0
  156. data/spec/rails_app/app/assets/stylesheets/application.css +7 -0
  157. data/spec/rails_app/app/cells/example/display.html.haml +2 -0
  158. data/spec/rails_app/app/cells/example/options.html.haml +15 -0
  159. data/spec/rails_app/app/cells/example_cell.rb +19 -0
  160. data/spec/rails_app/app/cells/image_example/display.html.haml +4 -0
  161. data/spec/rails_app/app/cells/image_example/options.html.haml +15 -0
  162. data/spec/rails_app/app/cells/image_example_cell.rb +18 -0
  163. data/spec/rails_app/app/controllers/application_controller.rb +3 -0
  164. data/spec/rails_app/app/helpers/application_helper.rb +2 -0
  165. data/spec/rails_app/app/mailers/.gitkeep +0 -0
  166. data/spec/rails_app/app/models/.gitkeep +0 -0
  167. data/spec/rails_app/app/views/cmsimple/_snippet_list.html.haml +8 -0
  168. data/spec/rails_app/app/views/cmsimple/templates/default.html.haml +19 -0
  169. data/spec/rails_app/app/views/cmsimple/templates/test.html.haml +2 -0
  170. data/spec/rails_app/app/views/layouts/application.html.haml +13 -0
  171. data/spec/rails_app/config.ru +4 -0
  172. data/spec/rails_app/config/application.rb +65 -0
  173. data/spec/rails_app/config/boot.rb +9 -0
  174. data/spec/rails_app/config/database.example.yml +22 -0
  175. data/spec/rails_app/config/database.travis.yml +8 -0
  176. data/spec/rails_app/config/environment.rb +5 -0
  177. data/spec/rails_app/config/environments/development.rb +30 -0
  178. data/spec/rails_app/config/environments/test.rb +39 -0
  179. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  180. data/spec/rails_app/config/initializers/cells.rb +1 -0
  181. data/spec/rails_app/config/initializers/cmsimple.rb +3 -0
  182. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  183. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  184. data/spec/rails_app/config/initializers/secret_token.rb +7 -0
  185. data/spec/rails_app/config/initializers/session_store.rb +8 -0
  186. data/spec/rails_app/config/initializers/teabag.rb +58 -0
  187. data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
  188. data/spec/rails_app/config/locales/en.yml +5 -0
  189. data/spec/rails_app/config/routes.rb +61 -0
  190. data/spec/rails_app/db/seeds.rb +11 -0
  191. data/spec/rails_app/lib/assets/.gitkeep +0 -0
  192. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  193. data/spec/rails_app/public/404.html +26 -0
  194. data/spec/rails_app/public/422.html +26 -0
  195. data/spec/rails_app/public/500.html +26 -0
  196. data/spec/rails_app/public/robots.txt +5 -0
  197. data/spec/rails_app/script/rails +6 -0
  198. data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
  199. data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
  200. data/spec/spec_helper.rb +31 -0
  201. data/spec/support/active_model_lint_example.rb +14 -0
  202. data/spec/teabag_env.rb +28 -0
  203. data/vendor/assets/images/sitemap/has-changes.png +0 -0
  204. data/vendor/assets/images/sitemap/published.png +0 -0
  205. data/vendor/assets/images/sitemap/unpublished.png +0 -0
  206. data/vendor/assets/images/toolbar/metadata.png +0 -0
  207. data/vendor/assets/images/toolbar/publish.png +0 -0
  208. data/vendor/assets/images/toolbar/redirect.png +0 -0
  209. data/vendor/assets/images/toolbar/sitemap.png +0 -0
  210. data/vendor/assets/images/toolbar/snippets.png +0 -0
  211. data/vendor/assets/images/toolbar/unpublished.png +0 -0
  212. data/vendor/assets/images/tree-line-horizontal-last.png +0 -0
  213. data/vendor/assets/images/tree-line-horizontal.png +0 -0
  214. data/vendor/assets/images/tree-line-vertical.png +0 -0
  215. data/vendor/assets/javascripts/jquery-serializeObject.js +107 -0
  216. data/vendor/assets/javascripts/jquery.to-json.js +74 -0
  217. data/vendor/assets/javascripts/jquery.ui.nestedSortable-1.3.4.js +391 -0
  218. data/vendor/assets/javascripts/moment-1.6.2.js +918 -0
  219. data/vendor/assets/javascripts/underscore-1.3.1.js +31 -0
  220. data/vendor/assets/stylesheets/jasmine-modified.css +216 -0
  221. metadata +686 -0
@@ -0,0 +1,27 @@
1
+
2
+ /* Button example */
3
+ .mercury-primary-toolbar .mercury-inspector-button em {
4
+ background-image: url(/assets/mercury/toolbar/primary/inspectorpanel.png);
5
+ }
6
+
7
+ .mercury-sitemap-button em {
8
+ background-image: url(/assets/toolbar/sitemap.png);
9
+ }
10
+
11
+ .mercury-publish-button em {
12
+ background-image: url(/assets/toolbar/publish.png);
13
+ }
14
+
15
+ .mercury-publish-button.unpublished em {
16
+ background-image: url(/assets/toolbar/unpublished.png);
17
+ }
18
+
19
+ .mercury-redirects-button em {
20
+ background-image: url(/assets/toolbar/redirect.png);
21
+ }
22
+
23
+ .mercury-primary-toolbar .mercury-editMetadata-button em,
24
+ .mercury-expander-button[data-button="inspector"] em {
25
+ background-image: url(/assets/toolbar/metadata.png);
26
+ }
27
+
@@ -0,0 +1,2 @@
1
+ /* TODO: figure out where Mercury is requiring this */
2
+
@@ -0,0 +1,38 @@
1
+ module Cmsimple
2
+ class FrontController < Cmsimple.configuration.parent_front_controller.constantize
3
+ self.responder = Cmsimple.configuration.template_strategy
4
+ helper Cmsimple::RegionsHelper
5
+ helper_method :in_editor_iframe?, :current_page
6
+
7
+ before_filter :check_for_redirect, :only => [:show, :editor, :update_content]
8
+ respond_to :html, :json, :js
9
+
10
+ def show
11
+ Cmsimple::PageResponder.new(self).respond
12
+ end
13
+
14
+ def in_editor_iframe?
15
+ params[:mercury_frame] && (params[:mercury_frame] == true || params[:mercury_frame] == 'true')
16
+ end
17
+
18
+ def current_path
19
+ @path ||= Path.from_request(params[:path])
20
+ end
21
+
22
+ def current_page
23
+ @page ||= if params[:id].present?
24
+ Cmsimple::Page.find(params[:id])
25
+ else
26
+ current_path.destination
27
+ end
28
+ end
29
+
30
+ def check_for_redirect
31
+ if current_path.redirect?
32
+ path = current_path.destination.uri
33
+ path = "/editor#{path}" if action_name == 'editor'
34
+ redirect_to path, status: 301
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ module Cmsimple
2
+ class ImagesController < Cmsimple.configuration.parent_controller.constantize
3
+ respond_to :json, :html
4
+ layout 'panel'
5
+
6
+ def index
7
+ @images = Image.all
8
+ respond_with @images
9
+ end
10
+
11
+ def new
12
+ @image = Image.new
13
+ respond_with @image
14
+ end
15
+
16
+ def create
17
+ @image = Image.new(params[:image])
18
+ @image.save
19
+ respond_with @image, location: new_image_path
20
+ end
21
+
22
+ def destroy
23
+ @image = Image.find(params[:id])
24
+ @image.destroy
25
+ respond_with @image
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ module Cmsimple
2
+ class MercuryController < ::MercuryController
3
+ def resource
4
+ render :action => "/#{params[:type]}/#{params[:resource]}"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,89 @@
1
+ module Cmsimple
2
+ class PagesController < Cmsimple.configuration.parent_controller.constantize
3
+ helper_method :current_page
4
+
5
+ before_filter :check_for_redirect, :only => [:editor, :update_content]
6
+ respond_to :html, :json, :js
7
+
8
+ def index
9
+ @pages = Page.all
10
+ respond_with @pages
11
+ end
12
+
13
+ def show
14
+ @page = Page.find(params[:id])
15
+ respond_with @page
16
+ end
17
+
18
+ def update_content
19
+ current_page.update_content(params[:content])
20
+ respond_with @page, :location => @page.uri
21
+ end
22
+
23
+ def editor
24
+ render :nothing => true, :layout => 'editor'
25
+ end
26
+
27
+ def edit
28
+ @page = Page.find(params[:id])
29
+ render :edit, :layout => false
30
+ end
31
+
32
+ def new
33
+ @page = Page.new
34
+ render :new, :layout => false
35
+ end
36
+
37
+ def publish
38
+ @page = Page.find(params[:id])
39
+ render :publish, :layout => false
40
+ end
41
+
42
+ def update
43
+ @page = Page.find(params[:id])
44
+ params[:page].delete :id if params[:page] && params[:page].key?(:id)
45
+ if @page.update_attributes(params[:page])
46
+ respond_with(@page)
47
+ else
48
+ render :edit, layout: false, status: 422
49
+ end
50
+ end
51
+
52
+ def create
53
+ params[:page].delete :id if params[:page] && params[:page].key?(:id)
54
+ @page = Page.new(params[:page])
55
+ if @page.save
56
+ respond_with(@page)
57
+ else
58
+ render :new, layout: false, status: 422
59
+ end
60
+ end
61
+
62
+ def destroy
63
+ @page = Page.find(params[:id])
64
+ @page.destroy
65
+ respond_with(@page) do |format|
66
+ format.html{ redirect_to '/editor' }
67
+ end
68
+ end
69
+
70
+ #helpers
71
+ def current_path
72
+ @path ||= Path.from_request(params[:path])
73
+ end
74
+
75
+ def current_page
76
+ @page ||= current_path.destination
77
+ end
78
+
79
+ def check_for_redirect
80
+ return true if params[:id].present?
81
+ if current_path.redirect?
82
+ path = current_path.destination.uri
83
+ path = "/editor#{path}" if action_name == 'editor'
84
+ redirect_to path, status: 301
85
+ end
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,23 @@
1
+ module Cmsimple
2
+ class PathsController < Cmsimple.configuration.parent_controller.constantize
3
+ respond_to :json
4
+
5
+ def index
6
+ @paths = Path.all
7
+ respond_with @paths
8
+ end
9
+
10
+ def create
11
+ @path = Path.new(params[:path])
12
+ @path.save
13
+ respond_with @path
14
+ end
15
+
16
+ def destroy
17
+ @path = Path.find(params[:id])
18
+ @path.destroy
19
+ respond_with @path
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,23 @@
1
+ module Cmsimple
2
+ class SnippetsController < Cmsimple.configuration.parent_controller.constantize
3
+
4
+ def index
5
+ render :index, layout: false
6
+ end
7
+
8
+ def preview
9
+ @snippet = Cmsimple::Snippet.new params[:name], options: params[:snippet]
10
+ render text: render_cell(params[:name], :preview, @snippet)
11
+ end
12
+
13
+ def options
14
+ # the options prefix is to handle legacy snippets mercury
15
+ # changed how it serializes snippets
16
+ @options = params[:options][:snippet] if params[:options]
17
+ @options ||= params[:snippet]
18
+ @snippet = Cmsimple::Snippet.new params[:name], options: @options
19
+ render text: render_cell(params[:name], :options, @snippet)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module Cmsimple
2
+ class VersionsController < Cmsimple.configuration.parent_controller.constantize
3
+ respond_to :json
4
+
5
+ def index
6
+ @versions = Page.find(params[:page_id]).versions
7
+ respond_with @versions
8
+ end
9
+
10
+ def revert_to
11
+ @page = Page.find(params[:page_id])
12
+ @version = @page.versions.find(params[:id])
13
+ @page.revert_to!(@version)
14
+ respond_with @page
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+
2
+ module Cmsimple
3
+ module RegionsHelper
4
+ def resource_regions
5
+ @page.regions
6
+ end
7
+
8
+ def region_content(region)
9
+ region.render_snippets do |snippet|
10
+ render_snippet(snippet)
11
+ end
12
+ raw region
13
+ end
14
+
15
+ def render_region(region_name, options={}, &block)
16
+ content = region_content(resource_regions.send(region_name))
17
+
18
+ if content.blank? && block_given?
19
+ content = capture(&block)
20
+ end
21
+
22
+ if options[:tag]
23
+ html_options = options[:html].presence || {}
24
+ html_options = html_options.merge(:id => region_name, :'data-mercury' => options[:region_type] || 'full')
25
+
26
+ content = content_tag options[:tag], content, html_options
27
+ end
28
+
29
+ raw content
30
+ end
31
+
32
+ def render_snippet(snippet)
33
+ return '' unless snippet.name.present?
34
+ render_cell snippet.name, :display, snippet
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,19 @@
1
+ module Cmsimple
2
+ class Image < ActiveRecord::Base
3
+ attr_accessible :attachment, :title, :width, :height, :content_type, :file_size
4
+ mount_uploader :attachment, ImageAttachmentUploader
5
+
6
+ validates :attachment, :presence => true
7
+
8
+ before_save :update_attachment_attributes
9
+
10
+ private
11
+
12
+ def update_attachment_attributes
13
+ if attachment.present? && attachment_changed?
14
+ self.content_type = attachment.file.content_type
15
+ self.file_size = attachment.file.size
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,203 @@
1
+ module Cmsimple
2
+ class Page < ActiveRecord::Base
3
+ serialize :content, Hash
4
+
5
+ attr_accessible :slug,
6
+ :uri,
7
+ :title,
8
+ :content,
9
+ :template,
10
+ :parent_id,
11
+ :is_root,
12
+ :position,
13
+ :published,
14
+ :keywords,
15
+ :description,
16
+ :browser_title
17
+
18
+ belongs_to :parent, :class_name => '::Cmsimple::Page', :foreign_key => 'parent_id'
19
+ has_many :children, :class_name => '::Cmsimple::Page', :foreign_key => 'parent_id', :dependent => :destroy
20
+ has_many :paths, :dependent => :destroy
21
+ has_many :versions, :dependent => :destroy
22
+
23
+ validates :uri,
24
+ :slug,
25
+ :title,
26
+ :presence => true
27
+
28
+ validates :uri, :uniqueness => true
29
+
30
+ validate :is_root_set
31
+
32
+ before_validation :set_current_uri
33
+ before_save :ensure_only_one_root
34
+ after_save :create_path
35
+
36
+ def self.for_parent_select(page)
37
+ scope = scoped
38
+ unless page.new_record?
39
+ scope = scope.where('id NOT IN (?)', page.descendants.map(&:id) + [page.id])
40
+ end
41
+ scope.order('position').all
42
+ end
43
+
44
+ # TODO: move this to a view delegator/presenter
45
+ def select_label
46
+ "#{'&nbsp;&nbsp;' * (uri ? (uri.count('/') - 1) : 0)}#{title}".html_safe
47
+ end
48
+
49
+ def self.root
50
+ where('cmsimple_pages.is_root = ?', true).limit(1)
51
+ end
52
+
53
+ def self.published
54
+ where('cmsimple_pages.published_at <= ?', Time.zone.now.utc)
55
+ end
56
+
57
+ def self.unpublished
58
+ where('cmsimple_pages.published_at IS NULL')
59
+ end
60
+
61
+ def root
62
+ parent = self.parent || self
63
+ while parent.try(:parent)
64
+ parent = parent.parent
65
+ end
66
+ parent
67
+ end
68
+
69
+ def descendants
70
+ children.all.inject([]) do |ary, child|
71
+ ary << child
72
+ ary + child.descendants
73
+ end.sort_by(&:position)
74
+ end
75
+
76
+ def regions
77
+ @regions ||= RegionsProxy.new(self.content)
78
+ end
79
+
80
+ def update_content(content)
81
+ if content.is_a?(String)
82
+ content = JSON.parse(content)
83
+ end
84
+ update_attributes(content: content)
85
+ end
86
+
87
+ def slug
88
+ self[:slug] ||= escape(title)
89
+ end
90
+
91
+ def slug=(val)
92
+ self[:slug] = escape(val)
93
+ end
94
+
95
+ # override in app to set optional rendering parameters like layouts
96
+ # on a per page basis
97
+ def template_render_options
98
+ Cmsimple.configuration.template_render_options
99
+ end
100
+
101
+ def publish!
102
+ self.published_at = Time.zone.now
103
+ self.save!
104
+ create_new_version
105
+ end
106
+
107
+ def unpublish!
108
+ self.published_at = nil
109
+ self.save!
110
+ end
111
+
112
+ def published?
113
+ self.published_at.present? && self.published_at <= Time.zone.now
114
+ end
115
+ alias :published :published?
116
+
117
+ def unpublished_changes?
118
+ self.published_at.blank? || (self.updated_at - self.published_at).abs > 1.second
119
+ end
120
+ alias :unpublished_changes :unpublished_changes?
121
+
122
+ #TODO: refactor me, this smells
123
+ def published=(val)
124
+ if val.to_bool
125
+ self.publish!
126
+ else
127
+ self.unpublish!
128
+ end
129
+ end
130
+
131
+ def as_published!
132
+ return false unless published?
133
+
134
+ readonly!
135
+ reify versions.published.first
136
+ return true
137
+ end
138
+
139
+ def at_version!(version_id)
140
+ return false unless published?
141
+
142
+ readonly!
143
+ reify versions.find(version_id)
144
+ return true
145
+ end
146
+
147
+ def reify(version)
148
+ return unless version.present?
149
+ self.content = version.content
150
+ self.template = version.template
151
+ @regions = RegionsProxy.new(self.content)
152
+ end
153
+
154
+ def revert_to!(version_id)
155
+ version = self.versions.find(version_id)
156
+ reify version
157
+ save!
158
+ end
159
+
160
+ def as_json(options={})
161
+ super(options.merge({:methods => [:unpublished_changes, :published]}))
162
+ end
163
+
164
+ protected
165
+
166
+ def escape(string)
167
+ result = string.to_s.dup
168
+ result.gsub!(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
169
+ result.gsub!(/[^\w_ \-]+/i, '') # Remove unwanted chars.
170
+ result.gsub!(/[ \-]+/i, '-') # No more than one of the separator in a row.
171
+ result.gsub!(/^\-|\-$/i, '') # Remove leading/trailing separator.
172
+ result.downcase
173
+ end
174
+
175
+ def set_current_uri
176
+ self.uri = [self.parent.try(:uri), slug].join('/')
177
+ end
178
+
179
+ def ensure_only_one_root
180
+ if is_root_changed? && is_root?
181
+ self.class.where(is_root: true).update_all(is_root: false)
182
+ end
183
+ end
184
+
185
+ def is_root_set
186
+ if is_root_changed? && !is_root?
187
+ errors[:is_root] << "can't unset home page"
188
+ end
189
+ end
190
+
191
+ def create_path
192
+ associated_path = Cmsimple::Path.where(uri: self.uri).first_or_initialize
193
+ associated_path.page = self
194
+ associated_path.redirect_uri = nil
195
+ associated_path.save!
196
+ end
197
+
198
+ def create_new_version
199
+ self.versions.create! content: self.content, template: self.template, published_at: self.published_at
200
+ end
201
+
202
+ end
203
+ end