comfypress 0.1.3

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 (289) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +22 -0
  4. data/Gemfile +22 -0
  5. data/Gemfile.lock +175 -0
  6. data/LICENSE +20 -0
  7. data/README.md +79 -0
  8. data/Rakefile +5 -0
  9. data/app/assets/images/comfypress/arrow_bottom.gif +0 -0
  10. data/app/assets/images/comfypress/arrow_right.gif +0 -0
  11. data/app/assets/images/comfypress/bootstrap/glyphicons-halflings-white.png +0 -0
  12. data/app/assets/images/comfypress/bootstrap/glyphicons-halflings.png +0 -0
  13. data/app/assets/images/comfypress/checkerboard.gif +0 -0
  14. data/app/assets/images/comfypress/icon_draft.gif +0 -0
  15. data/app/assets/images/comfypress/icon_file.gif +0 -0
  16. data/app/assets/images/comfypress/icon_layout.gif +0 -0
  17. data/app/assets/images/comfypress/icon_move.gif +0 -0
  18. data/app/assets/images/comfypress/icon_page.gif +0 -0
  19. data/app/assets/images/comfypress/icon_site.gif +0 -0
  20. data/app/assets/images/comfypress/icon_snippet.gif +0 -0
  21. data/app/assets/images/comfypress/nav_arrow.png +0 -0
  22. data/app/assets/javascripts/comfypress/admin/application.js +1 -0
  23. data/app/assets/javascripts/comfypress/application.js.coffee +175 -0
  24. data/app/assets/javascripts/comfypress/lib/bootstrap-datetimepicker.js +21 -0
  25. data/app/assets/javascripts/comfypress/lib/bootstrap-wysihtml5.js +492 -0
  26. data/app/assets/javascripts/comfypress/lib/bootstrap.js +6 -0
  27. data/app/assets/javascripts/comfypress/lib/codemirror.js +10 -0
  28. data/app/assets/javascripts/comfypress/lib/wysihtml5.js +261 -0
  29. data/app/assets/stylesheets/comfypress/admin/application.css +1 -0
  30. data/app/assets/stylesheets/comfypress/application.css.sass +8 -0
  31. data/app/assets/stylesheets/comfypress/base.css.sass +333 -0
  32. data/app/assets/stylesheets/comfypress/bootstrap_overrides.css.sass +45 -0
  33. data/app/assets/stylesheets/comfypress/codemirror_overrides.css.sass +27 -0
  34. data/app/assets/stylesheets/comfypress/lib/bootstrap-datetimepicker.css +9 -0
  35. data/app/assets/stylesheets/comfypress/lib/bootstrap-wysihtml5.css +102 -0
  36. data/app/assets/stylesheets/comfypress/lib/bootstrap.css +9 -0
  37. data/app/assets/stylesheets/comfypress/lib/codemirror.css +240 -0
  38. data/app/assets/stylesheets/comfypress/wysihtml5_overrides.css.sass +5 -0
  39. data/app/controllers/application_controller.rb +5 -0
  40. data/app/controllers/cms_admin/base_controller.rb +51 -0
  41. data/app/controllers/cms_admin/categories_controller.rb +35 -0
  42. data/app/controllers/cms_admin/files_controller.rb +108 -0
  43. data/app/controllers/cms_admin/layouts_controller.rb +67 -0
  44. data/app/controllers/cms_admin/menu_items_controller.rb +65 -0
  45. data/app/controllers/cms_admin/menus_controller.rb +60 -0
  46. data/app/controllers/cms_admin/pages_controller.rb +112 -0
  47. data/app/controllers/cms_admin/revisions_controller.rb +57 -0
  48. data/app/controllers/cms_admin/sites_controller.rb +64 -0
  49. data/app/controllers/cms_admin/snippets_controller.rb +64 -0
  50. data/app/controllers/cms_content_controller.rb +79 -0
  51. data/app/helpers/application_helper.rb +16 -0
  52. data/app/models/cms/block.rb +48 -0
  53. data/app/models/cms/categorization.rb +21 -0
  54. data/app/models/cms/category.rb +30 -0
  55. data/app/models/cms/file.rb +75 -0
  56. data/app/models/cms/layout.rb +99 -0
  57. data/app/models/cms/menu.rb +26 -0
  58. data/app/models/cms/menu_item.rb +14 -0
  59. data/app/models/cms/page.rb +202 -0
  60. data/app/models/cms/revision.rb +17 -0
  61. data/app/models/cms/site.rb +113 -0
  62. data/app/models/cms/snippet.rb +58 -0
  63. data/app/models/cms.rb +5 -0
  64. data/app/views/cms_admin/categories/_categories.html.haml +3 -0
  65. data/app/views/cms_admin/categories/_edit.html.haml +6 -0
  66. data/app/views/cms_admin/categories/_form.html.haml +8 -0
  67. data/app/views/cms_admin/categories/_index.html.haml +24 -0
  68. data/app/views/cms_admin/categories/_show.html.haml +13 -0
  69. data/app/views/cms_admin/categories/create.js.erb +7 -0
  70. data/app/views/cms_admin/categories/destroy.js.erb +3 -0
  71. data/app/views/cms_admin/categories/edit.js.erb +3 -0
  72. data/app/views/cms_admin/categories/update.js.erb +6 -0
  73. data/app/views/cms_admin/files/_file.html.haml +13 -0
  74. data/app/views/cms_admin/files/_form.html.haml +14 -0
  75. data/app/views/cms_admin/files/_index.html.haml +14 -0
  76. data/app/views/cms_admin/files/_page_form.html.haml +9 -0
  77. data/app/views/cms_admin/files/destroy.js.coffee +2 -0
  78. data/app/views/cms_admin/files/edit.html.haml +5 -0
  79. data/app/views/cms_admin/files/index.html.haml +28 -0
  80. data/app/views/cms_admin/files/new.html.haml +5 -0
  81. data/app/views/cms_admin/layouts/_form.html.haml +17 -0
  82. data/app/views/cms_admin/layouts/_index_branch.html.haml +23 -0
  83. data/app/views/cms_admin/layouts/edit.html.haml +9 -0
  84. data/app/views/cms_admin/layouts/index.html.haml +9 -0
  85. data/app/views/cms_admin/layouts/new.html.haml +5 -0
  86. data/app/views/cms_admin/menu_items/_form.html.haml +22 -0
  87. data/app/views/cms_admin/menu_items/edit.html.haml +8 -0
  88. data/app/views/cms_admin/menu_items/index.html.haml +24 -0
  89. data/app/views/cms_admin/menu_items/new.html.haml +5 -0
  90. data/app/views/cms_admin/menus/_form.html.haml +8 -0
  91. data/app/views/cms_admin/menus/edit.html.haml +8 -0
  92. data/app/views/cms_admin/menus/index.html.haml +24 -0
  93. data/app/views/cms_admin/menus/new.html.haml +5 -0
  94. data/app/views/cms_admin/pages/_form.html.haml +38 -0
  95. data/app/views/cms_admin/pages/_form_blocks.html.haml +28 -0
  96. data/app/views/cms_admin/pages/_index_branch.html.haml +35 -0
  97. data/app/views/cms_admin/pages/edit.html.haml +9 -0
  98. data/app/views/cms_admin/pages/form_blocks.js.erb +2 -0
  99. data/app/views/cms_admin/pages/index.html.haml +11 -0
  100. data/app/views/cms_admin/pages/new.html.haml +5 -0
  101. data/app/views/cms_admin/pages/toggle_branch.js.erb +11 -0
  102. data/app/views/cms_admin/revisions/show.html.haml +28 -0
  103. data/app/views/cms_admin/sites/_form.html.haml +14 -0
  104. data/app/views/cms_admin/sites/_mirrors.html.haml +17 -0
  105. data/app/views/cms_admin/sites/edit.html.haml +5 -0
  106. data/app/views/cms_admin/sites/index.html.haml +24 -0
  107. data/app/views/cms_admin/sites/new.html.haml +5 -0
  108. data/app/views/cms_admin/snippets/_form.html.haml +11 -0
  109. data/app/views/cms_admin/snippets/edit.html.haml +9 -0
  110. data/app/views/cms_admin/snippets/index.html.haml +28 -0
  111. data/app/views/cms_admin/snippets/new.html.haml +5 -0
  112. data/app/views/cms_content/_menu.html.haml +5 -0
  113. data/app/views/cms_content/render_sitemap.xml.builder +15 -0
  114. data/app/views/layouts/cms_admin/_body.html.haml +16 -0
  115. data/app/views/layouts/cms_admin/_center.html.haml +7 -0
  116. data/app/views/layouts/cms_admin/_footer.html.haml +3 -0
  117. data/app/views/layouts/cms_admin/_footer_js.html.haml +7 -0
  118. data/app/views/layouts/cms_admin/_head.html.haml +12 -0
  119. data/app/views/layouts/cms_admin/_left.html.haml +11 -0
  120. data/app/views/layouts/cms_admin/_right.html.haml +1 -0
  121. data/app/views/layouts/cms_admin.html.haml +4 -0
  122. data/comfypress.gemspec +28 -0
  123. data/config/application.rb +69 -0
  124. data/config/boot.rb +6 -0
  125. data/config/database.sqlite.yml +47 -0
  126. data/config/database.yml +47 -0
  127. data/config/environment.rb +5 -0
  128. data/config/environments/development.rb +39 -0
  129. data/config/environments/production.rb +67 -0
  130. data/config/environments/test.rb +39 -0
  131. data/config/initializers/comfypress.rb +100 -0
  132. data/config/initializers/paperclip.rb +3 -0
  133. data/config/locales/de.yml +236 -0
  134. data/config/locales/en.yml +285 -0
  135. data/config/locales/es.yml +236 -0
  136. data/config/locales/fr.yml +236 -0
  137. data/config/locales/ja.yml +237 -0
  138. data/config/locales/pl.yml +236 -0
  139. data/config/locales/pt-BR.yml +236 -0
  140. data/config/locales/ru.yml +236 -0
  141. data/config/locales/sv.yml +236 -0
  142. data/config/locales/zh-CN.yml +236 -0
  143. data/config/routes.rb +10 -0
  144. data/config.ru +4 -0
  145. data/db/cms_fixtures/sample-site/layouts/default/_default.yml +1 -0
  146. data/db/cms_fixtures/sample-site/layouts/default/content.html +5 -0
  147. data/db/cms_fixtures/sample-site/layouts/default/css.css +1 -0
  148. data/db/cms_fixtures/sample-site/layouts/default/js.js +1 -0
  149. data/db/cms_fixtures/sample-site/layouts/default/nested/_nested.yml +2 -0
  150. data/db/cms_fixtures/sample-site/layouts/default/nested/content.html +2 -0
  151. data/db/cms_fixtures/sample-site/layouts/default/nested/css.css +1 -0
  152. data/db/cms_fixtures/sample-site/layouts/default/nested/js.js +1 -0
  153. data/db/cms_fixtures/sample-site/pages/index/_index.yml +2 -0
  154. data/db/cms_fixtures/sample-site/pages/index/child/_child.yml +3 -0
  155. data/db/cms_fixtures/sample-site/pages/index/child/left.html +1 -0
  156. data/db/cms_fixtures/sample-site/pages/index/child/right.html +1 -0
  157. data/db/cms_fixtures/sample-site/pages/index/content.html +2 -0
  158. data/db/cms_fixtures/sample-site/snippets/default/_default.yml +1 -0
  159. data/db/cms_fixtures/sample-site/snippets/default/content.html +1 -0
  160. data/db/migrate/01_create_cms.rb +163 -0
  161. data/db/seeds.rb +9 -0
  162. data/db/upgrade_migrations/02_upgrade_to_1_1_0.rb +19 -0
  163. data/db/upgrade_migrations/03_upgrade_to_1_2_0.rb +15 -0
  164. data/db/upgrade_migrations/04_upgrade_to_1_3_0.rb +23 -0
  165. data/db/upgrade_migrations/05_upgrade_to_1_4_0.rb +33 -0
  166. data/db/upgrade_migrations/06_upgrade_to_1_5_0.rb +21 -0
  167. data/db/upgrade_migrations/07_upgrade_to_1_6_0.rb +25 -0
  168. data/doc/preview.png +0 -0
  169. data/doc/sofa.png +0 -0
  170. data/lib/comfypress/authentication/dummy_auth.rb +8 -0
  171. data/lib/comfypress/authentication/http_auth.rb +18 -0
  172. data/lib/comfypress/configuration.rb +99 -0
  173. data/lib/comfypress/engine.rb +18 -0
  174. data/lib/comfypress/error.rb +24 -0
  175. data/lib/comfypress/extensions/acts_as_tree.rb +102 -0
  176. data/lib/comfypress/extensions/has_revisions.rb +64 -0
  177. data/lib/comfypress/extensions/is_categorized.rb +49 -0
  178. data/lib/comfypress/extensions/is_mirrored.rb +85 -0
  179. data/lib/comfypress/extensions/rails.rb +24 -0
  180. data/lib/comfypress/fixtures.rb +289 -0
  181. data/lib/comfypress/form_builder.rb +97 -0
  182. data/lib/comfypress/render_methods.rb +85 -0
  183. data/lib/comfypress/routing.rb +62 -0
  184. data/lib/comfypress/sitemap.rb +27 -0
  185. data/lib/comfypress/tag.rb +154 -0
  186. data/lib/comfypress/tags/asset.rb +25 -0
  187. data/lib/comfypress/tags/collection.rb +64 -0
  188. data/lib/comfypress/tags/field_datetime.rb +17 -0
  189. data/lib/comfypress/tags/field_integer.rb +17 -0
  190. data/lib/comfypress/tags/field_rich_text.rb +17 -0
  191. data/lib/comfypress/tags/field_string.rb +17 -0
  192. data/lib/comfypress/tags/field_text.rb +17 -0
  193. data/lib/comfypress/tags/file.rb +29 -0
  194. data/lib/comfypress/tags/helper.rb +24 -0
  195. data/lib/comfypress/tags/menu.rb +27 -0
  196. data/lib/comfypress/tags/page_datetime.rb +13 -0
  197. data/lib/comfypress/tags/page_file.rb +51 -0
  198. data/lib/comfypress/tags/page_files.rb +52 -0
  199. data/lib/comfypress/tags/page_integer.rb +13 -0
  200. data/lib/comfypress/tags/page_markdown.rb +22 -0
  201. data/lib/comfypress/tags/page_rich_text.rb +13 -0
  202. data/lib/comfypress/tags/page_string.rb +13 -0
  203. data/lib/comfypress/tags/page_text.rb +13 -0
  204. data/lib/comfypress/tags/partial.rb +23 -0
  205. data/lib/comfypress/tags/snippet.rb +19 -0
  206. data/lib/comfypress/version.rb +3 -0
  207. data/lib/comfypress/view_hooks.rb +32 -0
  208. data/lib/comfypress/view_methods.rb +52 -0
  209. data/lib/comfypress.rb +66 -0
  210. data/lib/generators/comfy/cms/README +10 -0
  211. data/lib/generators/comfy/cms/cms_generator.rb +57 -0
  212. data/lib/tasks/comfypress.rake +45 -0
  213. data/script/rails +6 -0
  214. data/test/fixtures/cms/blocks.yml +12 -0
  215. data/test/fixtures/cms/categories.yml +4 -0
  216. data/test/fixtures/cms/categorizations.yml +3 -0
  217. data/test/fixtures/cms/files.yml +9 -0
  218. data/test/fixtures/cms/layouts.yml +40 -0
  219. data/test/fixtures/cms/menu_items.yml +15 -0
  220. data/test/fixtures/cms/menus.yml +9 -0
  221. data/test/fixtures/cms/pages.yml +39 -0
  222. data/test/fixtures/cms/revisions.yml +21 -0
  223. data/test/fixtures/cms/sites.yml +6 -0
  224. data/test/fixtures/cms/snippets.yml +6 -0
  225. data/test/fixtures/files/data.zip +0 -0
  226. data/test/fixtures/files/document.pdf +0 -0
  227. data/test/fixtures/files/image.gif +0 -0
  228. data/test/fixtures/files/image.jpg +0 -0
  229. data/test/fixtures/views/_nav_hook.html.erb +1 -0
  230. data/test/fixtures/views/_nav_hook_2.html.erb +1 -0
  231. data/test/fixtures/views/render_test/_test.html.erb +1 -0
  232. data/test/fixtures/views/render_test/new.html.erb +1 -0
  233. data/test/fixtures/views/render_test/render_layout.html.erb +1 -0
  234. data/test/functional/cms_admin/base_controller_test.rb +18 -0
  235. data/test/functional/cms_admin/categories_controller_test.rb +70 -0
  236. data/test/functional/cms_admin/files_controller_test.rb +216 -0
  237. data/test/functional/cms_admin/layouts_controller_test.rb +123 -0
  238. data/test/functional/cms_admin/pages_controller_test.rb +450 -0
  239. data/test/functional/cms_admin/revisions_controller_test.rb +138 -0
  240. data/test/functional/cms_admin/sites_controller_test.rb +105 -0
  241. data/test/functional/cms_admin/snippets_controller_test.rb +140 -0
  242. data/test/functional/cms_content_controller_test.rb +205 -0
  243. data/test/gemfiles/Gemfile.rails.3.1 +16 -0
  244. data/test/gemfiles/Gemfile.rails.3.2 +16 -0
  245. data/test/gemfiles/Gemfile.rails.4.0 +16 -0
  246. data/test/integration/authentication_test.rb +48 -0
  247. data/test/integration/fixtures_test.rb +61 -0
  248. data/test/integration/mirrors_test.rb +72 -0
  249. data/test/integration/render_cms_test.rb +233 -0
  250. data/test/integration/sites_test.rb +120 -0
  251. data/test/integration/view_hooks_test.rb +43 -0
  252. data/test/test_helper.rb +124 -0
  253. data/test/unit/cms/menu_item_test.rb +7 -0
  254. data/test/unit/cms/menu_test.rb +7 -0
  255. data/test/unit/configuration_test.rb +42 -0
  256. data/test/unit/fixtures_test.rb +357 -0
  257. data/test/unit/mirrors_test.rb +242 -0
  258. data/test/unit/models/block_test.rb +199 -0
  259. data/test/unit/models/categorization_test.rb +76 -0
  260. data/test/unit/models/category_test.rb +39 -0
  261. data/test/unit/models/file_test.rb +89 -0
  262. data/test/unit/models/layout_test.rb +125 -0
  263. data/test/unit/models/page_test.rb +255 -0
  264. data/test/unit/models/site_test.rb +152 -0
  265. data/test/unit/models/snippet_test.rb +49 -0
  266. data/test/unit/revisions_test.rb +185 -0
  267. data/test/unit/sitemap_test.rb +20 -0
  268. data/test/unit/tag_test.rb +308 -0
  269. data/test/unit/tags/asset_test.rb +56 -0
  270. data/test/unit/tags/collection_test.rb +116 -0
  271. data/test/unit/tags/field_datetime_test.rb +50 -0
  272. data/test/unit/tags/field_integer_test.rb +49 -0
  273. data/test/unit/tags/field_rich_text_test.rb +49 -0
  274. data/test/unit/tags/field_string_test.rb +52 -0
  275. data/test/unit/tags/field_text_test.rb +48 -0
  276. data/test/unit/tags/file_test.rb +67 -0
  277. data/test/unit/tags/helper_test.rb +86 -0
  278. data/test/unit/tags/page_datetime_test.rb +50 -0
  279. data/test/unit/tags/page_file_test.rb +119 -0
  280. data/test/unit/tags/page_files_test.rb +113 -0
  281. data/test/unit/tags/page_integer_test.rb +49 -0
  282. data/test/unit/tags/page_markdown_test.rb +48 -0
  283. data/test/unit/tags/page_rich_text_test.rb +49 -0
  284. data/test/unit/tags/page_string_test.rb +49 -0
  285. data/test/unit/tags/page_text_test.rb +52 -0
  286. data/test/unit/tags/partial_test.rb +76 -0
  287. data/test/unit/tags/snippet_test.rb +45 -0
  288. data/test/unit/view_methods_test.rb +80 -0
  289. metadata +457 -0
