comfortable_mexican_sofa 0.0.18 → 1.0.0

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 (263) hide show
  1. data/.gitignore +8 -8
  2. data/Gemfile +11 -0
  3. data/Gemfile.lock +91 -0
  4. data/README.md +4 -0
  5. data/Rakefile +28 -57
  6. data/VERSION +1 -1
  7. data/app/controllers/application_controller.rb +5 -0
  8. data/app/controllers/cms_admin/base_controller.rb +1 -21
  9. data/app/controllers/cms_admin/layouts_controller.rb +23 -38
  10. data/app/controllers/cms_admin/pages_controller.rb +24 -40
  11. data/app/controllers/cms_admin/snippets_controller.rb +26 -34
  12. data/app/controllers/cms_admin/uploads_controller.rb +27 -0
  13. data/app/controllers/cms_content_controller.rb +22 -19
  14. data/app/models/cms_block.rb +20 -6
  15. data/app/models/cms_layout.rb +34 -80
  16. data/app/models/cms_page.rb +44 -102
  17. data/app/models/cms_snippet.rb +12 -7
  18. data/app/models/cms_upload.rb +36 -0
  19. data/app/views/cms_admin/layouts/_form.html.erb +6 -0
  20. data/app/views/cms_admin/layouts/_index_branch.html.erb +24 -0
  21. data/app/views/cms_admin/layouts/edit.html.erb +6 -0
  22. data/app/views/cms_admin/layouts/index.html.erb +6 -0
  23. data/app/views/cms_admin/layouts/new.html.erb +6 -0
  24. data/app/views/cms_admin/pages/_form.html.erb +14 -0
  25. data/app/views/cms_admin/pages/_form_blocks.html.erb +7 -0
  26. data/app/views/cms_admin/pages/_index_branch.html.erb +27 -0
  27. data/app/views/cms_admin/pages/edit.html.erb +6 -0
  28. data/app/views/cms_admin/pages/form_blocks.js.erb +1 -0
  29. data/app/views/cms_admin/pages/index.html.erb +6 -0
  30. data/app/views/cms_admin/pages/new.html.erb +6 -0
  31. data/app/views/cms_admin/snippets/_form.html.erb +2 -0
  32. data/app/views/cms_admin/snippets/edit.html.erb +6 -0
  33. data/app/views/cms_admin/snippets/index.html.erb +3 -0
  34. data/app/views/cms_admin/snippets/new.html.erb +6 -0
  35. data/app/views/cms_admin/uploads/_index.html.erb +8 -0
  36. data/app/views/cms_admin/uploads/_upload.html.erb +11 -0
  37. data/app/views/cms_admin/uploads/destroy.js.erb +3 -0
  38. data/app/views/cms_admin/uploads/index.html.erb +2 -0
  39. data/app/views/layouts/cms_admin.html.erb +36 -0
  40. data/comfortable_mexican_sofa.gemspec +141 -197
  41. data/config.ru +4 -0
  42. data/config/application.rb +44 -0
  43. data/config/boot.rb +13 -0
  44. data/{test/rails_root/config → config}/database.yml +0 -0
  45. data/config/environment.rb +5 -0
  46. data/config/environments/development.rb +22 -0
  47. data/config/environments/production.rb +49 -0
  48. data/config/environments/test.rb +35 -0
  49. data/{test/rails_root/config → config}/initializers/backtrace_silencers.rb +2 -2
  50. data/{test/rails_root/config → config}/initializers/inflections.rb +1 -1
  51. data/{test/rails_root/config → config}/initializers/mime_types.rb +0 -0
  52. data/config/initializers/paperclip.rb +3 -0
  53. data/config/initializers/secret_token.rb +7 -0
  54. data/config/initializers/session_store.rb +8 -0
  55. data/{test/rails_root/config → config}/locales/en.yml +1 -1
  56. data/config/routes.rb +20 -0
  57. data/db/migrate/01_create_cms.rb +73 -0
  58. data/db/seeds.rb +7 -0
  59. data/doc/README_FOR_APP +95 -0
  60. data/lib/comfortable_mexican_sofa.rb +34 -39
  61. data/lib/comfortable_mexican_sofa/cms_acts_as_tree.rb +42 -49
  62. data/lib/comfortable_mexican_sofa/cms_form_builder.rb +107 -0
  63. data/lib/comfortable_mexican_sofa/cms_rails_extensions.rb +25 -5
  64. data/lib/comfortable_mexican_sofa/cms_tag.rb +90 -85
  65. data/lib/comfortable_mexican_sofa/cms_tag/field_datetime.rb +26 -0
  66. data/lib/comfortable_mexican_sofa/cms_tag/field_integer.rb +26 -0
  67. data/lib/comfortable_mexican_sofa/cms_tag/field_string.rb +26 -0
  68. data/lib/comfortable_mexican_sofa/cms_tag/field_text.rb +26 -0
  69. data/lib/comfortable_mexican_sofa/cms_tag/page_datetime.rb +22 -0
  70. data/lib/comfortable_mexican_sofa/cms_tag/page_integer.rb +22 -0
  71. data/lib/comfortable_mexican_sofa/cms_tag/page_string.rb +22 -0
  72. data/lib/comfortable_mexican_sofa/cms_tag/page_text.rb +22 -0
  73. data/lib/comfortable_mexican_sofa/cms_tag/partial.rb +20 -0
  74. data/lib/comfortable_mexican_sofa/cms_tag/snippet.rb +18 -0
  75. data/{generators/cms/templates → lib/generators}/README +0 -20
  76. data/lib/generators/cms_generator.rb +28 -0
  77. data/public/404.html +26 -0
  78. data/public/422.html +26 -0
  79. data/public/500.html +26 -0
  80. data/{test/rails_root/public → public}/favicon.ico +0 -0
  81. data/public/images/comfortable_mexican_sofa/body_bg.jpg +0 -0
  82. data/{generators/cms/templates/images → public/images/comfortable_mexican_sofa}/icon_regular.gif +0 -0
  83. data/public/javascripts/comfortable_mexican_sofa/cms.js +53 -0
  84. data/public/javascripts/comfortable_mexican_sofa/jquery-ui.js +325 -0
  85. data/public/javascripts/comfortable_mexican_sofa/jquery.js +154 -0
  86. data/public/javascripts/comfortable_mexican_sofa/plupload/plupload.full.min.js +1 -0
  87. data/public/javascripts/comfortable_mexican_sofa/plupload/plupload.html4.min.js +1 -0
  88. data/public/javascripts/comfortable_mexican_sofa/plupload/plupload.html5.min.js +1 -0
  89. data/public/javascripts/comfortable_mexican_sofa/rails.js +132 -0
  90. data/public/javascripts/comfortable_mexican_sofa/uploader.js +47 -0
  91. data/{test/rails_root/public → public}/robots.txt +0 -0
  92. data/public/stylesheets/comfortable_mexican_sofa/jquery-ui.css +305 -0
  93. data/public/stylesheets/comfortable_mexican_sofa/reset.css +1 -0
  94. data/public/stylesheets/comfortable_mexican_sofa/structure.css +194 -0
  95. data/public/stylesheets/comfortable_mexican_sofa/typography.css +20 -0
  96. data/script/rails +6 -0
  97. data/test/fixtures/README.md +22 -0
  98. data/test/fixtures/cms_blocks.yml +10 -34
  99. data/test/fixtures/cms_layouts.yml +37 -33
  100. data/test/fixtures/cms_pages.yml +11 -32
  101. data/test/fixtures/cms_snippets.yml +2 -6
  102. data/test/fixtures/cms_uploads.yml +4 -0
  103. data/test/fixtures/files/invalid_file.gif +9 -0
  104. data/test/fixtures/files/valid_image.jpg +0 -0
  105. data/test/functional/cms_admin/base_controller_test.rb +9 -0
  106. data/test/functional/cms_admin/layouts_controller_test.rb +61 -46
  107. data/test/functional/cms_admin/pages_controller_test.rb +201 -102
  108. data/test/functional/cms_admin/snippets_controller_test.rb +46 -39
  109. data/test/functional/cms_admin/uploads_controller_test.rb +32 -0
  110. data/test/functional/cms_content_controller_test.rb +37 -32
  111. data/test/test_helper.rb +29 -9
  112. data/test/unit/cms_block_test.rb +60 -0
  113. data/test/unit/cms_layout_test.rb +48 -0
  114. data/test/unit/cms_page_test.rb +122 -0
  115. data/test/unit/cms_snippet_test.rb +23 -0
  116. data/test/unit/cms_tag_test.rb +149 -0
  117. data/test/unit/cms_tags/field_datetime_test.rb +36 -0
  118. data/test/unit/cms_tags/field_integer_test.rb +35 -0
  119. data/test/unit/cms_tags/field_string_test.rb +35 -0
  120. data/test/unit/cms_tags/field_text_test.rb +34 -0
  121. data/test/unit/cms_tags/page_datetime_test.rb +36 -0
  122. data/test/unit/cms_tags/page_integer_test.rb +35 -0
  123. data/test/unit/cms_tags/page_string_test.rb +35 -0
  124. data/test/unit/cms_tags/page_text_test.rb +36 -0
  125. data/test/unit/cms_tags/partial_test.rb +30 -0
  126. data/test/unit/cms_tags/snippet_test.rb +34 -0
  127. data/test/unit/cms_upload_test.rb +30 -0
  128. metadata +176 -215
  129. data/CHANGELOG.rdoc +0 -2
  130. data/LICENSE +0 -20
  131. data/README.rdoc +0 -55
  132. data/app/controllers/cms_admin/attachments_controller.rb +0 -55
  133. data/app/controllers/cms_admin/categories_controller.rb +0 -69
  134. data/app/controllers/cms_admin/sections_controller.rb +0 -17
  135. data/app/controllers/cms_common/render_page.rb +0 -47
  136. data/app/helpers/cms_helper.rb +0 -12
  137. data/app/models/cms_attachment.rb +0 -17
  138. data/app/models/cms_attachment_categorization.rb +0 -5
  139. data/app/models/cms_category.rb +0 -36
  140. data/app/models/cms_page_categorization.rb +0 -6
  141. data/app/views/cms_admin/attachments/_details.html.haml +0 -27
  142. data/app/views/cms_admin/attachments/_form.html.haml +0 -24
  143. data/app/views/cms_admin/attachments/edit.html.haml +0 -10
  144. data/app/views/cms_admin/attachments/index.html.haml +0 -36
  145. data/app/views/cms_admin/attachments/new.html.haml +0 -8
  146. data/app/views/cms_admin/categories/_category.html.haml +0 -21
  147. data/app/views/cms_admin/categories/_category_subform.html.haml +0 -12
  148. data/app/views/cms_admin/categories/_form.html.haml +0 -18
  149. data/app/views/cms_admin/categories/_new.html.haml +0 -7
  150. data/app/views/cms_admin/categories/_toggle_link.html.haml +0 -9
  151. data/app/views/cms_admin/categories/_tree_branch.html.haml +0 -36
  152. data/app/views/cms_admin/categories/children.js.rjs +0 -10
  153. data/app/views/cms_admin/categories/create.js.rjs +0 -9
  154. data/app/views/cms_admin/categories/edit.html.haml +0 -10
  155. data/app/views/cms_admin/categories/index.html.haml +0 -7
  156. data/app/views/cms_admin/categories/new.html.haml +0 -8
  157. data/app/views/cms_admin/categories/show.html.haml +0 -17
  158. data/app/views/cms_admin/layouts/_details.html.haml +0 -6
  159. data/app/views/cms_admin/layouts/_form.html.haml +0 -19
  160. data/app/views/cms_admin/layouts/_toggle_link.html.haml +0 -9
  161. data/app/views/cms_admin/layouts/_tree_branch.html.haml +0 -39
  162. data/app/views/cms_admin/layouts/children.js.rjs +0 -10
  163. data/app/views/cms_admin/layouts/edit.html.haml +0 -10
  164. data/app/views/cms_admin/layouts/index.html.haml +0 -7
  165. data/app/views/cms_admin/layouts/new.html.haml +0 -8
  166. data/app/views/cms_admin/pages/_details.html.haml +0 -25
  167. data/app/views/cms_admin/pages/_form.html.haml +0 -45
  168. data/app/views/cms_admin/pages/_form_blocks.html.haml +0 -48
  169. data/app/views/cms_admin/pages/_toggle_link.html.haml +0 -10
  170. data/app/views/cms_admin/pages/_tree_branch.html.haml +0 -41
  171. data/app/views/cms_admin/pages/children.js.rjs +0 -10
  172. data/app/views/cms_admin/pages/edit.html.haml +0 -11
  173. data/app/views/cms_admin/pages/form_blocks.js.rjs +0 -1
  174. data/app/views/cms_admin/pages/index.html.haml +0 -6
  175. data/app/views/cms_admin/pages/new.html.haml +0 -9
  176. data/app/views/cms_admin/sections/show.html.haml +0 -23
  177. data/app/views/cms_admin/snippets/_form.html.haml +0 -10
  178. data/app/views/cms_admin/snippets/edit.html.haml +0 -10
  179. data/app/views/cms_admin/snippets/index.html.haml +0 -26
  180. data/app/views/cms_admin/snippets/new.html.haml +0 -8
  181. data/app/views/cms_content/show.xml.rxml +0 -27
  182. data/app/views/cms_content/sitemap.xml.rxml +0 -16
  183. data/app/views/layouts/cms_admin.html.haml +0 -44
  184. data/config/cms_routes.rb +0 -25
  185. data/generators/cms/cms_generator.rb +0 -55
  186. data/generators/cms/templates/images/arrow_bottom.gif +0 -0
  187. data/generators/cms/templates/images/arrow_right.gif +0 -0
  188. data/generators/cms/templates/images/icon_attachment.gif +0 -0
  189. data/generators/cms/templates/images/icon_category.gif +0 -0
  190. data/generators/cms/templates/images/icon_draft.gif +0 -0
  191. data/generators/cms/templates/images/icon_layout.gif +0 -0
  192. data/generators/cms/templates/images/icon_move.gif +0 -0
  193. data/generators/cms/templates/images/icon_snippet.gif +0 -0
  194. data/generators/cms/templates/images/logo.png +0 -0
  195. data/generators/cms/templates/initializers/cms.rb +0 -14
  196. data/generators/cms/templates/initializers/paperclip.rb +0 -14
  197. data/generators/cms/templates/javascripts/codemirror_init.js +0 -16
  198. data/generators/cms/templates/javascripts/mce_init.js +0 -17
  199. data/generators/cms/templates/javascripts/utilities.js +0 -27
  200. data/generators/cms/templates/migrations/create_cms.rb +0 -113
  201. data/generators/cms/templates/stylesheets/cms_master.sass +0 -414
  202. data/init.rb +0 -1
  203. data/lib/comfortable_mexican_sofa/acts_as_categorized.rb +0 -87
  204. data/lib/comfortable_mexican_sofa/acts_as_published.rb +0 -60
  205. data/lib/comfortable_mexican_sofa/cms_tags/attachment.rb +0 -3
  206. data/lib/comfortable_mexican_sofa/cms_tags/block.rb +0 -117
  207. data/lib/comfortable_mexican_sofa/cms_tags/helper.rb +0 -3
  208. data/lib/comfortable_mexican_sofa/cms_tags/page_block.rb +0 -119
  209. data/lib/comfortable_mexican_sofa/cms_tags/partial.rb +0 -19
  210. data/lib/comfortable_mexican_sofa/cms_tags/snippet.rb +0 -19
  211. data/rails/init.rb +0 -1
  212. data/test/fixtures/cms_attachment_categorizations.yml +0 -7
  213. data/test/fixtures/cms_attachments.yml +0 -6
  214. data/test/fixtures/cms_categories.yml +0 -19
  215. data/test/fixtures/cms_page_categorizations.yml +0 -15
  216. data/test/fixtures/files/upload_file.txt +0 -1
  217. data/test/functional/cms_admin/attachments_controller_test.rb +0 -63
  218. data/test/functional/cms_admin/categories_controller_test.rb +0 -86
  219. data/test/functional/cms_admin/sections_controller_test.rb +0 -9
  220. data/test/models/cms_attachment_test.rb +0 -16
  221. data/test/models/cms_block_test.rb +0 -11
  222. data/test/models/cms_categorization_test.rb +0 -39
  223. data/test/models/cms_category_test.rb +0 -71
  224. data/test/models/cms_layout_test.rb +0 -44
  225. data/test/models/cms_page_test.rb +0 -55
  226. data/test/models/cms_snippet_test.rb +0 -16
  227. data/test/models/cms_tag_test.rb +0 -70
  228. data/test/rails_root/README +0 -243
  229. data/test/rails_root/Rakefile +0 -10
  230. data/test/rails_root/app/controllers/application_controller.rb +0 -10
  231. data/test/rails_root/app/helpers/application_helper.rb +0 -3
  232. data/test/rails_root/app/views/cms/under-development.html.haml +0 -1
  233. data/test/rails_root/app/views/complex_page/_example.html.erb +0 -1
  234. data/test/rails_root/config/boot.rb +0 -110
  235. data/test/rails_root/config/environment.rb +0 -48
  236. data/test/rails_root/config/environments/development.rb +0 -17
  237. data/test/rails_root/config/environments/production.rb +0 -28
  238. data/test/rails_root/config/environments/test.rb +0 -28
  239. data/test/rails_root/config/initializers/new_rails_defaults.rb +0 -19
  240. data/test/rails_root/config/initializers/session_store.rb +0 -15
  241. data/test/rails_root/config/routes.rb +0 -43
  242. data/test/rails_root/doc/README_FOR_APP +0 -2
  243. data/test/rails_root/public/404.html +0 -30
  244. data/test/rails_root/public/422.html +0 -30
  245. data/test/rails_root/public/500.html +0 -30
  246. data/test/rails_root/public/images/rails.png +0 -0
  247. data/test/rails_root/public/index.html +0 -275
  248. data/test/rails_root/public/javascripts/application.js +0 -2
  249. data/test/rails_root/public/javascripts/controls.js +0 -963
  250. data/test/rails_root/public/javascripts/dragdrop.js +0 -973
  251. data/test/rails_root/public/javascripts/effects.js +0 -1128
  252. data/test/rails_root/public/javascripts/prototype.js +0 -4320
  253. data/test/rails_root/public/stylesheets/sass/cms_master.sass +0 -414
  254. data/test/rails_root/script/about +0 -4
  255. data/test/rails_root/script/console +0 -3
  256. data/test/rails_root/script/dbconsole +0 -3
  257. data/test/rails_root/script/destroy +0 -3
  258. data/test/rails_root/script/generate +0 -3
  259. data/test/rails_root/script/performance/benchmarker +0 -3
  260. data/test/rails_root/script/performance/profiler +0 -3
  261. data/test/rails_root/script/plugin +0 -3
  262. data/test/rails_root/script/runner +0 -3
  263. data/test/rails_root/script/server +0 -3
