effective_pages 3.3.2 → 3.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -4
  3. data/app/controllers/admin/carousel_items_controller.rb +15 -0
  4. data/app/controllers/admin/menus_controller.rb +3 -0
  5. data/app/controllers/admin/page_banners_controller.rb +13 -0
  6. data/app/datatables/effective_carousel_items_datatable.rb +35 -0
  7. data/app/datatables/effective_page_banners_datatable.rb +25 -0
  8. data/app/datatables/effective_page_sections_datatable.rb +2 -2
  9. data/app/datatables/effective_pages_datatable.rb +2 -0
  10. data/app/helpers/effective_carousels_helper.rb +23 -0
  11. data/app/helpers/effective_page_banners_helper.rb +23 -0
  12. data/app/models/effective/carousel_item.rb +73 -0
  13. data/app/models/effective/page.rb +36 -26
  14. data/app/models/effective/page_banner.rb +49 -0
  15. data/app/models/effective/page_section.rb +5 -6
  16. data/app/views/admin/carousel_items/_form.html.haml +7 -0
  17. data/app/views/admin/carousel_items/_form_carousel_item.html.haml +21 -0
  18. data/app/views/admin/carousel_items/index.html.haml +5 -0
  19. data/app/views/admin/menus/index.html.haml +4 -10
  20. data/app/views/admin/page_banners/_form.html.haml +7 -0
  21. data/app/views/admin/page_banners/_form_page_banner.html.haml +11 -0
  22. data/app/views/admin/page_sections/_form_page_section.html.haml +5 -5
  23. data/app/views/admin/pages/_form_page.html.haml +11 -0
  24. data/app/views/effective/carousels/_carousel.html.haml +27 -0
  25. data/config/effective_pages.rb +14 -0
  26. data/config/routes.rb +2 -0
  27. data/db/migrate/01_create_effective_pages.rb.erb +32 -5
  28. data/lib/effective_pages/engine.rb +2 -0
  29. data/lib/effective_pages/version.rb +1 -1
  30. data/lib/effective_pages.rb +20 -2
  31. data/lib/generators/effective_pages/install_generator.rb +3 -0
  32. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3ef36f0fae90cb4172cbc5541abbac53d632e611024fc1b3febd6fc8476cafd
4
- data.tar.gz: ed784ec8c9575641c5803450d5664b5d11cf90aab89d73163c4d86e28448f66e
3
+ metadata.gz: 33c7720dd14a75e375dffed5ae8c21e7390cfd93727886785c72d574fbe23376
4
+ data.tar.gz: 40ab7326b18be3a3a728461f604c4e2cfd827d75bacef55b2cd7bada79f5d513
5
5
  SHA512:
6
- metadata.gz: 6afc63a6a120d7b67d872ab985f990d0db4117b12a7e0ae1bf79a2451c00fdcf89e18e8c2a3c58d22344f3a0190e0fc9cf11589b11c01e57f8fbf7798fee12cb
7
- data.tar.gz: 38786d89a2341773f87bb122d9b64f26e7778d23c97dee10ee04d1b846b09331e9266acc7b156e6e8bd62dd249d58af64d465454d564d8cca958688ca8ca753c
6
+ metadata.gz: 4b9359a7b5c76c694ded55b524981df67e85f01e080c6ca2ae17c895762a52438d72d2c3b1ee508ff89d370eda0b921ea526af6b53800a353a8ad4ac5f79228e
7
+ data.tar.gz: 5ccdeb32c10e7920fa017a4f6d0d5ca8ba6416290de99d202a4f972092e20b3e18cb53dc4c1d26d6e38aafbeae6135073382d0029a9717d6aae61c99112adf89
data/README.md CHANGED
@@ -172,12 +172,17 @@ All authorization checks are handled via the effective_resources gem found in th
172
172
  The permissions you actually want to define are as follows (using CanCan):
173
173
 
174
174
  ```ruby
175
- can [:show], Effective::Page
175
+ can :index, Effective::Page
176
+ can(:show, Effective::Page) { |page| page.roles_permit?(user) }
176
177
 
177
178
  if user.is?(:admin)
178
- can :manage, Effective::Page
179
- can :manage, Effective::Menu
180
- can :admin, :effective_pages # Can access the admin screens
179
+ can :admin, :effective_pages
180
+
181
+ can(crud, Efective::Page)
182
+ can(crud - [:new, :create, :destroy], Effective::PageSection)
183
+
184
+ can(crud - [:destroy], Effective::PageBanner)
185
+ can(:destroy, Effective::PageBanner) { |pb| pb.pages.length == 0 }
181
186
  end
182
187
  ```
