activeadmin-cms 0.0.1
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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +73 -0
- data/Rakefile +27 -0
- data/lib/active_admin/cms.rb +54 -0
- data/lib/active_admin/cms/content.rb +71 -0
- data/lib/active_admin/cms/content_type.rb +73 -0
- data/lib/active_admin/cms/content_types/image.rb +17 -0
- data/lib/active_admin/cms/content_types/large_image.rb +21 -0
- data/lib/active_admin/cms/content_types/string.rb +10 -0
- data/lib/active_admin/cms/content_types/text.rb +13 -0
- data/lib/active_admin/cms/content_types/text_and_image.rb +12 -0
- data/lib/active_admin/cms/controller_extensions.rb +27 -0
- data/lib/active_admin/cms/helpers/cms_helper.rb +13 -0
- data/lib/active_admin/cms/page.rb +77 -0
- data/lib/active_admin/cms/recipe.rb +45 -0
- data/lib/active_admin/cms/recipe/ingredient.rb +56 -0
- data/lib/active_admin/cms/recipe/section.rb +36 -0
- data/lib/active_admin/cms/recipes/section_helper.rb +99 -0
- data/lib/active_admin/cms/uploaders/content_file_uploader.rb +56 -0
- data/lib/active_admin/cms/uploaders/content_image_uploader.rb +62 -0
- data/lib/active_admin/cms/uploaders/large_image_uploader.rb +66 -0
- data/lib/active_admin/cms/utility/class_level_inheritable_attributes.rb +31 -0
- data/lib/activeadmin-cms.rb +6 -0
- data/lib/activeadmin-cms/version.rb +3 -0
- data/lib/activeadmin/cms.rb +1 -0
- data/lib/generators/active_admin/cms/install/install_generator.rb +39 -0
- data/lib/generators/active_admin/cms/install/templates/initializer.rb +7 -0
- data/lib/generators/active_admin/cms/install/templates/migrations/1_install_aacms.rb +29 -0
- data/lib/generators/active_admin/cms/page/page_generator.rb +41 -0
- data/lib/generators/active_admin/cms/page/templates/admin/pages.rb.erb +39 -0
- data/lib/generators/active_admin/cms/page/templates/migrations/1_create_pages.rb +25 -0
- data/lib/generators/active_admin/cms/page/templates/page.rb.erb +3 -0
- data/lib/generators/active_admin/cms/page/templates/views/admin/cms/page.html.haml +0 -0
- data/lib/generators/active_admin/cms/page/templates/views/admin/cms/pages/_form.html.haml +20 -0
- data/lib/generators/active_admin/cms/page/templates/views/admin/cms/pages/_ingredient.html.haml +7 -0
- data/lib/generators/active_admin/cms/page/templates/views/admin/cms/pages/_section.html.haml +6 -0
- data/lib/generators/active_admin/cms/page/templates/views/admin/cms/pages/_show.html.haml +10 -0
- data/lib/generators/active_admin/cms/recipe/recipe_generator.rb +42 -0
- data/lib/generators/active_admin/cms/recipe/templates/recipe.rb.erb +20 -0
- data/lib/tasks/activeadmin-cms_tasks.rake +20 -0
- metadata +432 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Cms
|
3
|
+
class Page < ActiveRecord::Base
|
4
|
+
validates :title, :presence => true
|
5
|
+
validates :recipe_id, :presence => true
|
6
|
+
|
7
|
+
belongs_to :recipe
|
8
|
+
|
9
|
+
has_many :content
|
10
|
+
accepts_nested_attributes_for :content
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def for_url(url)
|
15
|
+
where(:url => url).first if where(:url => url).any?
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def content_for content_key
|
21
|
+
ret = nil
|
22
|
+
if recipe
|
23
|
+
if recipe.contains_content_key?(content_key)
|
24
|
+
ret = Cms::Content.where(:page_id => id, :key => content_key)
|
25
|
+
if ret.length == 0
|
26
|
+
ret = Cms::Content.new(:page => self, :key => content_key)
|
27
|
+
ret.content_type = recipe.ingredient_for(content_key).content_type
|
28
|
+
else
|
29
|
+
ret = ret[0]
|
30
|
+
end
|
31
|
+
#else
|
32
|
+
#raise Cms::Exceptions::InvalidContentKey
|
33
|
+
end
|
34
|
+
end
|
35
|
+
return ret
|
36
|
+
end
|
37
|
+
|
38
|
+
def meta_data
|
39
|
+
data = {}
|
40
|
+
if meta_title and !meta_title.blank?
|
41
|
+
data[:title] = meta_title
|
42
|
+
elsif title and !title.blank?
|
43
|
+
data[:title] = "#{Cms::SITE_TITLE} | #{title}"
|
44
|
+
else
|
45
|
+
data[:title] = Cms::SITE_TITLE
|
46
|
+
end
|
47
|
+
data[:description] = meta_description || Cms::DEFAULT_META_DESCRIPTION
|
48
|
+
data[:keywords] = meta_keywords || Cms::DEFAULT_META_KEYWORDS
|
49
|
+
data
|
50
|
+
end
|
51
|
+
|
52
|
+
# Takes a content_key => text hash and sets the text value for each of the content records
|
53
|
+
def set_value content_hash
|
54
|
+
if content_hash
|
55
|
+
content_hash.each do |key, value|
|
56
|
+
c = content_for(key)
|
57
|
+
#debugger
|
58
|
+
if c
|
59
|
+
c.set_content value
|
60
|
+
c.save
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_content content_key, content
|
67
|
+
if content.kind_of? Cms::Content
|
68
|
+
content.key = content_key
|
69
|
+
content.page = self
|
70
|
+
content.content_type = recipe.ingredient_for(content_key).content_type
|
71
|
+
content.save
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Cms
|
3
|
+
class Recipe < ActiveRecord::Base
|
4
|
+
|
5
|
+
include Cms::Recipes::SectionHelper::SectionContainer
|
6
|
+
|
7
|
+
has_many :pages
|
8
|
+
|
9
|
+
def self.define(&definition_block)
|
10
|
+
after_initialize do
|
11
|
+
define &definition_block
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def define(&block)
|
16
|
+
self.instance_eval &block
|
17
|
+
end
|
18
|
+
|
19
|
+
def admin_fieldset_title
|
20
|
+
'Content'
|
21
|
+
end
|
22
|
+
|
23
|
+
def contains_content_key? content_key
|
24
|
+
!!ingredient_for(content_key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ingredient_for content_key
|
28
|
+
section_keys = content_key.split ':'
|
29
|
+
current_section = self
|
30
|
+
section_keys.each do |section_id|
|
31
|
+
#debugger
|
32
|
+
if section_id == section_keys.last
|
33
|
+
return current_section.ingredients[section_id.to_sym]
|
34
|
+
else
|
35
|
+
if current_section.sections[section_id.to_sym]
|
36
|
+
current_section = current_section.sections[section_id.to_sym]
|
37
|
+
else
|
38
|
+
return nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Cms
|
3
|
+
class Recipe
|
4
|
+
class Ingredient
|
5
|
+
|
6
|
+
attr_accessor :id, :content_type, :section,
|
7
|
+
:title, :description, :options
|
8
|
+
|
9
|
+
def initialize(id, content_type, opts = {})
|
10
|
+
@id = id
|
11
|
+
@content_type = content_type
|
12
|
+
@options = opts
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_fields_to(formtastic_form)
|
16
|
+
page = formtastic_form.object
|
17
|
+
content = page.content_for content_key
|
18
|
+
#debugger
|
19
|
+
fields = formtastic_form.fields_for(content) do |i_form|
|
20
|
+
i_form.inputs do
|
21
|
+
i_form.input :text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
#debugger
|
25
|
+
fields
|
26
|
+
end
|
27
|
+
|
28
|
+
# returns the key to use for storing content
|
29
|
+
def content_key
|
30
|
+
return "#{section.section_key}:#{id}" if section
|
31
|
+
id
|
32
|
+
end
|
33
|
+
|
34
|
+
def input_settings opts = {}
|
35
|
+
opts[:prefix]
|
36
|
+
|
37
|
+
input_options = {:label => title, :input_html => {:name => "content[#{content_key}]", :id => content_key.to_s.gsub(':', '__')}}
|
38
|
+
|
39
|
+
input_options[:hint] ||= description if description
|
40
|
+
input_options[:hint] ||= content_type.description if !description and !content_type.description.blank?
|
41
|
+
input_options.merge! @options if @options
|
42
|
+
#debugger
|
43
|
+
[
|
44
|
+
content_type.input_field,
|
45
|
+
input_options.merge(content_type.input_opts)
|
46
|
+
]
|
47
|
+
end
|
48
|
+
|
49
|
+
def title
|
50
|
+
@title ||= id.to_s.humanize
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Cms
|
3
|
+
class Recipe
|
4
|
+
class Section
|
5
|
+
|
6
|
+
include ActiveAdmin::Cms::Recipes::SectionHelper::SectionContainer
|
7
|
+
|
8
|
+
attr_accessor :id, :options
|
9
|
+
|
10
|
+
@content = {}
|
11
|
+
|
12
|
+
def initialize(id, opts={}, &block)
|
13
|
+
|
14
|
+
#debugger
|
15
|
+
|
16
|
+
opts[:partial] ||= 'cms/recipes/section'
|
17
|
+
opts[:class] ||= ''
|
18
|
+
|
19
|
+
@id = id
|
20
|
+
@options = opts
|
21
|
+
|
22
|
+
if block
|
23
|
+
self.instance_eval &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def section(id, opts={}, &block)
|
28
|
+
#super(id, opts)
|
29
|
+
super
|
30
|
+
sections[id].parent = self
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'active_admin/cms/recipe/ingredient'
|
2
|
+
require 'active_admin/cms/recipe/section'
|
3
|
+
|
4
|
+
module ActiveAdmin
|
5
|
+
module Cms
|
6
|
+
module Recipes
|
7
|
+
module SectionHelper
|
8
|
+
module SectionContainer
|
9
|
+
|
10
|
+
class Ingredient < ActiveAdmin::Cms::Recipe::Ingredient; end
|
11
|
+
class Section < ActiveAdmin::Cms::Recipe::Section; end
|
12
|
+
|
13
|
+
attr_accessor :parent
|
14
|
+
|
15
|
+
def method_missing(method, *args, &block)
|
16
|
+
|
17
|
+
begin
|
18
|
+
klass = "ActiveAdmin::Cms::ContentTypes::#{method.to_s.camelcase}".constantize
|
19
|
+
rescue NameError
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
klass = "::ContentTypes::#{method.to_s.camelcase}".constantize
|
24
|
+
rescue NameError
|
25
|
+
end
|
26
|
+
|
27
|
+
if klass && klass.new.kind_of?(ActiveAdmin::Cms::ContentType)
|
28
|
+
args[2] = args[1]
|
29
|
+
args[1] = klass
|
30
|
+
ingredient *args
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Adds formatastic fields to the specified form
|
37
|
+
def add_fields_to(formtastic_form)
|
38
|
+
fields = {}
|
39
|
+
formtastic_form.inputs admin_fieldset_title do
|
40
|
+
ingredients.each do |i_id, i|
|
41
|
+
page = formtastic_form.object
|
42
|
+
content = page.content_for i.content_key
|
43
|
+
#debugger
|
44
|
+
fields[i.content_key] = formtastic_form.fields_for(content) do |i_form|
|
45
|
+
i_form.input :text
|
46
|
+
end
|
47
|
+
#i.add_fields_to(formtastic_form) if i.kind_of? ActiveAdmin::Cms::Recipe::Ingredient
|
48
|
+
end
|
49
|
+
end
|
50
|
+
sections.each do |s_id, s|
|
51
|
+
fields[s_id] = s.add_fields_to(formtastic_form) if s.kind_of? ActiveAdmin::Cms::Recipe::Section
|
52
|
+
end
|
53
|
+
|
54
|
+
#debugger
|
55
|
+
|
56
|
+
formtastic_form.inputs
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def admin_fieldset_title
|
61
|
+
section_id.to_s.humanize
|
62
|
+
end
|
63
|
+
|
64
|
+
def ingredient(ingredient_id, type, opts={})
|
65
|
+
@ingredients ||= {}
|
66
|
+
@ingredients[ingredient_id] = Ingredient.new(ingredient_id, type, opts)
|
67
|
+
@ingredients[ingredient_id].section = self
|
68
|
+
@ingredients[ingredient_id]
|
69
|
+
end
|
70
|
+
|
71
|
+
def ingredients
|
72
|
+
@ingredients ||= {}
|
73
|
+
end
|
74
|
+
|
75
|
+
def section(section_id, opts={}, &block)
|
76
|
+
|
77
|
+
s = Section.new(section_id, opts, &block)
|
78
|
+
@sections ||= {}
|
79
|
+
@sections[section_id] = s
|
80
|
+
s
|
81
|
+
end
|
82
|
+
|
83
|
+
def sections
|
84
|
+
@sections ||= {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def section_id
|
88
|
+
self.id
|
89
|
+
end
|
90
|
+
|
91
|
+
def section_key
|
92
|
+
return "#{@parent.section_key}:#{section_id.to_s}" if @parent
|
93
|
+
section_id.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveAdmin
|
3
|
+
module Cms
|
4
|
+
module Uploaders
|
5
|
+
class ContentFileUploader < CarrierWave::Uploader::Base
|
6
|
+
|
7
|
+
include ::CarrierWave::Backgrounder::Delay
|
8
|
+
|
9
|
+
# Include RMagick or MiniMagick support:
|
10
|
+
# include CarrierWave::RMagick
|
11
|
+
include CarrierWave::MiniMagick
|
12
|
+
|
13
|
+
# Choose what kind of storage to use for this uploader:
|
14
|
+
# storage :file
|
15
|
+
storage :fog
|
16
|
+
|
17
|
+
# Override the directory where uploaded files will be stored.
|
18
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
19
|
+
def store_dir
|
20
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Provide a default URL as a default if there hasn't been a file uploaded:
|
24
|
+
# def default_url
|
25
|
+
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
|
26
|
+
# end
|
27
|
+
|
28
|
+
# Process files as they are uploaded:
|
29
|
+
# process :scale => [200, 300]
|
30
|
+
#
|
31
|
+
# def scale(width, height)
|
32
|
+
# # do something
|
33
|
+
# end
|
34
|
+
|
35
|
+
# Create different versions of your uploaded files:
|
36
|
+
# version :thumb do
|
37
|
+
# process :scale => [50, 50]
|
38
|
+
# end
|
39
|
+
|
40
|
+
# Add a white list of extensions which are allowed to be uploaded.
|
41
|
+
# For images you might use something like this:
|
42
|
+
# def extension_white_list
|
43
|
+
# %w(jpg jpeg gif png)
|
44
|
+
# end
|
45
|
+
|
46
|
+
# Override the filename of the uploaded files:
|
47
|
+
# Avoid using model.id or version_name here, see uploader/store.rb for details.
|
48
|
+
# def filename
|
49
|
+
# "something.jpg" if original_filename
|
50
|
+
# end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveAdmin
|
3
|
+
module Cms
|
4
|
+
module Uploaders
|
5
|
+
class ContentImageUploader < CarrierWave::Uploader::Base
|
6
|
+
|
7
|
+
include ::CarrierWave::Backgrounder::Delay
|
8
|
+
|
9
|
+
# Include RMagick or MiniMagick support:
|
10
|
+
# include CarrierWave::RMagick
|
11
|
+
include CarrierWave::MiniMagick
|
12
|
+
|
13
|
+
# Choose what kind of storage to use for this uploader:
|
14
|
+
# storage :file
|
15
|
+
storage :fog
|
16
|
+
|
17
|
+
# Override the directory where uploaded files will be stored.
|
18
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
19
|
+
def store_dir
|
20
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Provide a default URL as a default if there hasn't been a file uploaded:
|
24
|
+
# def default_url
|
25
|
+
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
|
26
|
+
# end
|
27
|
+
def default_url
|
28
|
+
'/shared/missing.png'
|
29
|
+
end
|
30
|
+
|
31
|
+
# Process files as they are uploaded:
|
32
|
+
# process :scale => [200, 300]
|
33
|
+
#
|
34
|
+
# def scale(width, height)
|
35
|
+
# # do something
|
36
|
+
# end
|
37
|
+
|
38
|
+
# Create different versions of your uploaded files:
|
39
|
+
version :small do
|
40
|
+
process :resize_to_fit => [155, nil]
|
41
|
+
end
|
42
|
+
|
43
|
+
version :thumb do
|
44
|
+
process :resize_to_fit => [55, nil]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add a white list of extensions which are allowed to be uploaded.
|
48
|
+
# For images you might use something like this:
|
49
|
+
def extension_white_list
|
50
|
+
%w(jpg jpeg gif png)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Override the filename of the uploaded files:
|
54
|
+
# Avoid using model.id or version_name here, see uploader/store.rb for details.
|
55
|
+
# def filename
|
56
|
+
# "something.jpg" if original_filename
|
57
|
+
# end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module ActiveAdmin
|
3
|
+
module Cms
|
4
|
+
module Uploaders
|
5
|
+
class LargeImageUploader < CarrierWave::Uploader::Base
|
6
|
+
|
7
|
+
include ::CarrierWave::Backgrounder::Delay
|
8
|
+
|
9
|
+
# Include RMagick or MiniMagick support:
|
10
|
+
# include CarrierWave::RMagick
|
11
|
+
include CarrierWave::MiniMagick
|
12
|
+
|
13
|
+
# Choose what kind of storage to use for this uploader:
|
14
|
+
# storage :file
|
15
|
+
storage :fog
|
16
|
+
|
17
|
+
# Override the directory where uploaded files will be stored.
|
18
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
19
|
+
def store_dir
|
20
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Provide a default URL as a default if there hasn't been a file uploaded:
|
24
|
+
# def default_url
|
25
|
+
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
|
26
|
+
# end
|
27
|
+
def default_url
|
28
|
+
'/shared/missing.png'
|
29
|
+
end
|
30
|
+
|
31
|
+
# Process files as they are uploaded:
|
32
|
+
# process :scale => [200, 300]
|
33
|
+
#
|
34
|
+
# def scale(width, height)
|
35
|
+
# # do something
|
36
|
+
# end
|
37
|
+
|
38
|
+
# Create different versions of your uploaded files:
|
39
|
+
version :small do
|
40
|
+
process :resize_to_fit => [155, nil]
|
41
|
+
end
|
42
|
+
|
43
|
+
version :thumb do
|
44
|
+
process :resize_to_fit => [55, nil]
|
45
|
+
end
|
46
|
+
|
47
|
+
version :large do
|
48
|
+
process :resize_to_fit => [500, nil]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Add a white list of extensions which are allowed to be uploaded.
|
52
|
+
# For images you might use something like this:
|
53
|
+
def extension_white_list
|
54
|
+
%w(jpg jpeg gif png)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Override the filename of the uploaded files:
|
58
|
+
# Avoid using model.id or version_name here, see uploader/store.rb for details.
|
59
|
+
# def filename
|
60
|
+
# "something.jpg" if original_filename
|
61
|
+
# end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|