@@ -1,65 +1,58 @@
1
1
  module ActiveRecord
2
2
  module Acts
3
3
  module Tree
4
+
4
5
  def self.included(base)
5
6
  base.extend(ClassMethods)
6
7
  end
7
-
8
- # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
9
- # association. This requires that you have a foreign key column, which by default is called +parent_id+.
10
- #
11
- # class Category < ActiveRecord::Base
12
- # acts_as_tree :order => "name"
13
- # end
14
- #
15
- # Example:
16
- # root
17
- # \_ child1
18
- # \_ subchild1
19
- # \_ subchild2
20
- #
21
- # root = Category.create("name" => "root")
22
- # child1 = root.children.create("name" => "child1")
23
- # subchild1 = child1.children.create("name" => "subchild1")
24
- #
25
- # root.parent # => nil
26
- # child1.parent # => root
27
- # root.children # => [child1]
28
- # root.children.first.children.first # => subchild1
29
- #
30
- # In addition to the parent and children associations, the following instance methods are added to the class
31
- # after calling <tt>acts_as_tree</tt>:
32
- # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
33
- # * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
34
- # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
35
- # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
8
+
36
9
  module ClassMethods
37
- # Configuration options are:
38
- #
39
- # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
40
- # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
41
- # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
42
10
  def acts_as_tree(options = {})