@@ -0,0 +1,49 @@
1
+ module ComfyPress::IsCategorized
2
+
3
+ def self.included(base)
4
+ base.send :extend, ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def cms_is_categorized
9
+ include ComfyPress::IsCategorized::InstanceMethods
10
+
11
+ has_many :categorizations,
12
+ :as => :categorized,
13
+ :class_name => 'Cms::Categorization',
14
+ :dependent => :destroy
15
+ has_many :categories,
16
+ :through => :categorizations,
17
+ :class_name => 'Cms::Category'
18
+
19
+ attr_accessor :category_ids
20
+
21
+ after_save :sync_categories
22
+
23
+ scope :for_category, lambda { |*categories|
24
+ if (categories = [categories].flatten.compact).present?
25
+ select("DISTINCT #{table_name}.*").
26
+ joins(:categorizations => :category).
27
+ where('cms_categories.label' => categories)
28
+ end
29
+ }
30
+ end
31
+ end
32
+
33
+ module InstanceMethods
34
+ def sync_categories
35
+ (self.category_ids || {}).each do |category_id, flag|
36
+ case flag.to_i
37
+ when 1
38
+ if category = Cms::Category.find_by_id(category_id)
39
+ category.categorizations.create(:categorized => self)
40
+ end
41
+ when 0
42
+ self.categorizations.where(:category_id => category_id).destroy_all
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ ActiveRecord::Base.send :include, ComfyPress::IsCategorized
@@ -0,0 +1,85 @@
1
+ module ComfyPress::IsMirrored
2
+
3
+ def self.included(base)
4
+ base.send :extend, ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def cms_is_mirrored
9
+ include ComfyPress::IsMirrored::InstanceMethods
10
+
11
+ attr_accessor :is_mirrored
12
+
13
+ after_save :sync_mirror
14
+ after_destroy :destroy_mirror
15
+ end
16
+ end
17
+
18
+ module InstanceMethods
19
+
20
+ # Mirrors of the object found on other sites
21
+ def mirrors
22
+ return [] unless self.site.is_mirrored?
23
+ (Cms::Site.mirrored - [self.site]).collect do |site|
24
+ case self
25
+ when Cms::Layout then site.layouts.find_by_identifier(self.identifier)
26
+ when Cms::Page then site.pages.find_by_full_path(self.full_path)
27
+ when Cms::Snippet then site.snippets.find_by_identifier(self.identifier)
28
+ end
29
+ end.compact
30
+ end
31
+
32
+ # Creating or updating a mirror object. Relationships are mirrored
33
+ # but content is unique. When updating need to grab mirrors based on
34
+ # self.slug_was, new objects will use self.slug.
35
+ def sync_mirror
36
+ return if self.is_mirrored || !self.site.is_mirrored?
37
+
38
+ (Cms::Site.mirrored - [self.site]).each do |site|
39
+ mirror = case self
40
+ when Cms::Layout
41
+ m = site.layouts.find_by_identifier(self.identifier_was || self.identifier) || site.layouts.new
42
+ m.attributes = {
43
+ :identifier => self.identifier,
44
+ :parent_id => site.layouts.find_by_identifier(self.parent.try(:identifier)).try(:id)
45
+ }
46
+ m
47
+ when Cms::Page
48
+ m = site.pages.find_by_full_path(self.full_path_was || self.full_path) || site.pages.new
49
+ m.attributes = {
50
+ :slug => self.slug,
51
+ :label => self.slug.blank?? self.label : m.label,
52
+ :parent_id => site.pages.find_by_full_path(self.parent.try(:full_path)).try(:id),
53
+ :layout => site.layouts.find_by_identifier(self.layout.try(:identifier))
54
+ }
55
+ m
56
+ when Cms::Snippet
57
+ m = site.snippets.find_by_identifier(self.identifier_was || self.identifier) || site.snippets.new
58
+ m.attributes = {
59
+ :identifier => self.identifier
60
+ }
61
+ m
62
+ end
63
+
64
+ mirror.is_mirrored = true
65
+ begin
66
+ mirror.save!
67
+ rescue ActiveRecord::RecordInvalid
68
+ logger.detailed_error($!)
69
+ end
70
+ end
71
+ end
72
+
73
+ # Mirrors should be destroyed
74
+ def destroy_mirror
75
+ return if self.is_mirrored || !self.site.is_mirrored?
76
+ mirrors.each do |mirror|
77
+ mirror.is_mirrored = true
78
+ mirror.destroy
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ ActiveRecord::Base.send :include, ComfyPress::IsMirrored
@@ -0,0 +1,24 @@
1
+ class String
2
+ # Converts string to something suitable to be used as an element id
3
+ def slugify
4
+ self.strip.gsub(/\W|_/, '-').gsub(/\s|^_*|_*$/, '').squeeze('-')
5
+ end
6
+ end
7
+
8
+ module Enumerable
9
+ # Like a normal collect, only with index
10
+ def collect_with_index
11
+ result = []
12
+ self.each_with_index do |elt, idx|
13
+ result << yield(elt, idx)
14
+ end
15
+ result
16
+ end
17
+ end
18
+
19
+ class ActiveSupport::BufferedLogger
20
+ def detailed_error(e)
21
+ error(e.message)
22
+ e.backtrace.each{|line| error line }
23
+ end
24
+ end
@@ -0,0 +1,289 @@
1
+ module ComfyPress::Fixtures
2
+
3
+ def self.import_all(to_site, from_folder = nil, force_import = false)
4
+ import_layouts to_site, from_folder, nil, true, nil, [], force_import
5
+ import_pages to_site, from_folder, nil, true, nil, [], force_import
6
+ import_snippets to_site, from_folder, force_import
7
+ end
8
+
9
+ def self.export_all(from_site, to_folder = nil)
10
+ export_layouts from_site, to_folder
11
+ export_pages from_site, to_folder
12
+ export_snippets from_site, to_folder
13
+ end
14
+
15
+ def self.import_layouts(to_site, from_folder = nil, path = nil, root = true, parent = nil, layout_ids = [], force_import = false)
16
+ site = Cms::Site.find_or_create_by_identifier(to_site)
17
+ unless path ||= find_fixtures_path((from_folder || to_site), 'layouts')
18
+ ComfyPress.logger.warn('Cannot find Layout fixtures')
19
+ return []
20
+ end
21
+
22
+ Dir.glob("#{path}/*").select{|f| File.directory?(f)}.each do |path|
23
+ identifier = path.split('/').last
24
+ layout = site.layouts.find_by_identifier(identifier) || site.layouts.new(:identifier => identifier)
25
+
26
+ # updating attributes
27
+ if File.exists?(file_path = File.join(path, "_#{identifier}.yml"))
28
+ if layout.new_record? || File.mtime(file_path) > layout.updated_at || force_import
29
+ attributes = YAML.load_file(file_path).try(:symbolize_keys!) || { }
30
+ layout.label = attributes[:label] || identifier.titleize
31
+ layout.app_layout = attributes[:app_layout] || parent.try(:app_layout)
32
+ layout.position = attributes[:position] if attributes[:position]
33
+ end
34
+ elsif layout.new_record?
35
+ layout.label = identifier.titleize
36
+ layout.app_layout = parent.try(:app_layout)
37
+ end
38
+
39
+ # updating content
40
+ if File.exists?(file_path = File.join(path, 'content.html'))
41
+ if layout.new_record? || File.mtime(file_path) > layout.updated_at || force_import
42
+ layout.content = File.open(file_path).read
43
+ end
44
+ end
45
+ if File.exists?(file_path = File.join(path, 'css.css'))
46
+ if layout.new_record? || File.mtime(file_path) > layout.updated_at || force_import
47
+ layout.css = File.open(file_path).read
48
+ end
49
+ end
50
+ if File.exists?(file_path = File.join(path, 'js.js'))
51
+ if layout.new_record? || File.mtime(file_path) > layout.updated_at || force_import
52
+ layout.js = File.open(file_path).read
53
+ end
54
+ end
55
+
56
+ # saving
57
+ layout.parent = parent
58
+ if layout.changed?
59
+ if layout.save
60
+ ComfyPress.logger.warn("[Fixtures] Saved Layout {#{layout.identifier}}")
61
+ else
62
+ ComfyPress.logger.error("[Fixtures] Failed to save Layout {#{layout.errors.inspect}}")
63
+ next
64
+ end
65
+ end
66
+ layout_ids << layout.id
67
+
68
+ # checking for nested fixtures
69
+ layout_ids += import_layouts(to_site, from_folder, path, false, layout, layout_ids)
70
+ end
71
+
72
+ # removing all db entries that are not in fixtures
73
+ if root
74
+ site.layouts.where('id NOT IN (?)', layout_ids.uniq).each{ |l| l.destroy }
75
+ ComfyPress.logger.warn('Imported Layouts!')
76
+ end
77
+
78
+ # returning ids of layouts in fixtures
79
+ layout_ids.uniq
80
+ end
81
+
82
+ def self.import_pages(to_site, from_folder = nil, path = nil, root = true, parent = nil, page_ids = [], force_import = false)
83
+ site = Cms::Site.find_or_create_by_identifier(to_site)
84
+ unless path ||= find_fixtures_path((from_folder || to_site), 'pages')
85
+ ComfyPress.logger.warn('Cannot find Page fixtures')
86
+ return []
87
+ end
88
+
89
+ Dir.glob("#{path}/*").select{|f| File.directory?(f)}.each do |path|
90
+ slug = path.split('/').last
91
+ page = if parent
92
+ parent.children.find_by_slug(slug) || site.pages.new(:parent => parent, :slug => slug)
93
+ else
94
+ site.pages.root || site.pages.new(:slug => slug)
95
+ end
96
+
97
+ # updating attributes
98
+ if File.exists?(file_path = File.join(path, "_#{slug}.yml"))
99
+ if page.new_record? || File.mtime(file_path) > page.updated_at || force_import
100
+ attributes = YAML.load_file(file_path).try(:symbolize_keys!) || { }
101
+ page.label = attributes[:label] || slug.titleize
102
+ page.layout = site.layouts.find_by_identifier(attributes[:layout]) || parent.try(:layout)
103
+ page.target_page = site.pages.find_by_full_path(attributes[:target_page])
104
+ page.is_published = attributes[:is_published].nil?? true : attributes[:is_published]
105
+ page.position = attributes[:position] if attributes[:position]
106
+ end
107
+ elsif page.new_record?
108
+ page.label = slug.titleize
109
+ page.layout = parent.try(:layout)
110
+ end
111
+
112
+ # updating content
113
+ blocks_to_clear = page.blocks.collect(&:identifier)
114
+ blocks_attributes = [ ]
115
+ Dir.glob("#{path}/*.html").each do |file_path|
116
+ identifier = file_path.split('/').last.gsub(/\.html$/, '')
117
+ blocks_to_clear.delete(identifier)
118
+ if page.new_record? || File.mtime(file_path) > page.updated_at || force_import
119
+ blocks_attributes << {
120
+ :identifier => identifier,
121
+ :content => File.open(file_path).read
122
+ }
123
+ end
124
+ end
125
+
126
+ # clearing removed blocks
127
+ blocks_to_clear.each do |identifier|
128
+ blocks_attributes << {
129
+ :identifier => identifier,
130
+ :content => nil
131
+ }
132
+ end
133
+
134
+ # saving
135
+ page.blocks_attributes = blocks_attributes if blocks_attributes.present?
136
+ if page.changed? || blocks_attributes.present?
137
+ if page.save
138
+ ComfyPress.logger.warn("[Fixtures] Saved Page {#{page.full_path}}")
139
+ else
140
+ ComfyPress.logger.warn("[Fixtures] Failed to save Page {#{page.errors.inspect}}")
141
+ next
142
+ end
143
+ end
144
+ page_ids << page.id
145
+
146
+ # checking for nested fixtures
147
+ page_ids += import_pages(to_site, from_folder, path, false, page, page_ids)
148
+ end
149
+
150
+ # removing all db entries that are not in fixtures
151
+ if root
152
+ site.pages.where('id NOT IN (?)', page_ids.uniq).each{ |p| p.destroy }
153
+ ComfyPress.logger.warn('Imported Pages!')
154
+ end
155
+
156
+ # returning ids of layouts in fixtures
157
+ page_ids.uniq
158
+ end
159
+
160
+ def self.import_snippets(to_site, from_folder = nil, force_import = false)
161
+ site = Cms::Site.find_or_create_by_identifier(to_site)
162
+ unless path = find_fixtures_path((from_folder || to_site), 'snippets')
163
+ ComfyPress.logger.warn('Cannot find Snippet fixtures')
164
+ return []
165
+ end
166
+
167
+ snippet_ids = []
168
+ Dir.glob("#{path}/*").select{|f| File.directory?(f)}.each do |path|
169
+ identifier = path.split('/').last
170
+ snippet = site.snippets.find_by_identifier(identifier) || site.snippets.new(:identifier => identifier)
171
+
172
+ # updating attributes
173
+ if File.exists?(file_path = File.join(path, "_#{identifier}.yml"))
174
+ if snippet.new_record? || File.mtime(file_path) > snippet.updated_at || force_import
175
+ attributes = YAML.load_file(file_path).try(:symbolize_keys!) || { }
176
+ snippet.label = attributes[:label] || identifier.titleize
177
+ end
178
+ elsif snippet.new_record?
179
+ snippet.label = identifier.titleize
180
+ end
181
+
182
+ # updating content
183
+ if File.exists?(file_path = File.join(path, 'content.html'))
184
+ if snippet.new_record? || File.mtime(file_path) > snippet.updated_at || force_import
185
+ snippet.content = File.open(file_path).read
186
+ end
187
+ end
188
+
189
+ # saving
190
+ if snippet.changed?
191
+ if snippet.save
192
+ ComfyPress.logger.warn("[Fixtures] Saved Snippet {#{snippet.identifier}}")
193
+ else
194
+ ComfyPress.logger.warn("[Fixtures] Failed to save Snippet {#{snippet.errors.inspect}}")
195
+ next
196
+ end
197
+ end
198
+ snippet_ids << snippet.id
199
+ end
200
+
201
+ # removing all db entries that are not in fixtures
202
+ site.snippets.where('id NOT IN (?)', snippet_ids).each{ |s| s.destroy }
203
+ ComfyPress.logger.warn('Imported Snippets!')
204
+ end
205
+
206
+ def self.export_layouts(from_site, to_folder = nil)
207
+ return unless site = Cms::Site.find_by_identifier(from_site)
208
+ path = File.join(ComfyPress.config.fixtures_path, (to_folder || site.identifier), 'layouts')
209
+ FileUtils.rm_rf(path)
210
+ FileUtils.mkdir_p(path)
211
+
212
+ site.layouts.each do |layout|
213
+ layout_path = File.join(path, layout.ancestors.reverse.collect{|l| l.identifier}, layout.identifier)
214
+ FileUtils.mkdir_p(layout_path)
215
+
216
+ open(File.join(layout_path, "_#{layout.identifier}.yml"), 'w') do |f|
217
+ f.write({
218
+ 'label' => layout.label,
219
+ 'app_layout' => layout.app_layout,
220
+ 'parent' => layout.parent.try(:identifier),
221
+ 'position' => layout.position
222
+ }.to_yaml)
223
+ end
224
+ open(File.join(layout_path, 'content.html'), 'w') do |f|
225
+ f.write(layout.content)
226
+ end
227
+ open(File.join(layout_path, 'css.css'), 'w') do |f|
228
+ f.write(layout.css)
229
+ end
230
+ open(File.join(layout_path, 'js.js'), 'w') do |f|
231
+ f.write(layout.js)
232
+ end
233
+ end
234
+ end
235
+
236
+ def self.export_pages(from_site, to_folder = nil)
237
+ return unless site = Cms::Site.find_by_identifier(from_site)
238
+ path = File.join(ComfyPress.config.fixtures_path, (to_folder || site.identifier), 'pages')
239
+ FileUtils.rm_rf(path)
240
+ FileUtils.mkdir_p(path)
241
+
242
+ site.pages.each do |page|
243
+ page.slug = 'index' if page.slug.blank?
244
+ page_path = File.join(path, page.ancestors.reverse.collect{|p| p.slug.blank?? 'index' : p.slug}, page.slug)
245
+ FileUtils.mkdir_p(page_path)
246
+
247
+ open(File.join(page_path, "_#{page.slug}.yml"), 'w') do |f|
248
+ f.write({
249
+ 'label' => page.label,
250
+ 'layout' => page.layout.try(:identifier),
251
+ 'parent' => page.parent && (page.parent.slug.present?? page.parent.slug : 'index'),
252
+ 'target_page' => page.target_page.try(:slug),
253
+ 'is_published' => page.is_published,
254
+ 'position' => page.position
255
+ }.to_yaml)
256
+ end
257
+ page.blocks_attributes.each do |block|
258
+ open(File.join(page_path, "#{block[:identifier]}.html"), 'w') do |f|
259
+ f.write(block[:content])
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ def self.export_snippets(from_site, to_folder = nil)
266
+ return unless site = Cms::Site.find_by_identifier(from_site)
267
+ path = File.join(ComfyPress.config.fixtures_path, (to_folder || site.identifier), 'snippets')
268
+ FileUtils.rm_rf(path)
269
+ FileUtils.mkdir_p(path)
270
+
271
+ site.snippets.each do |snippet|
272
+ FileUtils.mkdir_p(snippet_path = File.join(path, snippet.identifier))
273
+ open(File.join(snippet_path, "_#{snippet.identifier}.yml"), 'w') do |f|
274
+ f.write({'label' => snippet.label}.to_yaml)
275
+ end
276
+ open(File.join(snippet_path, 'content.html'), 'w') do |f|
277
+ f.write(snippet.content)
278
+ end
279
+ end
280
+ end
281
+
282
+ protected
283
+
284
+ def self.find_fixtures_path(identifier, dir)
285
+ path = File.join(ComfyPress.config.fixtures_path, identifier, dir)
286
+ File.exists?(path) ? path : nil
287
+ end
288
+
289
+ end
@@ -0,0 +1,97 @@
1
+ class ComfyPress::FormBuilder < FormattedForm::FormBuilder
2
+
3
+ # -- Tag Field Fields -----------------------------------------------------
4
+ def default_tag_field(tag, index, method = :text_field_tag, options = {})
5
+
6
+ label = tag.page.class.human_attribute_name(tag.identifier.to_s)
7
+ css_class = tag.class.to_s.demodulize.underscore
8
+ content = ''
9
+
10
+ case method
11
+ when :file_field_tag
12
+ input_params = {:id => nil}
13
+ name = "page[blocks_attributes][#{index}][content]"
14
+
15
+ if options.delete(:multiple)
16
+ input_params.merge!(:multiple => true)
17
+ name << '[]'
18
+ end
19
+
20
+ content << @template.send(method, name, input_params)
21
+ content << @template.render(:partial => 'cms_admin/files/page_form', :object => tag.block)
22
+ else
23
+ content << @template.send(method, "page[blocks_attributes][#{index}][content]", tag.content, options)
24
+ end
25
+ content << @template.hidden_field_tag("page[blocks_attributes][#{index}][identifier]", tag.identifier, :id => nil)
26
+
27
+ element(label, content.html_safe)
28
+ end
29
+
30
+ def field_date_time(tag, index)
31
+ default_tag_field(tag, index, :text_field_tag, :data => {:datetime => true})
32
+ end
33
+
34
+ def field_integer(tag, index)
35
+ default_tag_field(tag, index, :number_field_tag)
36
+ end
37
+
38
+ def field_string(tag, index)
39
+ default_tag_field(tag, index)
40
+ end
41
+
42
+ def field_text(tag, index)
43
+ default_tag_field(tag, index, :text_area_tag, :data => {:cm_mode => 'text/html'})
44
+ end
45
+
46
+ def field_rich_text(tag, index)
47
+ default_tag_field(tag, index, :text_area_tag, :data => {:rich_text => true})
48
+ end
49
+
50
+ def page_date_time(tag, index)
51
+ default_tag_field(tag, index, :text_field_tag, :data => {:datetime => true})
52
+ end
53
+
54
+ def page_integer(tag, index)
55
+ default_tag_field(tag, index, :number_field_tag)
56
+ end
57
+
58
+ def page_string(tag, index)
59
+ default_tag_field(tag, index)
60
+ end
61
+
62
+ def page_text(tag, index)
63
+ default_tag_field(tag, index, :text_area_tag, :data => {:cm_mode => 'text/html'})
64
+ end
65
+
66
+ def page_rich_text(tag, index)
67
+ default_tag_field(tag, index, :text_area_tag, :data => {:rich_text => true})
68
+ end
69
+
70
+ def page_file(tag, index)
71
+ default_tag_field(tag, index, :file_field_tag)
72
+ end
73
+
74
+ def page_files(tag, index)
75
+ default_tag_field(tag, index, :file_field_tag, :multiple => true)
76
+ end
77
+
78
+ def page_markdown(tag, index)
79
+ default_tag_field(tag, index, :text_area_tag, :data => {:cm_mode => 'text/x-markdown'})
80
+ end
81
+
82
+ def collection(tag, index)
83
+ options = [["---- Select #{tag.collection_class.titleize} ----", nil]] +
84
+ tag.collection_objects.collect do |m|
85
+ [m.send(tag.collection_title), m.send(tag.collection_identifier)]
86
+ end
87
+
88
+ content = @template.select_tag(
89
+ "page[blocks_attributes][#{index}][content]",
90
+ @template.options_for_select(options, :selected => tag.content),
91
+ :id => nil
92
+ )
93
+ content << @template.hidden_field_tag("page[blocks_attributes][#{index}][identifier]", tag.identifier, :id => nil)
94
+ element(tag.identifier.titleize, content, :class => tag.class.to_s.demodulize.underscore )
95
+ end
96
+
97
+ end
@@ -0,0 +1,85 @@
1
+ module ComfyPress::RenderMethods
2
+
3
+ def self.included(base)
4
+
5
+ # If application controller doesn't have template associated with it
6
+ # CMS will attempt to find one. This is so you don't have to explicitly
7
+ # call render :cms_page => '/something'
8
+ base.rescue_from 'ActionView::MissingTemplate' do |e|
9
+ begin
10
+ render :cms_page => request.path
11
+ rescue ComfyPress::MissingPage
12
+ raise e
13
+ end
14
+ end
15
+
16
+ # Now you can render cms_page simply by calling:
17
+ # render :cms_page => '/path/to/page'
18
+ # This way application controllers can use CMS content while populating
19
+ # instance variables that can be used in partials (that are included by
20
+ # by the cms page and/or layout)
21
+ #
22
+ # Or how about not worrying about setting up CMS pages and rendering
23
+ # application view using a CMS layout?
24
+ # render :cms_layout => 'layout_slug', :cms_blocks => {
25
+ # :block_label_a => 'content text',
26
+ # :block_label_b => { :template => 'path/to/template' },
27
+ # :block_label_c => { :partial => 'path/to/partial' }
28
+ # }
29
+ #
30
+ # This way you are populating page block content and rendering
31
+ # an instantialized CMS page.
32
+ #
33
+ # Site is loaded automatically based on the request. However you can force
34
+ # it by passing :cms_site parameter with site's slug. For example:
35
+ # render :cms_page => '/path/to/page', :cms_site => 'default'
36
+ #
37
+ def render(options = {}, locals = {}, &block)
38
+
39
+ if options.is_a?(Hash) && identifier = options.delete(:cms_site)
40
+ unless @cms_site = Cms::Site.find_by_identifier(identifier)
41
+ raise ComfyPress::MissingSite.new(identifier)
42
+ end
43
+ end
44
+
45
+ if options.is_a?(Hash) && path = options.delete(:cms_page)
46
+ @cms_site ||= Cms::Site.find_site(request.host.downcase, request.fullpath)
47
+ if @cms_page = @cms_site && @cms_site.pages.find_by_full_path(path)
48
+ @cms_layout = @cms_page.layout
49
+ cms_app_layout = @cms_layout.try(:app_layout)
50
+ options[:layout] ||= cms_app_layout.blank?? nil : cms_app_layout
51
+ options[:inline] = @cms_page.content
52
+ super(options, locals, &block)
53
+ else
54
+ raise ComfyPress::MissingPage.new(path)
55
+ end
56
+
57
+ elsif options.is_a?(Hash) && identifier = options.delete(:cms_layout)
58
+ @cms_site ||= Cms::Site.find_site(request.host.downcase, request.fullpath)
59
+ if @cms_layout = @cms_site && @cms_site.layouts.find_by_identifier(identifier)
60
+ cms_app_layout = @cms_layout.try(:app_layout)
61
+ cms_page = @cms_site.pages.build(:layout => @cms_layout)
62
+ cms_blocks = options.delete(:cms_blocks) || { :content => render_to_string({ :layout => false }.merge(options)) }
63
+ cms_blocks.each do |identifier, value|
64
+ content = if value.is_a?(Hash)
65
+ render_to_string(value.keys.first.to_sym => value[value.keys.first], :layout => false)
66
+ else
67
+ value.to_s
68
+ end
69
+ cms_page.blocks.build(:identifier => identifier.to_s, :content => content)
70
+ end
71
+ options[:layout] ||= cms_app_layout.blank?? nil : cms_app_layout
72
+ options[:inline] = cms_page.content(true)
73
+ super(options, locals, &block)
74
+ else
75
+ raise ComfyPress::MissingLayout.new(identifier)
76
+ end
77
+
78
+ else
79
+ super(options, locals, &block)
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ ActionController::Base.send :include, ComfyPress::RenderMethods
@@ -0,0 +1,62 @@
1
+ module ComfyPress::Routing
2
+
3
+ def self.admin(options = {})
4
+ options[:path] ||= 'cms-admin'
5
+
6
+ Rails.application.routes.draw do
7
+ namespace :cms_admin, :path => options[:path], :except => :show do
8
+ get '/', :to => 'base#jump'
9
+ resources :sites do
10
+ resources :pages do
11
+ get :form_blocks, :on => :member
12
+ get :toggle_branch, :on => :member
13
+ put :reorder, :on => :collection
14
+ resources :revisions, :only => [:index, :show, :revert] do
15
+ put :revert, :on => :member
16
+ end
17
+ end
18
+ resources :files do
19
+ put :reorder, :on => :collection
20
+ end
21
+ resources :layouts do
22
+ put :reorder, :on => :collection
23
+ resources :revisions, :only => [:index, :show, :revert] do
24
+ put :revert, :on => :member
25
+ end
26
+ end
27
+ resources :snippets do
28
+ put :reorder, :on => :collection
29
+ resources :revisions, :only => [:index, :show, :revert] do
30
+ put :revert, :on => :member
31
+ end
32
+ end
33
+ resources :categories
34
+ resources :menus do
35
+ resources :menu_items
36
+ end
37
+ get 'dialog/:type' => 'dialogs#show', :as => 'dialog'
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.content(options = {})
44
+
45
+ Rails.application.routes.draw do
46
+ namespace :cms_content, :path => options[:path] do
47
+ get 'cms-css/:site_id/:identifier' => :render_css, :as => 'css'
48
+ get 'cms-js/:site_id/:identifier' => :render_js, :as => 'js'
49
+
50
+ if options[:sitemap]
51
+ get '(:cms_path)/sitemap' => :render_sitemap,
52
+ :as => 'sitemap',
53
+ :constraints => {:format => /xml/},
54
+ :format => :xml
55
+ end
56
+
57
+ get '/' => :render_html, :as => 'html', :path => "(*cms_path)"
58
+ end
59
+ end
60
+ end
61
+
62
+ end