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