comfortable_mexican_sofa 0.0.18 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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