43
- configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
11
+ configuration = {
12
+ :foreign_key => 'parent_id',
13
+ :order => nil,
14
+ :counter_cache => nil,
15
+ :dependent => :destroy,
16
+ :touch => false }
44
17
  configuration.update(options) if options.is_a?(Hash)
45
-
46
- belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
47
- has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
48
-
18
+
19
+ belongs_to :parent,
20
+ :class_name => name,
21
+ :foreign_key => configuration[:foreign_key],
22
+ :counter_cache => configuration[:counter_cache],
23
+ :touch => configuration[:touch]
24
+
25
+ has_many :children,
26
+ :class_name => name,
27
+ :foreign_key => configuration[:foreign_key],
28
+ :order => configuration[:order],
29
+ :dependent => configuration[:dependent]
30
+
49
31
  class_eval <<-EOV
50
32
  include ActiveRecord::Acts::Tree::InstanceMethods
51
-
52
- def self.roots
53
- find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
54
- end
55
-
33
+
34
+ scope :roots,
35
+ :conditions => "#{configuration[:foreign_key]} IS NULL",
36
+ :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}
37
+
56
38
  def self.root
57
- find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
39
+ roots.first
40
+ end
41
+
42
+ validates_each "#{configuration[:foreign_key]}" do |record, attr, value|
43
+ if value
44
+ if record.id == value
45
+ record.errors.add attr, "cannot be it's own id"
46
+ elsif record.descendants.map {|c| c.id}.include?(value)
47
+ record.errors.add attr, "cannot be a descendant's id"
48
+ end
49
+ end
58
50
  end
