comfortable_mexican_sofa 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/CHANGELOG.rdoc +2 -0
- data/LICENSE +20 -0
- data/README.rdoc +55 -0
- data/Rakefile +88 -0
- data/VERSION +1 -0
- data/app/controllers/cms_admin/attachments_controller.rb +55 -0
- data/app/controllers/cms_admin/base_controller.rb +25 -0
- data/app/controllers/cms_admin/categories_controller.rb +69 -0
- data/app/controllers/cms_admin/layouts_controller.rb +71 -0
- data/app/controllers/cms_admin/pages_controller.rb +79 -0
- data/app/controllers/cms_admin/sections_controller.rb +17 -0
- data/app/controllers/cms_admin/snippets_controller.rb +58 -0
- data/app/controllers/cms_common/render_page.rb +47 -0
- data/app/controllers/cms_content_controller.rb +30 -0
- data/app/helpers/cms_helper.rb +12 -0
- data/app/models/cms_attachment.rb +17 -0
- data/app/models/cms_attachment_categorization.rb +5 -0
- data/app/models/cms_block.rb +15 -0
- data/app/models/cms_category.rb +36 -0
- data/app/models/cms_layout.rb +102 -0
- data/app/models/cms_page.rb +125 -0
- data/app/models/cms_page_categorization.rb +6 -0
- data/app/models/cms_snippet.rb +15 -0
- data/app/views/cms_admin/attachments/_details.html.haml +27 -0
- data/app/views/cms_admin/attachments/_form.html.haml +24 -0
- data/app/views/cms_admin/attachments/edit.html.haml +10 -0
- data/app/views/cms_admin/attachments/index.html.haml +36 -0
- data/app/views/cms_admin/attachments/new.html.haml +8 -0
- data/app/views/cms_admin/categories/_category.html.haml +21 -0
- data/app/views/cms_admin/categories/_category_subform.html.haml +12 -0
- data/app/views/cms_admin/categories/_form.html.haml +18 -0
- data/app/views/cms_admin/categories/_new.html.haml +7 -0
- data/app/views/cms_admin/categories/_toggle_link.html.haml +9 -0
- data/app/views/cms_admin/categories/_tree_branch.html.haml +36 -0
- data/app/views/cms_admin/categories/children.js.rjs +10 -0
- data/app/views/cms_admin/categories/create.js.rjs +9 -0
- data/app/views/cms_admin/categories/edit.html.haml +10 -0
- data/app/views/cms_admin/categories/index.html.haml +7 -0
- data/app/views/cms_admin/categories/new.html.haml +8 -0
- data/app/views/cms_admin/categories/show.html.haml +17 -0
- data/app/views/cms_admin/layouts/_details.html.haml +6 -0
- data/app/views/cms_admin/layouts/_form.html.haml +19 -0
- data/app/views/cms_admin/layouts/_toggle_link.html.haml +9 -0
- data/app/views/cms_admin/layouts/_tree_branch.html.haml +39 -0
- data/app/views/cms_admin/layouts/children.js.rjs +10 -0
- data/app/views/cms_admin/layouts/edit.html.haml +10 -0
- data/app/views/cms_admin/layouts/index.html.haml +7 -0
- data/app/views/cms_admin/layouts/new.html.haml +8 -0
- data/app/views/cms_admin/pages/_details.html.haml +25 -0
- data/app/views/cms_admin/pages/_form.html.haml +45 -0
- data/app/views/cms_admin/pages/_form_blocks.html.haml +48 -0
- data/app/views/cms_admin/pages/_toggle_link.html.haml +10 -0
- data/app/views/cms_admin/pages/_tree_branch.html.haml +41 -0
- data/app/views/cms_admin/pages/children.js.rjs +10 -0
- data/app/views/cms_admin/pages/edit.html.haml +11 -0
- data/app/views/cms_admin/pages/form_blocks.js.rjs +1 -0
- data/app/views/cms_admin/pages/index.html.haml +6 -0
- data/app/views/cms_admin/pages/new.html.haml +9 -0
- data/app/views/cms_admin/sections/show.html.haml +23 -0
- data/app/views/cms_admin/snippets/_form.html.haml +10 -0
- data/app/views/cms_admin/snippets/edit.html.haml +10 -0
- data/app/views/cms_admin/snippets/index.html.haml +26 -0
- data/app/views/cms_admin/snippets/new.html.haml +8 -0
- data/app/views/cms_content/show.xml.rxml +27 -0
- data/app/views/cms_content/sitemap.xml.rxml +16 -0
- data/app/views/layouts/cms_admin.html.haml +44 -0
- data/comfortable_mexican_sofa.gemspec +254 -0
- data/config/cms_routes.rb +25 -0
- data/generators/cms/cms_generator.rb +55 -0
- data/generators/cms/templates/README +32 -0
- data/generators/cms/templates/images/arrow_bottom.gif +0 -0
- data/generators/cms/templates/images/arrow_right.gif +0 -0
- data/generators/cms/templates/images/icon_attachment.gif +0 -0
- data/generators/cms/templates/images/icon_category.gif +0 -0
- data/generators/cms/templates/images/icon_draft.gif +0 -0
- data/generators/cms/templates/images/icon_layout.gif +0 -0
- data/generators/cms/templates/images/icon_move.gif +0 -0
- data/generators/cms/templates/images/icon_regular.gif +0 -0
- data/generators/cms/templates/images/icon_snippet.gif +0 -0
- data/generators/cms/templates/images/logo.png +0 -0
- data/generators/cms/templates/initializers/cms.rb +14 -0
- data/generators/cms/templates/initializers/paperclip.rb +14 -0
- data/generators/cms/templates/javascripts/codemirror_init.js +16 -0
- data/generators/cms/templates/javascripts/mce_init.js +17 -0
- data/generators/cms/templates/javascripts/utilities.js +27 -0
- data/generators/cms/templates/migrations/create_cms.rb +113 -0
- data/generators/cms/templates/stylesheets/cms_master.sass +414 -0
- data/init.rb +1 -0
- data/lib/comfortable_mexican_sofa.rb +46 -0
- data/lib/comfortable_mexican_sofa/acts_as_categorized.rb +87 -0
- data/lib/comfortable_mexican_sofa/acts_as_published.rb +60 -0
- data/lib/comfortable_mexican_sofa/cms_acts_as_tree.rb +108 -0
- data/lib/comfortable_mexican_sofa/cms_rails_extensions.rb +12 -0
- data/lib/comfortable_mexican_sofa/cms_tag.rb +109 -0
- data/lib/comfortable_mexican_sofa/cms_tags/attachment.rb +3 -0
- data/lib/comfortable_mexican_sofa/cms_tags/block.rb +117 -0
- data/lib/comfortable_mexican_sofa/cms_tags/helper.rb +3 -0
- data/lib/comfortable_mexican_sofa/cms_tags/page_block.rb +119 -0
- data/lib/comfortable_mexican_sofa/cms_tags/partial.rb +19 -0
- data/lib/comfortable_mexican_sofa/cms_tags/snippet.rb +19 -0
- data/rails/init.rb +1 -0
- data/test/fixtures/cms_attachment_categorizations.yml +7 -0
- data/test/fixtures/cms_attachments.yml +6 -0
- data/test/fixtures/cms_blocks.yml +38 -0
- data/test/fixtures/cms_categories.yml +19 -0
- data/test/fixtures/cms_layouts.yml +41 -0
- data/test/fixtures/cms_page_categorizations.yml +15 -0
- data/test/fixtures/cms_pages.yml +38 -0
- data/test/fixtures/cms_snippets.yml +7 -0
- data/test/fixtures/files/upload_file.txt +1 -0
- data/test/functional/cms_admin/attachments_controller_test.rb +63 -0
- data/test/functional/cms_admin/categories_controller_test.rb +86 -0
- data/test/functional/cms_admin/layouts_controller_test.rb +77 -0
- data/test/functional/cms_admin/pages_controller_test.rb +153 -0
- data/test/functional/cms_admin/sections_controller_test.rb +9 -0
- data/test/functional/cms_admin/snippets_controller_test.rb +63 -0
- data/test/functional/cms_content_controller_test.rb +52 -0
- data/test/models/cms_attachment_test.rb +16 -0
- data/test/models/cms_block_test.rb +11 -0
- data/test/models/cms_categorization_test.rb +39 -0
- data/test/models/cms_category_test.rb +71 -0
- data/test/models/cms_layout_test.rb +44 -0
- data/test/models/cms_page_test.rb +55 -0
- data/test/models/cms_snippet_test.rb +16 -0
- data/test/models/cms_tag_test.rb +70 -0
- data/test/rails_root/README +243 -0
- data/test/rails_root/Rakefile +10 -0
- data/test/rails_root/app/controllers/application_controller.rb +10 -0
- data/test/rails_root/app/helpers/application_helper.rb +3 -0
- data/test/rails_root/app/views/cms/under-development.html.haml +1 -0
- data/test/rails_root/app/views/complex_page/_example.html.erb +1 -0
- data/test/rails_root/config/boot.rb +110 -0
- data/test/rails_root/config/database.yml +22 -0
- data/test/rails_root/config/environment.rb +48 -0
- data/test/rails_root/config/environments/development.rb +17 -0
- data/test/rails_root/config/environments/production.rb +28 -0
- data/test/rails_root/config/environments/test.rb +28 -0
- data/test/rails_root/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_root/config/initializers/inflections.rb +10 -0
- data/test/rails_root/config/initializers/mime_types.rb +5 -0
- data/test/rails_root/config/initializers/new_rails_defaults.rb +19 -0
- data/test/rails_root/config/initializers/session_store.rb +15 -0
- data/test/rails_root/config/locales/en.yml +5 -0
- data/test/rails_root/config/routes.rb +43 -0
- data/test/rails_root/doc/README_FOR_APP +2 -0
- data/test/rails_root/public/404.html +30 -0
- data/test/rails_root/public/422.html +30 -0
- data/test/rails_root/public/500.html +30 -0
- data/test/rails_root/public/favicon.ico +0 -0
- data/test/rails_root/public/images/rails.png +0 -0
- data/test/rails_root/public/index.html +275 -0
- data/test/rails_root/public/javascripts/application.js +2 -0
- data/test/rails_root/public/javascripts/controls.js +963 -0
- data/test/rails_root/public/javascripts/dragdrop.js +973 -0
- data/test/rails_root/public/javascripts/effects.js +1128 -0
- data/test/rails_root/public/javascripts/prototype.js +4320 -0
- data/test/rails_root/public/robots.txt +5 -0
- data/test/rails_root/public/stylesheets/sass/cms_master.sass +414 -0
- data/test/rails_root/script/about +4 -0
- data/test/rails_root/script/console +3 -0
- data/test/rails_root/script/dbconsole +3 -0
- data/test/rails_root/script/destroy +3 -0
- data/test/rails_root/script/generate +3 -0
- data/test/rails_root/script/performance/benchmarker +3 -0
- data/test/rails_root/script/performance/profiler +3 -0
- data/test/rails_root/script/plugin +3 -0
- data/test/rails_root/script/runner +3 -0
- data/test/rails_root/script/server +3 -0
- data/test/test_helper.rb +17 -0
- metadata +303 -0
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'comfortable_mexican_sofa'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'comfortable_mexican_sofa/cms_rails_extensions'
|
2
|
+
require 'comfortable_mexican_sofa/cms_acts_as_tree'
|
3
|
+
require 'comfortable_mexican_sofa/acts_as_published'
|
4
|
+
require 'comfortable_mexican_sofa/acts_as_categorized'
|
5
|
+
|
6
|
+
require 'comfortable_mexican_sofa/cms_tag'
|
7
|
+
require 'comfortable_mexican_sofa/cms_tags/block'
|
8
|
+
require 'comfortable_mexican_sofa/cms_tags/page_block'
|
9
|
+
require 'comfortable_mexican_sofa/cms_tags/snippet'
|
10
|
+
require 'comfortable_mexican_sofa/cms_tags/partial'
|
11
|
+
# require 'comfortable_mexican_sofa/cms_tags/helper'
|
12
|
+
# require 'comfortable_mexican_sofa/cms_tags/attachment'
|
13
|
+
|
14
|
+
# Helper inclusion
|
15
|
+
ActionView::Base.send(:include, CmsHelper)
|
16
|
+
|
17
|
+
module ComfortableMexicanSofa
|
18
|
+
class Config
|
19
|
+
def self.cattr_accessor_with_default(name, value = nil)
|
20
|
+
cattr_accessor name
|
21
|
+
self.send("#{name}=", value) if value
|
22
|
+
end
|
23
|
+
|
24
|
+
cattr_accessor_with_default :http_auth_enabled, true
|
25
|
+
cattr_accessor_with_default :http_auth_username, 'username'
|
26
|
+
cattr_accessor_with_default :http_auth_password, 'password'
|
27
|
+
cattr_accessor_with_default :cms_title
|
28
|
+
cattr_accessor_with_default :additional_cms_tabs, {}
|
29
|
+
cattr_accessor_with_default :paperclip_options, {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.config(&block)
|
33
|
+
yield ComfortableMexicanSofa::Config
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# loading engine routes
|
38
|
+
class ActionController::Routing::RouteSet
|
39
|
+
def load_routes_with_cms!
|
40
|
+
cms_routes = File.join(File.dirname(__FILE__), *%w[.. config cms_routes.rb])
|
41
|
+
add_configuration_file(cms_routes) unless configuration_files.include? cms_routes
|
42
|
+
load_routes_without_cms!
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method_chain :load_routes!, :cms
|
46
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module ActsAsCategorized
|
2
|
+
module StubMethods
|
3
|
+
|
4
|
+
def acts_as_categorized
|
5
|
+
|
6
|
+
__categorized = self.to_s.underscore.to_sym
|
7
|
+
__categorizations = "#{__categorized}_categorizations".to_sym
|
8
|
+
|
9
|
+
# -- Attributes -------------------------------------------------------
|
10
|
+
attr_accessor :attr_category_ids # hash that comes from the form
|
11
|
+
|
12
|
+
# -- Relationships ----------------------------------------------------
|
13
|
+
has_many __categorizations,
|
14
|
+
:dependent => :destroy
|
15
|
+
has_many :cms_categories,
|
16
|
+
:through => __categorizations
|
17
|
+
|
18
|
+
# -- Callbacks --------------------------------------------------------
|
19
|
+
after_save :save_categorizations
|
20
|
+
|
21
|
+
# -- Named Scopes -----------------------------------------------------
|
22
|
+
|
23
|
+
named_scope :in_category, lambda { |category| {
|
24
|
+
:joins => __categorizations,
|
25
|
+
:conditions => { __categorizations => {:cms_category_id => (category.is_a?(CmsCategory) ? category.id : category) } }
|
26
|
+
}}
|
27
|
+
|
28
|
+
# -- Instance Methods -------------------------------------------------
|
29
|
+
define_method :save_categorizations do
|
30
|
+
return if attr_category_ids.blank?
|
31
|
+
|
32
|
+
category_ids_to_remove = attr_category_ids.select{ |k, v| v.to_i == 0}.collect{|k, v| k }
|
33
|
+
category_ids_to_create = attr_category_ids.select{ |k, v| v.to_i == 1}.collect{|k, v| k }
|
34
|
+
|
35
|
+
# removing unchecked categories
|
36
|
+
send(__categorizations).all(:conditions => { :cms_category_id => category_ids_to_remove}).collect(&:destroy)
|
37
|
+
|
38
|
+
# creating categorizations
|
39
|
+
category_ids_to_create.each do |category_id|
|
40
|
+
send(__categorizations).create(:cms_category_id => category_id)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def acts_as_categorization
|
46
|
+
|
47
|
+
__categorized = self.to_s.underscore.gsub('_categorization', '').to_sym
|
48
|
+
__categorized_id = "#{__categorized}_id".to_sym
|
49
|
+
__categorizations = "#{__categorized}_categorizations".to_sym
|
50
|
+
|
51
|
+
# -- Relationships --------------------------------------------------------
|
52
|
+
belongs_to __categorized.to_sym
|
53
|
+
belongs_to :cms_category
|
54
|
+
|
55
|
+
# -- Validations ----------------------------------------------------------
|
56
|
+
validates_presence_of __categorized_id,
|
57
|
+
:cms_category_id
|
58
|
+
|
59
|
+
validates_uniqueness_of __categorized_id, :scope => :cms_category_id
|
60
|
+
|
61
|
+
# -- AR Callbacks ---------------------------------------------------------
|
62
|
+
after_save :create_parent_categorization
|
63
|
+
after_destroy :destroy_children_categorizations
|
64
|
+
|
65
|
+
# -- Instance Methods -----------------------------------------------------
|
66
|
+
define_method :create_parent_categorization do
|
67
|
+
return unless cms_category.parent
|
68
|
+
|
69
|
+
params = {
|
70
|
+
:cms_category_id => cms_category.parent_id,
|
71
|
+
__categorized_id => send(__categorized).id
|
72
|
+
}
|
73
|
+
self.class.create!(params) unless self.class.exists?(params)
|
74
|
+
end
|
75
|
+
|
76
|
+
define_method :destroy_children_categorizations do
|
77
|
+
return if cms_category.children.blank?
|
78
|
+
|
79
|
+
cms_category.children.each do |c|
|
80
|
+
send(__categorized).send(__categorizations).first(:conditions => {"cms_category_id" => c.id }).try(:destroy)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
ActiveRecord::Base.extend(ActsAsCategorized::StubMethods)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module ActsAsPublished
|
2
|
+
module StubMethods
|
3
|
+
def acts_as_published
|
4
|
+
|
5
|
+
extend ClassMethods
|
6
|
+
include InstanceMethods
|
7
|
+
|
8
|
+
named_scope :published, lambda { |*at_time| {
|
9
|
+
:conditions => published_find_conditions(*at_time)
|
10
|
+
}}
|
11
|
+
named_scope :unpublished, lambda { |*at_time| {
|
12
|
+
:conditions => unpublished_find_conditions(*at_time)
|
13
|
+
}}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def published_find_conditions(at_time = Time.now.utc)
|
19
|
+
[ "(#{self.table_name}.published_at IS NOT NULL AND #{self.table_name}.published_at <= ?)
|
20
|
+
AND
|
21
|
+
(#{self.table_name}.unpublished_at IS NULL OR #{self.table_name}.unpublished_at > ?)",
|
22
|
+
at_time, at_time
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
def unpublished_find_conditions(at_time = Time.now.utc)
|
27
|
+
[ "(#{self.table_name}.published_at IS NULL OR #{self.table_name}.published_at > ?)
|
28
|
+
AND
|
29
|
+
(#{self.table_name}.unpublished_at IS NULL OR #{self.table_name}.unpublished_at <= ?)",
|
30
|
+
at_time, at_time
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module InstanceMethods
|
36
|
+
|
37
|
+
def is_published?(at_time = Time.now.utc)
|
38
|
+
published_at && published_at <= at_time && !(unpublished_at && unpublished_at <= at_time)
|
39
|
+
end
|
40
|
+
|
41
|
+
def published_status
|
42
|
+
is_published? ? "published" : "unpublished"
|
43
|
+
end
|
44
|
+
|
45
|
+
def publish!(at_time = Time.now.utc)
|
46
|
+
update_attributes(
|
47
|
+
:published_at => at_time,
|
48
|
+
:unpublished_at => nil
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def unpublish!(at_time = Time.now.utc)
|
53
|
+
update_attributes(
|
54
|
+
:unpublished_at => at_time
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
ActiveRecord::Base.extend(ActsAsPublished::StubMethods)
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Acts
|
3
|
+
module Tree
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
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>)
|
36
|
+
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
|
+
def acts_as_tree(options = {})
|
43
|
+
configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
|
44
|
+
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
|
+
|
49
|
+
class_eval <<-EOV
|
50
|
+
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
|
+
|
56
|
+
def self.root
|
57
|
+
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
58
|
+
end
|
59
|
+
EOV
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module InstanceMethods
|
64
|
+
# Returns list of ancestors, starting from parent until root.
|
65
|
+
#
|
66
|
+
# subchild1.ancestors # => [child1, root]
|
67
|
+
def ancestors
|
68
|
+
node, nodes = self, []
|
69
|
+
nodes << node = node.parent while node.parent
|
70
|
+
nodes
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns all children and children of children
|
74
|
+
def descendants
|
75
|
+
nodes = []
|
76
|
+
self.children.each do |c|
|
77
|
+
nodes << c
|
78
|
+
nodes << c.descendants
|
79
|
+
end
|
80
|
+
nodes.flatten
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns the root node of the tree.
|
84
|
+
def root
|
85
|
+
node = self
|
86
|
+
node = node.parent while node.parent
|
87
|
+
node
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns all siblings of the current node.
|
91
|
+
#
|
92
|
+
# subchild1.siblings # => [subchild2]
|
93
|
+
def siblings
|
94
|
+
self_and_siblings - [self]
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns all siblings and a reference to the current node.
|
98
|
+
#
|
99
|
+
# subchild1.self_and_siblings # => [subchild1, subchild2]
|
100
|
+
def self_and_siblings
|
101
|
+
parent ? parent.children : self.class.roots
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
ActiveRecord::Base.send :include, ActiveRecord::Acts::Tree
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Converts string to something suitable to be used as an element id
|
4
|
+
def idify
|
5
|
+
self.strip.gsub(/\W/, '_').gsub(/\s|^_*|_*$/, '').squeeze('_')
|
6
|
+
end
|
7
|
+
|
8
|
+
# Converts a string to something usable as a url slug
|
9
|
+
def slugify
|
10
|
+
self.downcase.gsub(/\W|_/, ' ').strip.squeeze(' ').gsub(/\s/, '-')
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module CmsTag
|
2
|
+
|
3
|
+
class TagError < StandardError; end
|
4
|
+
|
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
|
10
|
+
|
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)}
|
18
|
+
end
|
19
|
+
tags.flatten
|
20
|
+
end
|
21
|
+
|
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
|
59
|
+
|
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
|
84
|
+
end
|
85
|
+
|
86
|
+
def assign_accessors
|
87
|
+
# ... FIX: looks retarded
|
88
|
+
end
|
89
|
+
|
90
|
+
def form_label
|
91
|
+
"Label Undefined!"
|
92
|
+
end
|
93
|
+
|
94
|
+
def form_input
|
95
|
+
"Form Field Undefined!"
|
96
|
+
end
|
97
|
+
|
98
|
+
def content
|
99
|
+
'Undefined Tag'
|
100
|
+
end
|
101
|
+
|
102
|
+
# when cms_page renders its content this is what tag outputs on the page
|
103
|
+
def render
|
104
|
+
content
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
class CmsTag::Block < CmsTag::Tag
|
2
|
+
|
3
|
+
FORMAT = {
|
4
|
+
:text => {
|
5
|
+
:db_column => :content_text,
|
6
|
+
:description => '',
|
7
|
+
:form_output => lambda { |tag|
|
8
|
+
tag.view.text_area_tag "cms_page[blocks][#{tag.label}][content_text]", tag.content,
|
9
|
+
:rows => 20
|
10
|
+
}
|
11
|
+
},
|
12
|
+
:string => {
|
13
|
+
:db_column => :content_string,
|
14
|
+
:description => '',
|
15
|
+
:form_output => lambda { |tag|
|
16
|
+
tag.view.text_field_tag "cms_page[blocks][#{tag.label}][content_string]", tag.content
|
17
|
+
}
|
18
|
+
},
|
19
|
+
:rich_text => {
|
20
|
+
:db_column => :content_text,
|
21
|
+
:description => '',
|
22
|
+
:form_output => lambda { |tag|
|
23
|
+
tag.view.text_area_tag "cms_page[blocks][#{tag.label}][content_text]", tag.content,
|
24
|
+
:rows => 20,
|
25
|
+
:class => 'mceEditor'
|
26
|
+
}
|
27
|
+
},
|
28
|
+
:code => {
|
29
|
+
:db_column => :content_text,
|
30
|
+
:description => '',
|
31
|
+
:form_output => lambda { |tag|
|
32
|
+
tag.view.content_tag :div, :class => 'codemirror' do
|
33
|
+
tag.view.text_area_tag "cms_page[blocks][#{tag.label}][content_text]", tag.content,
|
34
|
+
:rows => 20,
|
35
|
+
:class => 'codeTextArea'
|
36
|
+
end
|
37
|
+
}
|
38
|
+
},
|
39
|
+
:integer => {
|
40
|
+
:db_column => :content_integer,
|
41
|
+
:description => '',
|
42
|
+
:form_output => lambda { |tag|
|
43
|
+
tag.view.text_field_tag "cms_page[blocks][#{tag.label}][content_integer]", tag.content
|
44
|
+
}
|
45
|
+
},
|
46
|
+
:boolean => {
|
47
|
+
:db_column => :content_boolean,
|
48
|
+
:description => '',
|
49
|
+
:form_output => lambda { |tag|
|
50
|
+
tag.view.check_box_tag "cms_page[blocks][#{tag.label}][content_boolean]", tag.content
|
51
|
+
}
|
52
|
+
},
|
53
|
+
:date => {
|
54
|
+
:db_column => :content_datetime,
|
55
|
+
:description => '',
|
56
|
+
:form_output => lambda { |tag|
|
57
|
+
tag.view.fields_for "cms_page[blocks][#{tag.label}]" do |field|
|
58
|
+
field.date_select :content_datetime, :default => tag.content
|
59
|
+
end
|
60
|
+
}
|
61
|
+
},
|
62
|
+
:time => {
|
63
|
+
:db_column => :content_datetime,
|
64
|
+
:description => '',
|
65
|
+
:form_output => lambda { |tag|
|
66
|
+
tag.view.fields_for "cms_page[blocks][#{tag.label}]" do |field|
|
67
|
+
field.datetime_select :content_datetime, :default => tag.content
|
68
|
+
end
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
attr_accessor :format
|
74
|
+
|
75
|
+
def self.regex
|
76
|
+
/\{\{\s*?(cms_block:.*?)\s*?\}\}/
|
77
|
+
end
|
78
|
+
|
79
|
+
def regex
|
80
|
+
/\{\{\s*?cms_block:#{Regexp.escape(label)}.*?\s*?\}\}/
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.render_priority
|
84
|
+
1
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.has_form?
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
def assign_accessors
|
92
|
+
tokens = self.tag_signature.split(':')
|
93
|
+
self.label = tokens[1]
|
94
|
+
self.format = tokens[2]
|
95
|
+
end
|
96
|
+
|
97
|
+
def form_label
|
98
|
+
view.label_tag label.titleize
|
99
|
+
end
|
100
|
+
|
101
|
+
def form_input
|
102
|
+
if FORMAT.has_key? self.format.to_sym
|
103
|
+
FORMAT[self.format.to_sym][:form_output].call(self)
|
104
|
+
else
|
105
|
+
'Unknown tag format'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def content
|
110
|
+
page && page.cms_block_content(self.label, FORMAT[self.format.to_sym][:db_column])
|
111
|
+
end
|
112
|
+
|
113
|
+
def render
|
114
|
+
''
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|