cmor_cms 0.0.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +88 -0
- data/Rakefile +19 -0
- data/app/assets/javascripts/cmor/cms/application.js +1 -0
- data/app/assets/javascripts/cmor/cms/application/navigations.js.coffee +4 -0
- data/app/assets/javascripts/cmor_cms.js +1 -0
- data/app/assets/stylesheets/cmor/cms/application.css +3 -0
- data/app/assets/stylesheets/cmor/cms/application/keep.css +0 -0
- data/app/assets/stylesheets/cmor_cms.css +3 -0
- data/app/controllers/cmor/cms/page_controller.rb +54 -0
- data/app/importers/navigation.rb +27 -0
- data/app/importers/navigation_item.rb +61 -0
- data/app/importers/page.rb +38 -0
- data/app/models/cmor/cms/content_block.rb +14 -0
- data/app/models/cmor/cms/content_box.rb +12 -0
- data/app/models/cmor/cms/navigation.rb +18 -0
- data/app/models/cmor/cms/navigation_item.rb +86 -0
- data/app/models/cmor/cms/page.rb +29 -0
- data/app/models/cmor/cms/partial.rb +15 -0
- data/app/models/cmor/cms/template.rb +13 -0
- data/app/models/concerns/model/cmor/cms/navigation_item/properties_concern.rb +25 -0
- data/app/resolvers/cmor/cms/page_resolver.rb +61 -0
- data/app/resolvers/cmor/cms/partial_resolver.rb +29 -0
- data/app/resolvers/cmor/cms/template_resolver.rb +29 -0
- data/app/services/cmor/cms/add_homepages_service.rb +79 -0
- data/app/services/cmor/cms/create_navigation_service.rb +49 -0
- data/app/services/cmor/cms/import_partials_service.rb +126 -0
- data/app/template_handlers/action_view/template/handlers/textile.rb +26 -0
- data/app/view_helpers/cmor/cms/application_view_helper.rb +36 -0
- data/app/view_helpers/cmor/cms/navigation_view_helper.rb +87 -0
- data/app/view_helpers/cmor/cms/page_view_helper.rb +34 -0
- data/app/views/cmor/cms/_link_to_top.html.erb +5 -0
- data/app/views/cmor/cms/page/fallback.html.erb +2 -0
- data/app/views/cmor/cms/page/fallback.txt +1 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/mime_types.rb +1 -0
- data/config/initializers/simple_navigation.rb +1 -0
- data/config/initializers/textile_support.rb +3 -0
- data/config/locales/de.yml +140 -0
- data/config/locales/en.yml +140 -0
- data/config/navigation.rb +0 -0
- data/config/routes.rb +6 -0
- data/db/migrate/002_create_cmor_cms_pages.rb +17 -0
- data/db/migrate/003_create_cmor_cms_templates.rb +14 -0
- data/db/migrate/004_create_cmor_cms_partials.rb +15 -0
- data/db/migrate/005_create_cmor_cms_navigations.rb +13 -0
- data/db/migrate/006_create_cmor_cms_navigation_items.rb +29 -0
- data/db/migrate/007_create_cmor_cms_content_boxes.rb +9 -0
- data/db/migrate/008_create_cmor_cms_content_blocks.rb +15 -0
- data/lib/cmor/cms.rb +23 -0
- data/lib/cmor/cms/action_view/template_patch.rb +18 -0
- data/lib/cmor/cms/action_view/template_renderer_patch.rb +45 -0
- data/lib/cmor/cms/configuration.rb +35 -0
- data/lib/cmor/cms/controller_extensions/page_resolver.rb +12 -0
- data/lib/cmor/cms/controller_extensions/partial_resolver.rb +12 -0
- data/lib/cmor/cms/controller_extensions/template_resolver.rb +12 -0
- data/lib/cmor/cms/database_resolver.rb +99 -0
- data/lib/cmor/cms/database_template.rb +70 -0
- data/lib/cmor/cms/engine.rb +16 -0
- data/lib/cmor/cms/version.rb +7 -0
- data/lib/cmor_cms.rb +8 -0
- data/lib/generators/cmor/cms/install/install_generator.rb +34 -0
- data/lib/generators/cmor/cms/install/templates/initializer.rb +53 -0
- data/lib/generators/cmor/cms/install/templates/routes.source +4 -0
- data/lib/tasks/cmor_cms_tasks.rake +15 -0
- data/spec/factories/cmor/cms/content_block.rb +7 -0
- data/spec/factories/cmor/cms/content_box.rb +5 -0
- data/spec/factories/cmor/cms/navigation_items.rb +16 -0
- data/spec/factories/cmor/cms/navigations.rb +6 -0
- data/spec/factories/cmor/cms/pages.rb +8 -0
- data/spec/factories/cmor/cms/partials.rb +7 -0
- data/spec/factories/cmor/cms/templates.rb +7 -0
- metadata +465 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module Cmor::Cms
|
2
|
+
class Page < ActiveRecord::Base
|
3
|
+
# add shared behaviour for database backed templates
|
4
|
+
include DatabaseTemplate
|
5
|
+
|
6
|
+
# associations
|
7
|
+
has_many :navigation_items,
|
8
|
+
dependent: :nullify
|
9
|
+
has_many :content_blocks,
|
10
|
+
dependent: :destroy,
|
11
|
+
inverse_of: :page
|
12
|
+
|
13
|
+
accepts_nested_attributes_for :content_blocks, allow_destroy: true
|
14
|
+
|
15
|
+
# callbacks
|
16
|
+
after_save :touch_navigation_items
|
17
|
+
|
18
|
+
# validations
|
19
|
+
validates :title, presence: true
|
20
|
+
|
21
|
+
def home_page?
|
22
|
+
pathname == '/' && basename == 'home'
|
23
|
+
end
|
24
|
+
|
25
|
+
def touch_navigation_items
|
26
|
+
navigation_items.map(&:update_url_form_page!)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'cmor/cms/database_template'
|
2
|
+
|
3
|
+
class Cmor::Cms::Partial < ActiveRecord::Base
|
4
|
+
# add shared behaviour for database backed templates
|
5
|
+
include Cmor::Cms::DatabaseTemplate
|
6
|
+
|
7
|
+
# callbacks
|
8
|
+
before_validation :ensure_basename_starts_with_underscore, if: proc { |t| t.basename.present? }
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def ensure_basename_starts_with_underscore
|
13
|
+
basename.insert(0, '_') unless basename.start_with?('_')
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Cmor::Cms::Template < ActiveRecord::Base
|
2
|
+
# add shared behaviour for database backed templates
|
3
|
+
include Cmor::Cms::DatabaseTemplate
|
4
|
+
|
5
|
+
# callbacks
|
6
|
+
before_validation :ensure_basename_starts_without_underscore, if: proc { |t| t.basename.present? }
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def ensure_basename_starts_without_underscore
|
11
|
+
basename.slice!(0) if basename.start_with?('_')
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Model::Cmor::Cms::NavigationItem
|
4
|
+
module PropertiesConcern
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
serialize :properties, OpenStruct
|
9
|
+
delegate *Cmor::Cms::Configuration.navigation_item_properties, to: :li_attributes
|
10
|
+
delegate *Cmor::Cms::Configuration.navigation_item_properties.collect { |a| "#{a}=".to_sym }, to: :li_attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
def highlights_on
|
14
|
+
properties.highlights_on ||= nil
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate :highlights_on=, to: :properties
|
18
|
+
|
19
|
+
def li_attributes
|
20
|
+
properties.li_attributes ||= OpenStruct.new
|
21
|
+
end
|
22
|
+
|
23
|
+
delegate :li_attributes=, to: :properties
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'cmor/cms/database_resolver'
|
2
|
+
|
3
|
+
module Cmor
|
4
|
+
module Cms
|
5
|
+
class PageResolver < ::ActionView::Resolver
|
6
|
+
require 'singleton'
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
# add shared behaviour for database backed templates
|
10
|
+
include Cmor::Cms::DatabaseResolver
|
11
|
+
|
12
|
+
def build_source(record)
|
13
|
+
output = ''
|
14
|
+
record.content_blocks.each do |content_block|
|
15
|
+
# rendered_body = RedCloth.new(begin;content_block.body;end).to_html.html_safe
|
16
|
+
rendered_body = RedCloth.new(content_block.body).to_html
|
17
|
+
output << "<% content_for :#{content_block.content_box_name} do %>#{rendered_body}<% end %>"
|
18
|
+
end
|
19
|
+
|
20
|
+
output << content_for_title(record)
|
21
|
+
output << content_for_meta_description(record)
|
22
|
+
|
23
|
+
output << record.body unless record.body.nil?
|
24
|
+
|
25
|
+
output
|
26
|
+
end
|
27
|
+
|
28
|
+
def normalize_basename(basename)
|
29
|
+
basename
|
30
|
+
end
|
31
|
+
|
32
|
+
def resolve(partial_flag)
|
33
|
+
!partial_flag
|
34
|
+
end
|
35
|
+
|
36
|
+
def template_class
|
37
|
+
'Cmor::Cms::Page'
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def content_for_title(record)
|
43
|
+
case record.handler
|
44
|
+
when 'haml'
|
45
|
+
"= content_for(:title) { \"#{Cmor::Cms::Configuration.site_title} - #{record.title}\" }\r\n"
|
46
|
+
else
|
47
|
+
"<% content_for :title do %>#{Cmor::Cms::Configuration.site_title} - #{record.title}<% end %>"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def content_for_meta_description(record)
|
52
|
+
case record.handler
|
53
|
+
when 'haml'
|
54
|
+
"= content_for(:meta_description) { \"#{record.meta_description}\" }\r\n"
|
55
|
+
else
|
56
|
+
"<% content_for :meta_description do %>#{record.meta_description}<% end %>"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'cmor/cms/database_resolver'
|
2
|
+
|
3
|
+
module Cmor
|
4
|
+
module Cms
|
5
|
+
class PartialResolver < ::ActionView::Resolver
|
6
|
+
require 'singleton'
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
# add shared behaviour for database backed templates
|
10
|
+
include Cmor::Cms::DatabaseResolver
|
11
|
+
|
12
|
+
def template_class
|
13
|
+
'Cmor::Cms::Partial'
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_source(record)
|
17
|
+
record.body
|
18
|
+
end
|
19
|
+
|
20
|
+
def normalize_basename(basename)
|
21
|
+
'_' << basename
|
22
|
+
end
|
23
|
+
|
24
|
+
def resolve(partial_flag)
|
25
|
+
partial_flag
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'cmor/cms/database_resolver'
|
2
|
+
|
3
|
+
module Cmor
|
4
|
+
module Cms
|
5
|
+
class TemplateResolver < ::ActionView::Resolver
|
6
|
+
require 'singleton'
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
# add shared behaviour for database backed templates
|
10
|
+
include Cmor::Cms::DatabaseResolver
|
11
|
+
|
12
|
+
def build_source(record)
|
13
|
+
record.body
|
14
|
+
end
|
15
|
+
|
16
|
+
def normalize_basename(basename)
|
17
|
+
basename
|
18
|
+
end
|
19
|
+
|
20
|
+
def resolve(partial_flag)
|
21
|
+
!partial_flag
|
22
|
+
end
|
23
|
+
|
24
|
+
def template_class
|
25
|
+
'Cmor::Cms::Template'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Cmor::Cms
|
2
|
+
# Creates root pages for all given locales.
|
3
|
+
#
|
4
|
+
# After installing the cms you don't have any pages. This service
|
5
|
+
# creates home pages for all (or the given) locales.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# Cmor::Cms::AddHomepagesService.call(locales: [:de, :en])
|
10
|
+
#
|
11
|
+
class AddHomepagesService < Rao::Service::Base
|
12
|
+
class Result < Rao::Service::Result::Base
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :locales
|
16
|
+
|
17
|
+
validates :locales, presence: true
|
18
|
+
|
19
|
+
def initialize(attributes = {}, options = {})
|
20
|
+
attributes.reverse_merge!({ locales: I18n.available_locales })
|
21
|
+
attributes[:locales].try(:reject!, &:blank?)
|
22
|
+
|
23
|
+
super(attributes, options)
|
24
|
+
|
25
|
+
@all_pages = []
|
26
|
+
@already_existent_pages = []
|
27
|
+
@failed_pages = []
|
28
|
+
@created_pages = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def _perform
|
32
|
+
create_homepages
|
33
|
+
warn("Skipped #{@already_existent_pages.size} already existent pages for locales: #{@already_existent_pages.map(&:locale).join(', ')}") if @already_existent_pages.any?
|
34
|
+
info("Added #{@created_pages.size} new home pages for locales: #{@created_pages.map(&:locale).join(', ')}")
|
35
|
+
warn("Failed adding #{@failed_pages.size} new home pages for locales: #{@failed_pages.map(&:locale).join(', ')}") if @failed_pages.any?
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def warn(message)
|
42
|
+
say(message)
|
43
|
+
end
|
44
|
+
|
45
|
+
def info(message)
|
46
|
+
say(message)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_homepages
|
50
|
+
@all_pages = @locales.collect do |locale|
|
51
|
+
say "Adding homepage for locale #{locale}"
|
52
|
+
page = Cmor::Cms::Page.where(locale: locale, pathname: '/', basename: 'home', handler: 'textile').first_or_initialize
|
53
|
+
unless page.new_record?
|
54
|
+
@already_existent_pages << page
|
55
|
+
warn "already exists"
|
56
|
+
next page
|
57
|
+
end
|
58
|
+
page.tap do |page|
|
59
|
+
page.title = "Homepage (#{locale})"
|
60
|
+
page.meta_description = 'home'
|
61
|
+
page.body = "h1. Homepage (#{locale})"
|
62
|
+
page.pathname = '/'
|
63
|
+
page.basename = 'home'
|
64
|
+
page.locale = locale
|
65
|
+
page.handler = 'textile'
|
66
|
+
end
|
67
|
+
if page.save
|
68
|
+
@created_pages << page
|
69
|
+
info "done"
|
70
|
+
else
|
71
|
+
@failed_pages << page
|
72
|
+
errors << page.errors
|
73
|
+
warn "could not save page. errors: #{page.errors.full_messages.to_sentence}"
|
74
|
+
end
|
75
|
+
page
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Cmor::Cms
|
2
|
+
class CreateNavigationService < Rao::Service::Base
|
3
|
+
class Result < Rao::Service::Result::Base
|
4
|
+
attr_accessor :navigation, :navigation_items, :created_navigation_items, :errored_navigation_items
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_accessor :locale, :name, :items_attributes
|
8
|
+
|
9
|
+
validates :locale, :name, :items_attributes, presence: true
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def after_initialize
|
14
|
+
@created_navigation_items ||= []
|
15
|
+
@errored_navigation_items ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def _perform
|
19
|
+
@navigation = build_navigation
|
20
|
+
@navigation_items = build_navigation_items
|
21
|
+
@navigation_items.collect do |navigation_item|
|
22
|
+
if navigation_item.save
|
23
|
+
say "Created #{navigation_item}"
|
24
|
+
@created_navigation_items << navigation_item
|
25
|
+
else
|
26
|
+
add_error_and_say :base, "Error creating #{navigation_item}. Errors: #{navigation_item.errors.full_messages.to_sentence}"
|
27
|
+
@errored_navigation_items << navigation_item
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@result.navigation = @navigation
|
32
|
+
@result.navigation_items = @navigation_items
|
33
|
+
@result.created_navigation_items = @created_navigation_items
|
34
|
+
@result.errored_navigation_items = @errored_navigation_items
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def build_navigation
|
40
|
+
Navigation.new(locale: locale, name: name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_navigation_items
|
44
|
+
@items_attributes.collect do |item_attributes|
|
45
|
+
NavigationItem.new(item_attributes.merge(navigation: @navigation))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Cmor::Cms
|
2
|
+
class ImportPartialsService < Rao::Service::Base
|
3
|
+
class Result < Rao::Service::Result::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class PartialInFileSystem
|
7
|
+
def initialize(filename, view_path)
|
8
|
+
@filename = filename
|
9
|
+
@view_path = view_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def pathname
|
13
|
+
@pathname ||= File.join("#{File.dirname(relative_filename)}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def basename
|
17
|
+
@basename ||= File.basename(relative_filename).split('.').first
|
18
|
+
end
|
19
|
+
|
20
|
+
def locale
|
21
|
+
locale = File.basename(relative_filename).split('.')[-3]
|
22
|
+
if I18n.available_locales.map(&:to_s).include?(locale)
|
23
|
+
@locale ||= locale
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def format
|
28
|
+
format = File.basename(relative_filename).split('.')[-2]
|
29
|
+
@format ||= format if Mime::SET.symbols.map(&:to_s).include?(format)
|
30
|
+
end
|
31
|
+
|
32
|
+
def handler
|
33
|
+
handler = File.basename(relative_filename).split('.').last
|
34
|
+
if ActionView::Template::Handlers.extensions.map(&:to_s).include?(handler)
|
35
|
+
@handler ||= handler
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def body
|
40
|
+
File.read(@filename)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_partial_attributes_hash
|
44
|
+
{
|
45
|
+
pathname: pathname,
|
46
|
+
basename: basename,
|
47
|
+
locale: locale,
|
48
|
+
format: format,
|
49
|
+
handler: handler,
|
50
|
+
body: body
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def human
|
55
|
+
"#{relative_filename} (#{body.size} bytes)"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def relative_filename
|
61
|
+
@relative_filename ||= @filename.gsub(view_path.to_s, '')
|
62
|
+
end
|
63
|
+
|
64
|
+
attr_reader :view_path
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_accessor :view_path, :force
|
68
|
+
|
69
|
+
validates :view_path, presence: true
|
70
|
+
|
71
|
+
def initialize(attributes = {}, options = {})
|
72
|
+
attributes.reverse_merge!(view_path: Rails.root.join(*%w(app views)), force: false)
|
73
|
+
super(attributes, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def _perform
|
79
|
+
@partials = load_partials
|
80
|
+
partials_count = @partials.size
|
81
|
+
say "Processing #{partials_count} partials in #{view_path}" do
|
82
|
+
@partials.each_with_index do |partial, index|
|
83
|
+
say " (#{index + 1}/#{partials_count}) #{partial.human}" do
|
84
|
+
attributes_hash = partial.to_partial_attributes_hash
|
85
|
+
partial = force ? find_or_initialize_partial(attributes_hash) : initialize_partial(attributes_hash)
|
86
|
+
new_record = partial.new_record?
|
87
|
+
partial.attributes = attributes_hash
|
88
|
+
if partial.save
|
89
|
+
say "#{new_record ? 'Created' : 'Updated'} #{partial.human}"
|
90
|
+
else
|
91
|
+
say "Could not #{new_record ? 'create' : 'update'} #{partial.human}. Errors: #{partial.errors.full_messages.to_sentence}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def force=(value)
|
99
|
+
@force = if Rails.version < '5.0'
|
100
|
+
ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
|
101
|
+
else
|
102
|
+
ActiveRecord::Type::Boolean.new.cast(value)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def find_or_initialize_partial(attributes)
|
109
|
+
attributes = attributes.dup
|
110
|
+
attributes.compact!.delete(:body)
|
111
|
+
Partial.where(attributes).first_or_initialize
|
112
|
+
end
|
113
|
+
|
114
|
+
def initialize_partial(attributes)
|
115
|
+
Partial.new(attributes)
|
116
|
+
end
|
117
|
+
|
118
|
+
def load_partials
|
119
|
+
load_partials_absolute.collect { |file| PartialInFileSystem.new(file, view_path) }
|
120
|
+
end
|
121
|
+
|
122
|
+
def load_partials_absolute
|
123
|
+
Dir.glob("#{view_path}/**/_*.*")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|