51
+
59
52
  EOV
60
53
  end
61
54
  end
62
-
55
+
63
56
  module InstanceMethods
64
57
  # Returns list of ancestors, starting from parent until root.
65
58
  #
@@ -79,21 +72,21 @@ module ActiveRecord
79
72
  end
80
73
  nodes.flatten
81
74
  end
82
-
75
+
83
76
  # Returns the root node of the tree.
84
77
  def root
85
78
  node = self
86
79
  node = node.parent while node.parent
87
80
  node
88
81
  end
89
-
82
+
90
83
  # Returns all siblings of the current node.
91
84
  #
92
85
  # subchild1.siblings # => [subchild2]
93
86
  def siblings
94
87
  self_and_siblings - [self]
95
88
  end
96
-
89
+
97
90
  # Returns all siblings and a reference to the current node.
98
91
  #
99
92
  # subchild1.self_and_siblings # => [subchild1, subchild2]
@@ -0,0 +1,107 @@
1
+ class CmsFormBuilder < ActionView::Helpers::FormBuilder
2
+
3
+ helpers = field_helpers -
4
+ %w(hidden_field fields_for) +
5
+ %w(select)
6
+
7
+ helpers.each do |name|
8
+ class_eval %Q^
9
+ def #{name}(field, *args)
10
+ options = args.extract_options!
11
+ args << options
12
+ return super if options.delete(:disable_builder)
13
+ default_field('#{name}', field, options){ super }
14
+ end
15
+ ^
16
+ end
17
+
18
+ def default_field(type, field, options = {}, &block)
19
+ %(
20
+ <div class='form_element #{type}_element'>
21
+ <div class='label'>#{label_for(field, options)}</div>
22
+ <div class='value'>#{yield}</div>
23
+ </div>
24
+ ).html_safe
25
+ end
26
+
27
+ def label_for(field, options)
28
+ label = options.delete(:label) || field.to_s.titleize.capitalize_all
29
+ "<label for=\"#{object_name}_#{field}\">#{label}</label>".html_safe
30
+ end
31
+
32
+ def submit(value, options = {}, &block)
33
+ extra_content = @template.capture(&block) if block_given?
34
+ cancel_link ||= options[:cancel_url] ? ' or ' + options.delete(:cancel_url) : ''
35
+ %(
36
+ <div class='form_element submit_element'>
37
+ #{super(value, options)} #{extra_content} #{cancel_link}
38
+ </div>
39
+ ).html_safe
40
+ end
41
+
42
+ # -- Tag Field Fields -----------------------------------------------------
43
+ def default_tag_field(tag, options = {})
44
+ label = options[:label] || tag.label.to_s.titleize
45
+ css_class = options[:css_class] || tag.class.to_s.underscore.downcase.idify
46
+
47
+ options[:content_field_method] ||= :text_field_tag
48
+ field =
49
+ options[:field] ||
50
+ @template.send(options[:content_field_method], 'cms_page[cms_blocks_attributes][][content]', tag.content, :id => nil)
51
+
52
+ %(
53
+ <div class='form_element #{css_class}'>
54
+ <div class='label'>#{label}</div>
55
+ <div class='value'>
56
+ #{field}
57
+ #{@template.hidden_field_tag('cms_page[cms_blocks_attributes][][label]', tag.label)}
58
+ #{@template.hidden_field_tag('cms_page[cms_blocks_attributes][][type]', tag.type)}
59
+ #{@template.hidden_field_tag('cms_page[cms_blocks_attributes][][id]', tag.id) unless tag.new_record?}
60
+ </div>
61
+ </div>
62
+ ).html_safe
63
+ end
64
+
65
+ def field_date_time(tag)
66
+ default_tag_field(tag, :content_field_method => :datetime_field_tag)
67
+ end
68
+
69
+ def field_integer(tag)
70
+ default_tag_field(tag, :content_field_method => :number_field_tag)
71
+ end
72
+
73
+ def field_string(tag)
74
+ default_tag_field(tag)
75
+ end
76
+
77
+ def field_text(tag)
78
+ default_tag_field(tag, :content_field_method => :text_area_tag)
79
+ end
80
+
81
+ def page_date_time(tag)
82
+ default_tag_field(tag, :content_field_method => :datetime_field_tag)
83
+ end
84
+
85
+ def page_integer(tag)
86
+ default_tag_field(tag, :content_field_method => :number_field_tag)
87
+ end
88
+
89
+ def page_string(tag)
90
+ default_tag_field(tag)
91
+ end
92
+
93
+ def page_text(tag)
94
+ default_tag_field(tag, :content_field_method => :text_area_tag)
95
+ end
96
+
97
+ # Capturing all calls of cms_tag_* type. For those we'll try to render
98
+ # a form element. Everything else can trigger MethodNotFound error.
99
+ def method_missing(method_name, *args)
100
+ if m = method_name.to_s.match(/^cms_tag_(\w+)$/)
101
+ send(m[1], *args) if respond_to?(m[1])
102
+ else
103
+ super
104
+ end
105
+ end
106
+
107
+ end
@@ -1,12 +1,32 @@
1
1
  class String
