cmor_cms 0.0.1.pre
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.
- 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
|