183
188
 
@@ -0,0 +1,15 @@
1
+ module Admin
2
+ class CarouselItemsController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_pages) }
5
+
6
+ include Effective::CrudController
7
+
8
+ page_title 'Carousels'
9
+
10
+ def permitted_params
11
+ params.require(:effective_carousel_item).permit!
12
+ end
13
+
14
+ end
15
+ end
@@ -3,8 +3,11 @@ module Admin
3
3
  before_action(:authenticate_user!) if defined?(Devise)
4
4
  before_action { EffectiveResources.authorize!(self, :admin, :effective_pages) }
5
5
 
6
+
6
7
  include Effective::CrudController
7
8
 
9
+ page_title 'Menus'
10
+
8
11
  resource_scope -> { Effective::Page.all }
9
12
 
10
13
  if (config = EffectivePages.layout)
@@ -0,0 +1,13 @@
1
+ module Admin
2
+ class PageBannersController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_pages) }
5
+
6
+ include Effective::CrudController
7
+
8
+ def permitted_params
9
+ params.require(:effective_page_banner).permit!
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ class EffectiveCarouselItemsDatatable < Effective::Datatable
2
+
3
+ datatable do
4
+ reorder :position
5
+
6
+ col :id, visible: false
7
+ col :updated_at, visible: false
8
+
9
+ col :carousel
10
+ col :title
11
+
12
+ col :title
13
+ col :rich_text_body, label: 'Content'
14
+
15
+ col :file, label: 'Image' do |carousel_item|
16
+ image_tag(carousel_item.file, style: 'max-height: 100px;')
17
+ end
18
+
19
+ col :link_label, visible: false
20
+ col :link_url, visible: false
21
+ col :caption, visible: false
22
+
23
+ actions_col
24
+ end
25
+
26
+ collection do
27
+ Effective::CarouselItem.deep.all.where(carousel: carousel)
28
+ end
29
+
30
+ def carousel
31
+ carousel = EffectivePages.carousels.find { |carousel| carousel.to_s == attributes[:carousel].to_s }
32
+ carousel || raise("unexpected carousel: #{attributes[:carousel] || 'none'}")
33
+ end
34
+
35
+ end
@@ -0,0 +1,25 @@
1
+ class EffectivePageBannersDatatable < Effective::Datatable
2
+
3
+ datatable do
4
+ order :name, :asc
5
+ length :all
6
+
7
+ col :id, visible: false
8
+ col :updated_at, visible: false
9
+
10
+ col :name
11
+
12
+ col :file
13
+ col :caption
14
+
15
+ col :rich_text_body, visible: false
16
+ col :pages
17
+
18
+ actions_col
19
+ end
20
+
21
+ collection do
22
+ Effective::PageBanner.deep.all
23
+ end
24
+
25
+ end
@@ -8,13 +8,13 @@ class EffectivePageSectionsDatatable < Effective::Datatable
8
8
  col :updated_at, visible: false
9
9
 
10
10
  col :name
11
- col :hint
12
11
 
13
12
  col :title
14
13
  col :rich_text_body
15
14
 
16
- col :files
15
+ col :file
17
16
 
17
+ col :hint, visible: false
18
18
  col :link_label, visible: false
19
19
  col :link_url, visible: false
20
20
  col :caption, visible: false
@@ -33,6 +33,8 @@ class EffectivePagesDatatable < Effective::Datatable
33
33
  col :menu_parent, search: { collection: admin_menu_parent_collection(), grouped: true }
34
34
  col :menu_position, visible: false
35
35
 
36
+ col :page_banner
37
+
36
38
  col :authenticate_user, visible: false
37
39
  col :roles, visible: false