2
-
3
2
  # Converts string to something suitable to be used as an element id
4
3
  def idify
5
4
  self.strip.gsub(/\W/, '_').gsub(/\s|^_*|_*$/, '').squeeze('_')
6
5
  end
7
6
 
8
- # Converts a string to something usable as a url slug
9
- def slugify
10
- self.downcase.gsub(/\W|_/, ' ').strip.squeeze(' ').gsub(/\s/, '-')
7
+ # Capitalize all words in the string
8
+ def capitalize_all(delimiter = ' ')
9
+ self.split(delimiter).collect{|w| w.capitalize }.join(' ')
11
10
  end
12
- end
11
+ end
12
+
13
+ module CmsViewHelpers
14
+
15
+ # Wrapper around CmsFormBuilder
16
+ def cms_form_for(record_or_name_or_array, *args, &proc)
17
+ options = args.extract_options!
18
+ form_for(record_or_name_or_array, *(args << options.merge(:builder => CmsFormBuilder)), &proc)
19
+ end
20
+
21
+ # Wrapper for <span>
22
+ def span_tag(*args)
23
+ content_tag(:span, *args)
24
+ end
25
+
26
+ # Rails 3.0 doesn't have this helper defined
27
+ def datetime_field_tag(name, value = nil, options = {})
28
+ text_field_tag(name, value, options.stringify_keys.update('type' => 'datetime'))
29
+ end
30
+ end
31
+
32
+ ActionView::Base.send :include, CmsViewHelpers
@@ -1,109 +1,114 @@
1
+ # This module provides all Tag classes with neccessary methods.
2
+ # Example class that will behave as a Tag:
3
+ # class MySpecialTag
4
+ # include CmsTag
5
+ # ...
6
+ # end
1
7
  module CmsTag