38
40
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module EffectiveCarouselsHelper
3
+
4
+ def render_carousel(name, options = {}, &block)
5
+ name = name.to_s
6
+ carousel = Array(EffectivePages.carousels).find { |carousel| carousel.to_s == name }
7
+
8
+ if carousel.blank?
9
+ raise("unable to find carousel #{name}. Please add it to config/initializers/effective_pages.rb")
10
+ end
11
+
12
+ carousel_items = Effective::CarouselItem.sorted.where(carousel: carousel)
13
+ return if carousel_items.blank?
14
+
15
+ if block_given?
16
+ yield(carousel_items); nil
17
+ else
18
+ render('effective/carousels/carousel', carousel: carousel, carousel_items: carousel_items, carousel_options: options)
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EffectivePageBannersHelper
4
+
5
+ def render_page_banner(page, opts = {}, &block)
6
+ raise('expected a page') unless page.kind_of?(Effective::Page)
7
+
8
+ # Do nothing if page.banner is false
9
+ return unless page.banner?
10
+
11
+ page_banner = page.page_banner
12
+ page_banner ||= Effective::PageBanner.random.first if page.banner_random?
13
+
14
+ raise("unable to find page banner for page #{page}") unless page_banner.present?
15
+
16
+ if block_given?
17
+ yield(page_banner); nil
18
+ else
19
+ image_tag(page_banner.file, alt: page_banner.caption, **opts)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,73 @@
1
+ # Carousels are configured in the config/initializers/effective_pages.rb
2
+ # Kind of like a menu, they are predefined and cannot be edited by admin
3
+ # The carousel items belong to a carousel through the string field
4
+ module Effective
5
+ class CarouselItem < ActiveRecord::Base
6
+ attr_accessor :current_user
7
+
8
+ # For the body
9
+ has_many_rich_texts
10
+
11
+ # For the image attachment
12
+ has_one_attached :file
13
+
14
+ log_changes if respond_to?(:log_changes)
15
+
16
+ self.table_name = EffectivePages.carousel_items_table_name.to_s
17
+
18
+ effective_resource do
19
+ carousel :string # The hardcoded carousel I render underneath
20
+
21
+ title :string
22
+ caption :string
23
+
24
+ link_label :string
25
+ link_url :string
26
+
27
+ position :integer
28
+
29
+ timestamps
30
+ end
31
+
32
+ scope :deep, -> { with_attached_file.includes(:rich_texts) }
33
+ scope :sorted, -> { order(:position, :id) }
34
+
35
+ before_validation(if: -> { carousel.present? }) do
36
+ self.position ||= (self.class.where(carousel: carousel).pluck(:position).compact.max || -1) + 1
37
+ end
38
+
39
+ validates :carousel, presence: true
40
+
41
+ validates :title, presence: true, length: { maximum: 255 }
42
+ validates :file, presence: true
43
+ validates :position, presence: true
44
+
45
+ validates :link_url, presence: true, if: -> { link_label.present? }
46
+ validates :link_url, absence: true, if: -> { link_label.blank? }
47
+
48
+ validate(if: -> { carousel.present? && EffectivePages.carousels? }) do
49
+ unless (carousels = EffectivePages.carousels).find { |c| c.to_s == carousel.to_s }.present?
50
+ self.errors.add(:carousel, "must be one of #{carousels.to_sentence}")
51
+ end
52
+ end
53
+
54
+ validate(if: -> { file.attached? }) do
55
+ self.errors.add(:file, 'must be an image') unless file.image?
56
+ end
57
+
58
+ def to_s
59
+ persisted? ? [carousel, number].join(' ') : 'carousel item'
60
+ end
61
+
62
+ # As per has_many_rich_texts
63
+ def body
64
+ rich_text_body
65
+ end
66
+
67
+ def number
68
+ '#' + position.to_s
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -3,6 +3,8 @@ module Effective
3
3
  attr_accessor :current_user
4
4
  attr_accessor :menu_root_level
5
5
 
6
+ belongs_to :page_banner, optional: true
7
+
6
8
  # These parent / children are for the menu as well
7
9
  belongs_to :menu_parent, class_name: 'Effective::Page', optional: true
8
10
 
@@ -28,7 +30,7 @@ module Effective
28
30
 
29
31
  slug :string
30
32
 
31
- # Menu stuff
33
+ # Menus
32
34
  menu :boolean # Should this be displayed on the menu at all?
33
35
  menu_name :string # When I'm a root level item, this is the menu I render underneath
34
36
  menu_group :string # Used for design. Group by menu_group to display full dropdowns.
@@ -37,6 +39,10 @@ module Effective
37
39
  menu_url :string # Redirect to this url instead of the page url
38
40
  menu_position :integer # Position in the menu
39
41
 
42
+ # Banners
43
+ banner :boolean # Should we display a banner?
44
+ banner_random :boolean # Display a random banner
45
+
40
46
  # Access
41
47
  roles_mask :integer
42
48
  authenticate_user :boolean
@@ -44,31 +50,7 @@ module Effective
44
50
  timestamps
45
51
  end
46
52
 
47
- before_validation(if: -> { menu? && menu_position.blank? }) do
48
- self.menu_position = (self.class.where(menu_parent: menu_parent).maximum(:menu_position) || -1) + 1
49
- end
50
-
51
- validate(if: -> { menu_url.present? }) do
52
- unless menu_url.start_with?('http://') || menu_url.start_with?('https://') || menu_url.start_with?('/')
53
- self.errors.add(:menu_url, "must start with http(s):// or /")
54
- end
55
- end
56
-
57
- validates :title, presence: true, length: { maximum: 255 }
58
- validates :meta_description, presence: true, length: { maximum: 150 }
59
-
60
- validates :layout, presence: true
61
- validates :template, presence: true
62
-
63
- validates :menu_name, presence: true, if: -> { menu_root? && EffectivePages.menus.present? }
64
-
65
- # Doesn't make sense for a top level item to have a menu group
66
- validates :menu_group, absence: true, if: -> { menu_root? && EffectivePages.menus.present? }
67
-
68
- # validates :menu_position, if: -> { menu? },
69
- # presence: true, uniqueness: { scope: [:menu_name, :menu_parent_id] }
70
-
71
- scope :deep, -> { includes(:menu_parent, menu_children: :menu_parent) }
53
+ scope :deep, -> { includes(:page_banner, :menu_parent, menu_children: :menu_parent) }
72
54
 
73
55
  scope :draft, -> { where(draft: true) }
74
56
  scope :published, -> { where(draft: false) }
@@ -93,6 +75,34 @@ module Effective
93
75
  published.where(menu: false).or(published.where(menu: true).where.not(id: menu_root_with_children))
94
76
  }
95
77
 
78
+ before_validation(if: -> { menu? && menu_position.blank? }) do
79
+ self.menu_position = (self.class.where(menu_parent: menu_parent).maximum(:menu_position) || -1) + 1
80
+ end
81
+
82
+ validate(if: -> { menu_url.present? }) do
83
+ unless menu_url.start_with?('http://') || menu_url.start_with?('https://') || menu_url.start_with?('/')
84
+ self.errors.add(:menu_url, "must start with http(s):// or /")
85
+ end
86
+ end
87
+
88
+ validates :title, presence: true, length: { maximum: 255 }
89
+ validates :meta_description, presence: true, length: { maximum: 150 }
90
+
91
+ validates :layout, presence: true
92
+ validates :template, presence: true
93
+
94
+ validates :menu_name, presence: true, if: -> { menu_root? && EffectivePages.menus.present? }
95
+
96
+ # Doesn't make sense for a top level item to have a menu group
97
+ validates :menu_group, absence: true, if: -> { menu_root? && EffectivePages.menus.present? }
98
+
99
+ validate(if: -> { banner? && EffectivePages.banners? }) do
100
+ unless (page_banner.present? ^ banner_random?) # xor
101
+ self.errors.add(:page_banner_id, "please select a page banner or random")
102
+ self.errors.add(:banner_random, "please select a page banner or random")
103
+ end
104
+ end
105
+
96
106
  def to_s
97
107
  title
98
108
  end
@@ -0,0 +1,49 @@
1
+ # Banners can be
2
+ module Effective
3
+ class PageBanner < ActiveRecord::Base
4
+ attr_accessor :current_user
5
+
6
+ # Not used
7
+ has_many_rich_texts
8
+
9
+ # Can be displayed on multiple pages
10
+ has_many :pages
11
+
12
+ # For the image attachment
13
+ has_one_attached :file
14
+
15
+ log_changes if respond_to?(:log_changes)
16
+
17
+ self.table_name = EffectivePages.page_banners_table_name.to_s
18
+
19
+ effective_resource do
20
+ name :string # Unique name of this page banner. Just used for reference.
21
+
22
+ caption :string
23
+
24
+ timestamps
25
+ end
26
+
27
+ scope :deep, -> { with_attached_file.includes(:rich_texts) }
28
+ scope :sorted, -> { order(:name) }
29
+ scope :random, -> { order('RANDOM()') }
30
+
31
+ validates :name, presence: true, uniqueness: true, length: { maximum: 255 }
32
+ validates :file, presence: true
33
+
34
+ validate(if: -> { file.attached? }) do
35
+ self.errors.add(:file, 'must be an image') unless file.image?
36
+ end
37
+
38
+ def to_s
39
+ name.presence || 'page banner'
40
+ end
41
+
42
+ # As per has_many_rich_texts
43
+ def body
44
+ rich_text_body
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -1,10 +1,10 @@
1
+ # Page sections are only created by seeds / a developer
2
+ # They are referenced by name
3
+ # The admin user can only edit/update content
1
4
  module Effective