2
8
 
3
- class TagError < StandardError; end
9
+ attr_accessor :parent
4
10
 
5
- # Initializes all tags found in the provided content
6
- # Will ignore duplicate tags. Will use format definition of the first one.
7
- def self.parse_tags(*args)
8
- options = args.extract_options!
9
- content = args.first
11
+ module ClassMethods
12
+ # Regex that is used to match tags in the content
13
+ # Example:
14
+ # /<\s*?cms:page:(\w+)\/?>/
15
+ # will match tags like these:
16
+ # <cms:page:my_label/>
17
+ def regex_tag_signature
18
+ nil
19
+ end
10
20
 
11
- # bailing out if nothing was sent for parsing
12
- return [] if content.blank?
13
-
14
- tags = []
15
- CmsTag::Tag.subclasses.each do |tag|
16
- tag = tag.constantize
17
- tags << tag.parse_tags(content).group_by{|s| s.split(':')[0...2].join(':')}.collect{|g, tag_signature| tag.new(tag_signature.first, options)}
21
+ # Initializing tag object for a particular Tag type
22
+ # First capture group in the regex is the tag label
23
+ def initialize_tag(cms_page, tag_signature)
24
+ if match = tag_signature.match(regex_tag_signature)
25
+ if self.respond_to?(:initialize_or_find)
26
+ self.initialize_or_find(cms_page, match[1])
27
+ else
28
+ tag = self.new
29
+ tag.label = match[1]
30
+ tag
31
+ end
32
+ end
18
33
  end