2
5
  class PageSection < ActiveRecord::Base
3
6
  attr_accessor :current_user
4
7
 
5
- # Not used
6
- belongs_to :owner, polymorphic: true, optional: true
7
-
8
8
  has_many_rich_texts
9
9
  has_one_attached :file
10
10
 
@@ -13,7 +13,8 @@ module Effective
13
13
  self.table_name = EffectivePages.page_sections_table_name.to_s
14
14
 
15
15
  effective_resource do
16
- name :string # Unique name of this page section
16
+ name :string # Set by developer. The unique name of this page section
17
+ hint :text # Set by developer. A hint to display to user.
17
18
 
18
19
  title :string
19
20
  caption :string
@@ -21,8 +22,6 @@ module Effective
21
22
  link_label :string
22
23
  link_url :string
23
24
 
24
- hint :text
25
-
26
25
  timestamps
27
26
  end
28
27
 
@@ -0,0 +1,7 @@
1
+ = tabs do
2
+ = tab 'Carousel Item' do
3
+ = render '/admin/carousel_items/form_carousel_item', carousel_item: carousel_item
4
+
5
+ - if carousel_item.persisted?
6
+ = tab 'Logs' do
7
+ = render_datatable(carousel_item.log_changes_datatable, inline: true, namespace: :admin)
@@ -0,0 +1,21 @@
1
+ = effective_form_with(model: [:admin, carousel_item], engine: true) do |f|
2
+ - if (carousels = EffectivePages.carousels).length > 1
3
+ = f.select :carousel, carousels, label: 'Carousel item in this carousel'
4
+ - else
5
+ = f.hidden_field :carousel, value: carousels.first
6
+
7
+ = f.text_field :title
8
+
9
+ - if defined?(EffectiveArticleEditor)
10
+ = f.article_editor :rich_text_body, label: 'Body'
11
+ - else
12
+ = f.rich_text_area :rich_text_body, label: 'Body'
13
+
14
+ .row
15
+ .col= f.text_field :link_label
16
+ .col= f.url_field :link_url
17
+
18
+ = f.file_field :file, label: 'Image attachment', hint: EffectivePages.carousels_hint_text
19
+ = f.text_field :caption, hint: 'Optional'
20
+
21
+ = effective_submit(f)
@@ -0,0 +1,5 @@
1
+ - EffectivePages.carousels.each do |carousel|
2
+ .bg-white.my-5.p-3.rounded
3
+ %h3.mb-0 #{carousel.to_s.titleize} Carousel
4
+ - datatable = EffectiveCarouselItemsDatatable.new(carousel: carousel)
5
+ = render_datatable(datatable, simple: true, inline: true)
@@ -1,11 +1,5 @@
1
- %h1= @page_title
2
-
3
- %p
4
- Click Reorder to drag & drop reorder menu items.
5
- Edit an item to reorder its children items.
6
-
7
1
  - EffectivePages.menus.each do |menu|
8
- %h3 #{menu.to_s.titleize} Menu
9
- - datatable = EffectivePagesMenuDatatable.new(menu: menu)
10
- = render_datatable(datatable, simple: true, inline: true)
11
- %hr.my-5
2
+ .bg-white.my-5.p-3.rounded
3
+ %h3.mb-0 #{menu.to_s.titleize} Menu
4
+ - datatable = EffectivePagesMenuDatatable.new(menu: menu)
5
+ = render_datatable(datatable, simple: true, inline: true)
@@ -0,0 +1,7 @@
1
+ = tabs do
2
+ = tab 'Page Banner' do
3
+ = render '/admin/page_banners/form_page_banner', page_banner: page_banner
4
+
5
+ - if page_banner.persisted?
6
+ = tab 'Logs' do
7
+ = render_datatable(page_banner.log_changes_datatable, inline: true, namespace: :admin)
@@ -0,0 +1,11 @@
1
+ = effective_form_with(model: [:admin, page_banner], engine: true) do |f|
2
+ = f.text_field :name, hint: 'The name of this banner, used only for reference'
3
+ = f.file_field :file, label: 'Image attachment', hint: EffectivePages.banners_hint_text
4
+ = f.text_field :caption, hint: 'Optional. Displayed alongside the image'
5
+
6
+ -# - if defined?(EffectiveArticleEditor)
7
+ -# = f.article_editor :rich_text_body, label: 'Body', hint: 'The main content'
8
+ -# - else
9
+ -# = f.rich_text_area :rich_text_body, label: 'Body', hint: 'The main content'
10
+
11
+ = effective_submit(f)
@@ -1,11 +1,12 @@
1
1
  = effective_form_with(model: [:admin, page_section], engine: true) do |f|
2
2
  - if f.object.new_record?
3
- = f.text_field :name, hint: 'The name of this region must be unique'
3
+ = f.text_field :name, hint: 'The name of this page section'
4
4
  - else
5
5
  = f.static_field :name
6
6
 
7
7
  - if f.object.hint.present?
8
- .mb-4= f.object.hint.html_safe
8
+ %h4.mt-0 Instructions
9
+ %p= f.object.hint.html_safe
9
10
 
10
11
  = f.text_field :title
11
12
 
@@ -18,8 +19,7 @@
18
19
  .col= f.text_field :link_label
19
20
  .col= f.url_field :link_url
20
21
 
21
- = f.file_field :file, label: 'Attachment'
22
-
23
- = f.text_field :caption
22
+ = f.file_field :file, label: 'Attachment', hint: 'Upload an image to display on this page section'
23
+ = f.text_field :caption, hint: 'Displayed alongside the image'
24
24
 
25
25
  = effective_submit(f)
@@ -23,6 +23,17 @@
23
23
  - current_url = (effective_pages.page_url(f.object) rescue nil)
24
24
  = f.text_field :slug, hint: "The slug controls this page's internet address. Be careful, changing the slug will break links that other websites may have to the old address.<br>#{('This page is currently reachable via ' + link_to(current_url.gsub(f.object.slug, '<strong>' + f.object.slug + '</strong>').html_safe, current_url)) if current_url }".html_safe
25
25
 
26
+ - if EffectivePages.banners?
27
+ = f.check_box :banner, label: 'Yes, display a page banner on this page'
28
+
29
+ = f.show_if(:banner, true) do
30
+ = card('Page Banner') do
31
+ %p.text-muted Please visit #{link_to('Page Banners', effective_pages.admin_page_banners_path)} to add or update the page banners.
32
+
33
+ = f.select :page_banner_id, Effective::PageBanner.sorted.all, label: 'Display this page banner'
34
+ %p - or -
35
+ = f.check_box :banner_random, label: 'Display a random page banner each time the page is refreshed'
36
+
26
37
  = render partial: '/admin/pages/additional_fields', locals: { page: page, form: f, f: f }
27
38
 
28
39
  - if f.object.persisted? && f.object.menu_root_with_children?
@@ -0,0 +1,27 @@
1
+ - uid = "effective-carousel-#{carousel}-#{Time.zone.now.to_i}"
2
+ - options = carousel_options
3
+
4
+ - raise('expected one or more carousel items') unless carousel_items.present?
5
+
6
+ %div.carousel.slide{id: uid, 'data-ride': 'carousel', **options}
7
+ %ol.carousel-indicators
8
+ - carousel_items.each_with_index do |item, index|
9
+ %li{'data-target': '#' + uid, 'data-slide-to': index, class: ('active' if index == 0)}
10
+
11
+ %div.carousel-inner
12
+ - carousel_items.each_with_index do |item, index|
13
+ %div.carousel-item{class: ('active' if index == 0)}
14
+ - if item.caption.blank?
15
+ = image_tag(item.file, class: 'd-block w-100', alt: "Slide #{index+1}")
16
+ - else
17
+ = image_tag(item.file, alt: item.caption)
18
+ %div.carousel-caption.d-none.d-md-block
19
+ %p= item.caption
20
+
21
+ %a.carousel-control-prev{href: '#' + uid, role: 'button', 'data-slide': 'prev'}
22
+ %span.carousel-control-prev-icon{'aria-hidden': true}
23
+ %span.sr-only Previous
24
+
25
+ %a.carousel-control-next{href: '#' + uid, role: 'button', 'data-slide': 'next'}
26
+ %span.carousel-control-next-icon{'aria-hidden': true}
27
+ %span.sr-only Next
@@ -1,6 +1,8 @@
1
1
  EffectivePages.setup do |config|
2
2
  config.pages_table_name = :pages
3
3
  config.page_sections_table_name = :page_sections
4
+ config.page_banners_table_name = :page_banners
5
+ config.carousel_items_table_name = :carousel_items
4
6
 
5
7
  # The menu names a page can belong to
6
8
  config.menus = [:main, :footer]