19
- tags.flatten
20
34
  end
21
35
 
22
- class Tag
23
- attr_accessor :tag_signature, :label, :view, :page
24
-
25
- # Returns tag type based on it's classname
26
- # CmsTag::MyAwesomeTag.tag_type => 'cms_my_awesome_tag'
27
- def self.tag_type
28
- 'cms_' + to_s.split('::').last.underscore
29
- end
30
-
31
- def tag_type
32
- self.class.tag_type
33
- end
34
-
35
- # regular expression that finds tag signature
36
- def self.regex
37
- 'tag regex not defined'
38
- end
39
-
40
- # regex needed for content substitution
41
- def regex
42
- 'tag regex not defined'
43
- end
44
-
45
- # Returns tag identifiers from passed content based on regex defined
46
- # for the particular tag
47
- def self.parse_tags(content)
48
- content.scan(regex).flatten
49
- end
50
-
51
- # order at which tags get replaced with their content during page rendering
52
- def self.render_priority
53
- 0
54
- end
55
-
56
- def self.has_form?
57
- false
58
- end
36
+ module InstanceMethods
59
37
 
60
- def initialize(*args)
61
- options = args.extract_options!
62
- self.tag_signature = args.first
63
-
64
- # provides access to action view methods for rendering form elements
65
- if options[:view]
66
- unless options[:view].is_a?(ActionView::Base)
67
- raise TagError, "Expected ActionView::Base but got #{options[:view].class}"
68
- end
69
- self.view = options[:view]
70
- end
71
-
72
- # owner of the the tag
73
- if options[:page]
74
- unless options[:page].is_a?(CmsPage)
75
- raise TagError, "Expected CmsPage but got #{options[:page].class}"
76
- end
77
- self.page = options[:page]
78
- end
79
-
80
- tokens = self.tag_signature.split(':')
81
- self.label = tokens[1]
82
-
83
- assign_accessors
38
+ # String indentifier of the tag
39
+ def identifier
40
+ "#{self.class.name.underscore}_#{self.label}"
84
41
  end
85
42
 
86
- def assign_accessors
87
- # ... FIX: looks retarded
43
+ # Equality check. Content doesn't matter. Tag identifier does.
44
+ def ==(tag)
45
+ self.identifier == tag.identifier
88
46
  end
89
47
 
90
- def form_label
91
- "Label Undefined!"
48
+ # Ancestors of this tag constructed during rendering process.
49
+ def ancestors
50
+ node, nodes = self, []
51
+ nodes << node = node.parent while node.parent
52
+ nodes
92
53
  end
93
54
 
94
- def form_input
95
- "Form Field Undefined!"
55
+ # Regex that is used to identify instance of the tag
56
+ # Example:
57
+ # /<\s*?cms:page:tag_label\/?>/
58
+ def regex_tag_signature
59
+ nil
96
60
  end
97
61
 
62
+ # Content that is accociated with Tag instance.
98
63
  def content
99
- 'Undefined Tag'
64
+ nil
100
65
  end
101
66
 
102
- # when cms_page renders its content this is what tag outputs on the page
67
+ # Content that is used during page rendering. Outputting existing content
68
+ # as a default.
103
69
  def render
104
- content
70
+ content.to_s
105
71
  end
106
-
107
72
  end
108
73
 
74
+ private
75
+
76
+ # Initializes a tag. It's handled by one of the tag classes
77
+ def self.initialize_tag(cms_page, tag_signature)
78
+ tag_instance = nil
79
+ tag_classes.find{ |c| tag_instance = c.initialize_tag(cms_page, tag_signature) }
80
+ tag_instance
81
+ end
82
+
83
+ # Scanning provided content and splitting it into [tag, text] tuples.
84
+ # Tags are processed further and their content is expanded in the same way.
85
+ # Tags are defined in the parent tags are ignored and not rendered.
86
+ def self.process_content(cms_page, content = '', parent_tag = nil)
87
+ tokens = content.to_s.scan(/(<\s*cms:\w+:\w+(?::\w+)?\s*\/?>)|((?:[^<]|\<(?!\s*cms:\w+:\w+(?::\w+)?\s*\/?>))+)/)
88
+ tokens.collect do |tag_signature, text|
89
+ if tag_signature
90
+ if tag = self.initialize_tag(cms_page, tag_signature)
91
+ tag.parent = parent_tag if parent_tag
92
+ unless tag.ancestors.member?(tag)
93
+ cms_page.cms_tags << tag
94
+ self.process_content(cms_page, tag.render, tag)
95
+ end
96
+ end
97
+ else
98
+ text
99
+ end
100
+ end.join('')
101
+ end
102
+
103
+ def self.included(tag)
104
+ tag.send(:include, CmsTag::InstanceMethods)
105
+ tag.send(:extend, CmsTag::ClassMethods)
106
+ @@tag_classes ||= []
107
+ @@tag_classes << tag
108
+ end
109
+
110
+ # A list of registered Tag classes
111
+ def self.tag_classes
112
+ @@tag_classes ||= []
113
+ end
109
114
  end