@@ -57,4 +59,16 @@ EffectivePages.setup do |config|
57
59
  # Only 2 or 3 are supported right now
58
60
  config.max_menu_depth = 2
59
61
 
62
+ # Page Banners
63
+ # Allow a page banner to be selected on the Admin::Pages#edit screen
64
+ # Banners can be CRUD by the admin
65
+ config.banners = false
66
+ config.banners_hint_text = 'Hint text that includes required image dimensions'
67
+
68
+ # Page Carousels
69
+ # The menu names a page can belong to
70
+ config.carousels = false
71
+ # config.carousels = [:home, :secondary]
72
+ config.carousels_hint_text = 'Hint text that includes required image dimensions'
73
+
60
74
  end
data/config/routes.rb CHANGED
@@ -4,7 +4,9 @@ EffectivePages::Engine.routes.draw do
4
4
  namespace :admin do
5
5
  resources :pages, except: [:show]
6
6
  resources :page_sections, only: [:index, :edit, :update]
7
+ resources :page_banners, except: [:show]
7
8
  resources :menus, only: [:index]
9
+ resources :carousel_items, except: [:show]
8
10
  end
9
11
 
10
12
  scope module: 'effective' do
@@ -1,6 +1,8 @@
1
1
  class CreateEffectivePages < ActiveRecord::Migration[4.2]
2
2
  def self.up
3
3
  create_table <%= @pages_table_name %> do |t|
4
+ t.integer :page_banner_id
5
+
4
6
  t.string :title
5
7
  t.string :meta_description
6
8
 
@@ -25,17 +27,27 @@ class CreateEffectivePages < ActiveRecord::Migration[4.2]
25
27
  t.string :menu_url
26
28
  t.integer :menu_position
27
29
 
30
+ t.boolean :banner, default: false
31
+ t.boolean :banner_random, default: false
32
+
28
33
  t.datetime :updated_at
29
34
  t.datetime :created_at
30
35
  end
31
36
 
32
37
  add_index <%= @pages_table_name %>, :slug, :unique => true
33
38
 
34
- create_table <%= @page_sections_table_name %> do |t|
35
- t.string :owner_type
36
- t.integer :owner_id
39
+ create_table <%= @page_banners_table_name %> do |t|
40
+ t.string :name
41
+ t.string :caption
42
+
43
+ t.timestamps
44
+ end
45
+
46
+ add_index <%= @page_banners_table_name %>, :name, :unique => true
37
47
 
48
+ create_table <%= @page_sections_table_name %> do |t|
38
49
  t.string :name
50
+ t.text :hint
39
51
 
40
52
  t.string :title
41
53
  t.string :caption
@@ -43,18 +55,33 @@ class CreateEffectivePages < ActiveRecord::Migration[4.2]
43
55
  t.string :link_label
44
56
  t.string :link_url
45
57
 
46
- t.text :hint
47
-
48
58
  t.datetime :updated_at
49
59
  t.datetime :created_at
50
60
  end
51
61
 
52
62
  add_index <%= @page_sections_table_name %>, :name, :unique => true
63
+
64
+ create_table <%= @carousel_items_table_name %> do |t|
65
+ t.string :carousel
66
+
67
+ t.string :title
68
+ t.string :caption
69
+
70
+ t.string :link_label
71
+ t.string :link_url
72
+
73
+ t.integer :position
74
+
75
+ t.timestamps
76
+ end
77
+
53
78
  end
54
79
 
55
80
  def self.down
56
81
  drop_table <%= @pages_table_name %>
82
+ drop_table <%= @page_banners_table_name %>
57
83
  drop_table <%= @page_sections_table_name %>
84
+ drop_table <%= @carousel_items_table_name %>
58
85
  end
59
86
 
60
87
  end
@@ -7,7 +7,9 @@ module EffectivePages
7
7
  app.config.to_prepare do
8
8
  ActiveSupport.on_load :action_controller_base do
9
9
  helper EffectivePagesHelper
10
+ helper EffectiveCarouselsHelper
10
11
  helper EffectivePageSectionsHelper
12
+ helper EffectivePageBannersHelper
11
13
  helper EffectiveMenusHelper
12
14
  end
13
15
  end
@@ -1,3 +1,3 @@
1
1
  module EffectivePages
2
- VERSION = '3.3.2'.freeze
2
+ VERSION = '3.4.1'.freeze
3
3
  end
@@ -7,12 +7,18 @@ require 'effective_pages/version'
7
7
  module EffectivePages
8
8
  def self.config_keys
9
9
  [
10
- :pages_table_name, :page_sections_table_name,
10
+ :pages_table_name, :page_sections_table_name, :page_banners_table_name, :carousel_items_table_name,
11
11
  :pages_path, :excluded_pages, :layouts_path, :excluded_layouts,
12
12
  :site_og_image, :site_og_image_width, :site_og_image_height,
13
13
  :site_title, :site_title_suffix, :fallback_meta_description,
14
14
  :silence_missing_page_title_warnings, :silence_missing_meta_description_warnings, :silence_missing_canonical_url_warnings,
15
- :use_effective_roles, :menus, :layout, :max_menu_depth
15
+ :use_effective_roles, :layout, :max_menu_depth, :banners_hint_text, :carousels_hint_text,
16
+
17
+ # Booleans
18
+ :banners,
19
+
20
+ # Hashes
21
+ :menus, :carousels
16
22
  ]
17
23
  end
18
24
 
@@ -49,4 +55,16 @@ module EffectivePages
49
55
  depth
50
56
  end
51
57
 
58
+ def self.banners?
59
+ !!banners
60
+ end
61
+
62
+ def self.carousels?
63
+ carousels.kind_of?(Array)
64
+ end
65
+
66
+ def self.menus?
67
+ menus.kind_of?(Array)
68
+ end
69
+
52
70
  end
@@ -22,6 +22,9 @@ module EffectivePages
22
22
  def create_migration_file
23
23
  @pages_table_name = ':' + EffectivePages.pages_table_name.to_s
24
24
  @page_sections_table_name = ':' + EffectivePages.page_sections_table_name.to_s
25
+ @page_banners_table_name = ':' + EffectivePages.page_banners_table_name.to_s
26
+ @carousel_items_table_name = ':' + EffectivePages.carousel_items_table_name.to_s
27
+
25
28
  migration_template ('../' * 3) + 'db/migrate/01_create_effective_pages.rb.erb', 'db/migrate/create_effective_pages.rb'
26
29
  end
27
30
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_pages
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.2
4
+ version: 3.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-11 00:00:00.000000000 Z
11
+ date: 2022-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -75,19 +75,32 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - MIT-LICENSE
77
77
  - README.md
78
+ - app/controllers/admin/carousel_items_controller.rb
78
79
  - app/controllers/admin/menus_controller.rb
80
+ - app/controllers/admin/page_banners_controller.rb
79
81
  - app/controllers/admin/page_sections_controller.rb
80
82
  - app/controllers/admin/pages_controller.rb
81
83
  - app/controllers/effective/pages_controller.rb
84
+ - app/datatables/effective_carousel_items_datatable.rb
85
+ - app/datatables/effective_page_banners_datatable.rb
82
86
  - app/datatables/effective_page_sections_datatable.rb
83
87
  - app/datatables/effective_pages_datatable.rb
84
88
  - app/datatables/effective_pages_menu_datatable.rb
89
+ - app/helpers/effective_carousels_helper.rb
85
90
  - app/helpers/effective_menus_helper.rb
91
+ - app/helpers/effective_page_banners_helper.rb
86
92
  - app/helpers/effective_page_sections_helper.rb
87
93
  - app/helpers/effective_pages_helper.rb
94
+ - app/models/effective/carousel_item.rb
88
95
  - app/models/effective/page.rb
96
+ - app/models/effective/page_banner.rb
89
97
  - app/models/effective/page_section.rb
98
+ - app/views/admin/carousel_items/_form.html.haml
99
+ - app/views/admin/carousel_items/_form_carousel_item.html.haml
100
+ - app/views/admin/carousel_items/index.html.haml
90
101
  - app/views/admin/menus/index.html.haml
102
+ - app/views/admin/page_banners/_form.html.haml
103
+ - app/views/admin/page_banners/_form_page_banner.html.haml
91
104
  - app/views/admin/page_sections/_form.html.haml
92
105
  - app/views/admin/page_sections/_form_page_section.html.haml
93
106
  - app/views/admin/pages/_additional_fields.html.haml
@@ -96,6 +109,7 @@ files:
96
109
  - app/views/admin/pages/_form_menu.html.haml
97
110
  - app/views/admin/pages/_form_page.html.haml
98
111
  - app/views/admin/pages/_rich_text_areas.html.haml
112
+ - app/views/effective/carousels/_carousel.html.haml
99
113
  - app/views/effective/pages/_menu.html.haml
100
114
  - app/views/effective/pages/_page_menu.html.haml
101
115
  - config/effective_pages.rb