effective_pages 3.0.1 → 3.0.2

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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/admin/menus_controller.rb +1 -1
  3. data/app/controllers/admin/pages_controller.rb +1 -1
  4. data/app/datatables/effective_pages_datatable.rb +17 -1
  5. data/app/datatables/effective_pages_menu_datatable.rb +38 -0
  6. data/app/helpers/effective_menus_helper.rb +31 -136
  7. data/app/models/effective/page.rb +31 -8
  8. data/app/views/admin/menus/index.html.haml +11 -0
  9. data/app/views/admin/pages/_form.html.haml +20 -21
  10. data/app/views/admin/pages/_form_access.html.haml +10 -0
  11. data/app/views/admin/pages/_form_content.html.haml +3 -0
  12. data/app/views/admin/pages/_form_menu.html.haml +16 -0
  13. data/app/views/admin/pages/_form_page.html.haml +31 -0
  14. data/app/views/admin/pages/_rich_text_areas.html.haml +2 -0
  15. data/app/views/effective/pages/_menu.html.haml +20 -0
  16. data/config/effective_pages.rb +0 -8
  17. data/config/routes.rb +1 -1
  18. data/db/migrate/01_create_effective_pages.rb.erb +2 -28
  19. data/lib/effective_pages.rb +2 -2
  20. data/lib/effective_pages/version.rb +1 -1
  21. data/lib/generators/templates/example.html.haml +4 -1
  22. metadata +10 -15
  23. data/app/datatables/effective_menus_datatable.rb +0 -16
  24. data/app/helpers/effective_breadcrumbs_helper.rb +0 -41
  25. data/app/helpers/effective_menus_admin_helper.rb +0 -8
  26. data/app/models/effective/menu.rb +0 -148
  27. data/app/models/effective/menu_item.rb +0 -81
  28. data/app/views/admin/menu_items/_actions.html.haml +0 -4
  29. data/app/views/admin/menu_items/_expand.html.haml +0 -2
  30. data/app/views/admin/menu_items/_item.html.haml +0 -13
  31. data/app/views/admin/menu_items/_new.html.haml +0 -3
  32. data/app/views/admin/menus/_form.html.haml +0 -4
  33. data/app/views/admin/menus/show.html.haml +0 -39
  34. data/app/views/admin/pages/_rich_texts.html.haml +0 -2
  35. data/app/views/admin/pages/_roles.html.haml +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccfde3b643933010d2ed2b254f381eda959b5d057cf9e30ab1cb1e2ed57adfaf
4
- data.tar.gz: 5021c6f8feb8dfddc5f32ae1e076c976f7fc15408d0c69db25ae37e8c40da834
3
+ metadata.gz: 2624cae83c49b16480071da85aaac6bf14daac37bb3c761af9a5eb463c4f1559
4
+ data.tar.gz: 5cea72cad0f89b57bd47d62a25f1d694e0b5accd1546bd0f190dc104da3fbe10
5
5
  SHA512:
6
- metadata.gz: 70284db9597483e1ff7117056a18c282c7c822c372a6f5d1826e1d01ad4fbdba6603385e584c64040b0e2a0702590f3427d258837a38829cdbf340e5650ee613
7
- data.tar.gz: f0f64d3c8739c2aeefb511cbbd1b6fd505728e7608f06684c020c68781d0baf005b753919da9b0ed2cdaad0dcc637d5016d43ac3c7750e12344a7464a6b26678
6
+ metadata.gz: 576642b33ebfe721192d30e860d6d864d659abba485a24e158e33234f4dde18b4a3548b33d043024114fe89eae8e3c6ab8854b3dd9dc8e5e23b6c5d617d0d023
7
+ data.tar.gz: 512237ffc6d895b2d547fe0ffd8d9807931c5e925bcabb912eec86defe56745335a3f1d9c6b3fe848ed0e5613bf90505c79e91504cf125440896029eaa9b0c0e
@@ -5,7 +5,7 @@ module Admin
5
5
 
6
6
  include Effective::CrudController
7
7
 
8
- helper EffectiveMenusAdminHelper
8
+ resource_scope -> { Effective::Page.all }
9
9
 
10
10
  if (config = EffectivePages.layout)
11
11
  layout(config.kind_of?(Hash) ? config[:admin] : config)
@@ -12,7 +12,7 @@ module Admin
12
12
  submit :save, 'Save'
13
13
  submit :save, 'Save and Add New', redirect: :new
14
14
  submit :save, 'Save and View', redirect: -> { effective_pages.page_path(resource) }
15
- submit :save, 'Duplicate', only: :edit, redirect: -> { effective_posts.new_admin_page_path(duplicate_id: resource.id) }
15
+ submit :save, 'Duplicate', only: :edit, redirect: -> { effective_pages.new_admin_page_path(duplicate_id: resource.id) }
16
16
 
17
17
  def permitted_params
18
18
  params.require(:effective_page).permit!
@@ -1,5 +1,12 @@
1
1
  class EffectivePagesDatatable < Effective::Datatable
2
2
 
3
+ filters do
4
+ scope :published
5
+ scope :draft
6
+ scope :on_menu
7
+ scope :all
8
+ end
9
+
3
10
  datatable do
4
11
  order :title, :asc
5
12
  length :all
@@ -18,13 +25,22 @@ class EffectivePagesDatatable < Effective::Datatable
18
25
  col :layout, visible: false
19
26
  col :tempate, visible: false
20
27
 
28
+ col :menu
29
+ col :menu_name, visible: false
30
+ col :menu_url, visible: false
31
+ col :menu_parent, visible: false
32
+ col :menu_position, visible: false
33
+
34
+ col :authenticate_user, visible: false
35
+ col :roles, visible: false
36
+
21
37
  actions_col do |page|
22
38
  dropdown_link_to('View', effective_pages.page_path(page), target: '_blank')
23
39
  end
24
40
  end
25
41
 
26
42
  collection do
27
- Effective::Page.all
43
+ Effective::Page.deep.all
28
44
  end
29
45
 
30
46
  end
@@ -0,0 +1,38 @@
1
+ class EffectivePagesMenuDatatable < Effective::Datatable
2
+
3
+ datatable do
4
+ reorder :menu_position
5
+
6
+ if attributes[:menu_parent_id].present?
7
+ col :menu_parent
8
+ end
9
+
10
+ col :title do |page|
11
+ link_to(page, effective_pages.edit_admin_page_path(page))
12
+ end
13
+
14
+ col :menu_url, label: 'Redirect Url'
15
+ col :menu_position, label: 'Position', visible: false
16
+ col :menu_children, label: 'Children'
17
+
18
+ actions_col(new: false, destroy: false)
19
+ end
20
+
21
+ collection(apply_belongs_to: false) do
22
+ scope = Effective::Page.deep.for_menu(menu)
23
+
24
+ scope = if attributes[:menu_parent_id].present?
25
+ scope.where(menu_parent_id: attributes[:menu_parent_id])
26
+ else
27
+ scope.where(menu_parent_id: nil)
28
+ end
29
+
30
+ scope
31
+ end
32
+
33
+ def menu
34
+ menu = EffectivePages.menus.find { |menu| menu.to_s == attributes[:menu].to_s }
35
+ menu || raise("unexpected menu: #{attributes[:menu] || 'none'}")
36
+ end
37
+
38
+ end
@@ -1,156 +1,51 @@
1
+ # frozen_string_literal: true
1
2
  module EffectiveMenusHelper
2
- def render_menu(menu, options = {}, &block)
3
- menu = Effective::Menu.find_by_title(menu.to_s) if menu.kind_of?(String) || menu.kind_of?(Symbol)
4
- return "<ul class='nav navbar-nav'><li>Menu '#{menu}' does not exist</li></ul>".html_safe if !menu.present?
5
3
 
6
- if (effectively_editting? && EffectiveResources.authorized?(controller, :edit, menu) rescue false)
7
- options[:menu_id] = menu.id
8
- form_for(menu, :url => '/') { |form| options[:form] = form }
9
- end
10
-
11
- menu_items = menu.menu_items
12
-
13
- if menu.new_record?
14
- menu_items = menu_items.to_a.sort! { |a, b| a.lft <=> b.lft }
15
- end
4
+ def render_menu(name, options = {}, &block)
5
+ name = name.to_s
6
+ menu = Array(EffectivePages.menus).find { |menu| menu.to_s == name }
16
7
 
17
- if block_given? && options[:form].blank?
18
- render_menu_items(menu_items, options) { yield }
19
- else
20
- render_menu_items(menu_items, options)
8
+ if menu.blank?
9
+ raise("unable to find menu #{name}. Please add it to config/initializers/effective_pages.rb")
21
10
  end
22
11
 
23
- # if options[:for_editor]
24
- #else
25
- # Rails.cache.fetch(menu) { render_menu_items(menu.menu_items, options) }
26
- #end
12
+ content_tag(:ul, options) { render('effective/pages/menu', menu: menu) }
27
13
  end
28
14
 
29
- def render_menu_items(items, options = {}, &block)
30
- if options[:form].present? && options[:form].kind_of?(ActionView::Helpers::FormBuilder) == false
31
- raise 'Expecting ActionView::Helpers::FormBuilder object for :form => option'
32
- end
33
-
34
- html = ''
35
-
36
- if options[:form]
37
- html << "<ul class='nav navbar-nav effective-menu #{options[:class]}'"
38
- html << " data-effective-menu-id='#{options[:menu_id] || 0}'"
39
- html << " data-effective-menu-expand-html=\"#{render(:partial => 'admin/menu_items/expand').gsub('"', "'").gsub("\n", '').gsub(' ', '')}\""
40
- html << " data-effective-menu-new-html=\"#{render(:partial => 'admin/menu_items/new', :locals => { :item => Effective::MenuItem.new(), :form => options[:form] }).gsub('"', "'").gsub("\n", '').gsub(' ', '').gsub('[0]', '[:new]').gsub('_0_', '_:new_')}\""
15
+ def render_breadcrumbs(menu, page = @page, root: 'Home')
16
+ return breadcrumbs_root_url(page, root: root) if request.path == '/'
17
+ return breadcrumbs_fallback(page, root: root) unless page.kind_of?(Effective::Page)
41
18
 
42
- maxdepth = ((options[:maxdepth].presence || EffectivePages.menu[:maxdepth].presence).to_i rescue 0)
43
- html << " data-effective-menu-maxdepth='#{maxdepth}'" if maxdepth > 0
19
+ parents = [page.menu_parent].compact
44
20
 
45
- html << ">"
46
- else
47
- html << "<ul class='nav navbar-nav#{' ' + options[:class].to_s if options[:class].present?}'>"
21
+ content_tag(:ol, class: 'breadcrumb') do
22
+ (
23
+ [content_tag(:li, link_to(root, root_path, title: root), class: 'breadcrumb-item')] +
24
+ parents.map do |page|
25
+ url = (page.menu_url.presence || effective_pages.page_path(page))
26
+ content_tag(:li, link_to(page, url, title: page.title), class: 'breadcrumb-item')
27
+ end +
28
+ [content_tag(:li, page, class: 'breadcrumb-item active', 'aria-current': 'page')]
29
+ ).join.html_safe
48
30
  end
49
-
50
- stack = [items.to_a.first] # A stack to keep track of rgt values.
51
- skip_to_lft = 0 # This lets us skip over nodes we don't have visible_for? permission to see
52
-
53
- items.each_with_index do |item, index|
54
- next if index == 0 # We always skip the first Root node
55
-
56
- # This allows us to skip over nodes we don't have permission to view
57
- next if item.lft < skip_to_lft
58
- if options[:form].blank? && !item.visible_for?(defined?(current_user) ? current_user : nil)
59
- skip_to_lft = item.rgt + 1
60
- next
61
- end
62
-
63
- if stack.size > 1
64
- html << "<ul class='dropdown-menu'>" if (item.rgt < stack.last.rgt) # Level down?
65
-
66
- while item.rgt > stack.last.rgt # Level up?
67
- stack.pop
68
- html << "</ul></li>" if (item.rgt > stack.last.rgt)
69
- end
70
- end
71
-
72
- # Render the <li>...</li> with carets only on top level dropdowns, not sub dropdowns
73
- html << render_menu_item(item, stack.size == 1, options)
74
-
75
- stack.push(item)
76
- end
77
-
78
- while stack.size > 0
79
- item = stack.pop
80
-
81
- if stack.size == 0 # Very last one
82
- html << render(:partial => 'admin/menu_items/actions') if options[:form]
83
- html << (capture(&block) || '') if block_given? && !options[:form]
84
- html << '</ul>'
85
- elsif item.leaf? == false
86
- html << '</ul></li>'
87
- end
88
- end
89
-
90
- html.html_safe
91
31
  end
92
32
 
93
- private
94
-
95
- # This is where we actually build out an li item
96
- def render_menu_item(item, caret, options)
97
- html = ""
98
-
99
- url = (
100
- if item.menuable.kind_of?(Effective::Page)
101
- effective_pages.page_path(item.menuable)
102
- elsif item.divider?
103
- nil
104
- elsif (item.special || '').end_with?('_path')
105
- self.send(item.special) rescue nil
106
- elsif item.url.present?
107
- item.url
108
- end
109
- ).presence || '#'
33
+ alias_method :render_breadcrumb, :render_breadcrumbs
110
34
 
111
- classes = (item.classes || '').split(' ')
112
- classes << 'active' if EffectivePages.menu[:apply_active_class] && request.try(:fullpath) == url
113
- classes << 'divider' if item.divider?
114
- classes << 'dropdown' if item.dropdown?
115
- classes = classes.join(' ')
116
-
117
- if item.leaf?
118
- html << (classes.present? ? "<li class='#{classes}'>" : "<li>")
119
-
120
- if !item.divider? || options[:form] # Show the URL in edit mode, but not normally
121
- html << render_menu_item_anchor_tag(item, caret, url)
122
- end
123
-
124
- if options[:form]
125
- html << render(:partial => 'admin/menu_items/item', :locals => { :item => item, :form => options[:form] })
126
- end
127
-
128
- html << "</li>"
129
- else
130
- html << (classes.present? ? "<li class='#{classes}'>" : "<li>")
131
- html << render_menu_item_anchor_tag(item, caret, url)
132
-
133
- if options[:form]
134
- html << render(:partial => 'admin/menu_items/item', :locals => { :item => item, :form => options[:form] })
135
- end
35
+ def breadcrumbs_root_url(page = @page, root: 'Home')
36
+ content_tag(:ol, class: 'breadcrumb') do
37
+ content_tag(:li, root, class: 'breadcrumb-item active', 'aria-current': 'page')
136
38
  end
137
-
138
- html
139
39
  end
140
40
 
141
- def render_menu_item_anchor_tag(item, caret, url)
142
- new_window_html = (item.new_window? ? " target='_blank'" : "")
41
+ def breadcrumbs_fallback(page = @page, root: 'Home')
42
+ label = (page if page.kind_of?(Effective::Page)) || @page_title || 'Here'
143
43
 
144
- if item.special == 'destroy_user_session_path'
145
- "<a href='#{url}' data-method='delete' data-no-turbolink='true'>#{item.title}</a>"
146
- elsif item.dropdown?
147
- ''.tap do |html|
148
- html << "<a href='#{url}' data-toggle='dropdown'#{new_window_html}>#{item.title}"
149
- html << "<span class='caret'></span>" if caret
150
- html << "</a>"
151
- end
152
- else
153
- "<a href='#{url}'#{new_window_html}>#{item.title}</a>"
44
+ content_tag(:ol, class: 'breadcrumb') do
45
+ [
46
+ content_tag(:li, link_to(root, root_path, title: root), class: 'breadcrumb-item'),
47
+ content_tag(:li, label, class: 'breadcrumb-item active', 'aria-current': 'page')
48
+ ].join.html_safe
154
49
  end
155
50
  end
156
51
 
@@ -27,36 +27,56 @@ module Effective
27
27
 
28
28
  slug :string
29
29
 
30
- roles_mask :integer
31
- authenticate_user :boolean
32
-
33
30
  # Menu stuff
34
31
  menu :boolean
35
32
  menu_name :string
33
+
36
34
  menu_url :string
37
35
  menu_position :integer
38
36
 
37
+ # Access
38
+ roles_mask :integer
39
+ authenticate_user :boolean
40
+
39
41
  timestamps
40
42
  end
41
43
 
44
+ before_validation(if: -> { menu? && menu_position.blank? }) do
45
+ self.menu_position = (self.class.where(menu_parent: menu_parent).maximum(:menu_position) || -1) + 1
46
+ end
47
+
48
+ validate(if: -> { menu_url.present? }) do
49
+ unless menu_url.start_with?('http://') || menu_url.start_with?('https://') || menu_url.start_with?('/')
50
+ self.errors.add(:menu_url, "must start with http(s):// or /")
51
+ end
52
+ end
53
+
42
54
  validates :title, presence: true, length: { maximum: 255 }
43
55
  validates :meta_description, presence: true, length: { maximum: 150 }
44
56
 
57
+ validates :layout, presence: true
45
58
  validates :template, presence: true
46
59
 
47
- # validates :menu_name, if: -> { menu? },
48
- # presence: true, inclusion: { in: EffectivePages.menus }
60
+ validates :menu_name, if: -> { menu? && EffectivePages.menus.present? },
61
+ presence: true, inclusion: { in: EffectivePages.menus.map(&:to_s) }
49
62
 
50
63
  # validates :menu_position, if: -> { menu? },
51
64
  # presence: true, uniqueness: { scope: [:menu_name, :menu_parent_id] }
52
65
 
53
- scope :drafts, -> { where(draft: true) }
66
+ scope :deep, -> { includes(:menu_parent, menu_children: :menu_parent) }
67
+
68
+ scope :draft, -> { where(draft: true) }
54
69
  scope :published, -> { where(draft: false) }
55
70
  scope :sorted, -> { order(:title) }
71
+ scope :on_menu, -> { where(menu: true) }
56
72
  scope :except_home, -> { where.not(title: 'Home') }
57
73
 
58
74
  scope :menuable, -> { where(menu: true).order(:menu_position) }
75
+ scope :menu_deep, -> { includes(:menu_parent, :menu_children) }
76
+
59
77
  scope :for_menu, -> (name) { menuable.where(menu_name: name) }
78
+ scope :for_menu_root, -> (name) { for_menu(name).menu_deep.root_level }
79
+ scope :root_level, -> { where(menu_parent_id: nil) }
60
80
 
61
81
  def to_s
62
82
  title
@@ -71,9 +91,12 @@ module Effective
71
91
  Page.new(attributes.except('id', 'updated_at', 'created_at')).tap do |page|
72
92
  page.title = page.title + ' (Copy)'
73
93
  page.slug = page.slug + '-copy'
74
- page.draft = true
75
94
 
76
- post.body = body
95
+ rich_texts.each do |rt|
96
+ page.send("rich_text_#{rt.name}=", rt.body)
97
+ end
98
+
99
+ page.draft = true
77
100
  end
78
101
  end
79
102
 
@@ -0,0 +1,11 @@
1
+ %h1= @page_title
2
+
3
+ %p
4
+ Click Reorder to drag & drop reorder the menu.
5
+ Edit an item to reorder its children items.
6
+
7
+ - EffectivePages.menus.each do |menu|
8
+ %h2 #{menu.to_s.titleize} Menu
9
+ - datatable = EffectivePagesMenuDatatable.new(menu: menu)
10
+ = render_datatable(datatable, simple: true, inline: true)
11
+ %hr
@@ -1,28 +1,27 @@
1
- = effective_form_with(model: page, url: page.persisted? ? effective_pages.admin_page_path(page.id) : effective_pages.admin_pages_path) do |f|
2
- = f.text_field :title, hint: 'The title of your page.'
1
+ - if inline_datatable? && inline_datatable.attributes[:menu]
2
+ - menu = inline_datatable.attributes[:menu]
3
+ - datatable = EffectivePagesMenuDatatable.new(menu: menu, menu_parent_id: page.id)
3
4
 
4
- - if (templates = EffectivePages.templates).length > 1
5
- = f.select :template, templates
6
- - else
7
- = f.hidden_field :template, value: templates.first
5
+ = render '/admin/pages/form_menu', page: page
8
6
 
9
- - if (layouts = EffectivePages.layouts).length > 1
10
- = f.select :layout, layouts
11
- - else
12
- = f.hidden_field :layout, value: layouts.first
7
+ - if datatable.present?(self)
8
+ %h3 Children
9
+ = render_datatable(datatable, simple: true, inline: true)
13
10
 
14
- - if f.object.persisted? || f.object.errors.include?(:slug)
15
- - current_url = (effective_pages.page_url(f.object) rescue nil)
16
- = 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
11
+ - else
12
+ = tabs do
13
+ = tab 'Page' do
14
+ = render '/admin/pages/form_page', page: page
17
15
 
18
- = f.text_field :meta_description, hint: "A one or two sentence summary of this page. Appears on Google search results underneath the page title.", input_html: { maxlength: 150 }
16
+ - if page.persisted?
17
+ = tab 'Content' do
18
+ = render '/admin/pages/form_content', page: page
19
19
 
20
- = render partial: '/admin/pages/additional_fields', locals: { page: page, form: f, f: f }
21
- = render partial: '/admin/pages/rich_texts', locals: { page: page, form: f, f: f }
20
+ = tab 'Menu' do
21
+ = render '/admin/pages/form_menu', page: page
22
22
 
23
- = f.check_box :draft, label: 'Save this page as a draft. It will not be accessible on the website.'
23
+ = tab 'Access' do
24
+ = render '/admin/pages/form_access', page: page
24
25
 
25
- - if EffectivePages.use_effective_roles
26
- = render partial: '/admin/pages/roles', locals: { page: page, form: f, f: f }
27
-
28
- = effective_submit(f)
26
+ = tab 'Logs' do
27
+ = render_datatable(page.log_changes_datatable, inline: true, namespace: :admin)
@@ -0,0 +1,10 @@
1
+ = effective_form_with(model: page, url: page.persisted? ? effective_pages.admin_page_path(page.id) : effective_pages.admin_pages_path) do |f|
2
+ = f.check_box :authenticate_user, label: 'Yes, the user must be be signed in to view this page'
3
+
4
+ - if EffectivePages.use_effective_roles
5
+ = f.checks :roles, EffectiveRoles.roles_collection(f.object)
6
+
7
+ %p.text-hint
8
+ * leave blank for a regular public page that anyone can view
9
+
10
+ = f.submit
@@ -0,0 +1,3 @@
1
+ = effective_form_with(model: page, url: page.persisted? ? effective_pages.admin_page_path(page.id) : effective_pages.admin_pages_path) do |f|
2
+ = render '/admin/pages/rich_text_areas', page: page, f: f
3
+ = effective_submit(f)
@@ -0,0 +1,16 @@
1
+ = effective_form_with(model: page, url: page.persisted? ? effective_pages.admin_page_path(page.id) : effective_pages.admin_pages_path) do |f|
2
+ = f.check_box :menu, label: 'Yes, display this page on the menu'
3
+
4
+ = f.show_if :menu, true do
5
+
6
+ - if (menus = EffectivePages.menus).length > 1
7
+ = f.select :menu_name, menus
8
+ - else
9
+ = f.hidden_field :menu_name, value: menus.first
10
+
11
+ = f.text_field :menu_url, label: "Redirect to path or url instead of displaying page",
12
+ hint: "Must start with http(s):// or /"
13
+
14
+ = f.select :menu_parent_id, Effective::Page.menuable.root_level, placeholder: 'None. Top level menu.'
15
+
16
+ = f.submit
@@ -0,0 +1,31 @@
1
+ = effective_form_with(model: page, url: page.persisted? ? effective_pages.admin_page_path(page.id) : effective_pages.admin_pages_path) do |f|
2
+ = f.text_field :title, hint: 'The title of your page.'
3
+
4
+ = f.check_box :draft,
5
+ label: 'Save this page as a draft. It will not be accessible on the website.'
6
+
7
+ = f.text_field :meta_description,
8
+ hint: "A one or two sentence summary of this page. Appears on Google search results underneath the page title.",
9
+ input_html: { maxlength: 150 }
10
+
11
+ - if (layouts = EffectivePages.layouts).length > 1
12
+ = f.select :layout, layouts
13
+ - else
14
+ = f.hidden_field :layout, value: layouts.first
15
+
16
+ - if (templates = EffectivePages.templates).length > 1
17
+ = f.select :template, templates
18
+ - else
19
+ = f.hidden_field :template, value: templates.first
20
+
21
+ - if f.object.persisted? || f.object.errors.include?(:slug)
22
+ - current_url = (effective_pages.page_url(f.object) rescue nil)
23
+ = 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
24
+
25
+ = render partial: '/admin/pages/additional_fields', locals: { page: page, form: f, f: f }
26
+
27
+ -# This is for duplicate
28
+ - if f.object.new_record? && f.object.rich_texts.present?
29
+ = render partial: '/admin/pages/rich_text_areas', locals: { page: page, form: f, f: f }
30
+
31
+ = effective_submit(f)
@@ -0,0 +1,2 @@
1
+ = f.rich_text_area :rich_text_body, label: 'Body', hint: 'The main body of your page'
2
+ = f.rich_text_area :rich_text_sidebar, label: 'Sidebar', hint: 'The sidebar content of your page'
@@ -0,0 +1,20 @@
1
+ - raise('expected a menu') unless menu.present?
2
+ - menu = menu.to_s
3
+
4
+ - Effective::Page.for_menu_root(menu).each do |page|
5
+ - next unless EffectiveResources.authorized?(self, :show, page)
6
+ - next if (page.authenticate_user || page.roles.present?) && current_user.blank?
7
+ - next if page.roles.present? && !current_user.roles.include?(page.roles)
8
+
9
+ - menu_children = page.menu_children.select { |page| page.menu_name == menu }
10
+
11
+ - if menu_children.blank?
12
+ = nav_link_to(page, page.menu_url.presence || effective_pages.page_path(page))
13
+ - else
14
+ = nav_dropdown(page.to_s) do
15
+ - ([page] + menu_children).each do |page|
16
+ - next unless EffectiveResources.authorized?(self, :show, page)
17
+ - next if (page.authenticate_user || page.roles.present?) && current_user.blank?
18
+ - next if page.roles.present? && !current_user.roles.include?(page.roles)
19
+
20
+ = nav_link_to(page, page.menu_url.presence || effective_pages.page_path(page))
@@ -1,7 +1,5 @@
1
1
  EffectivePages.setup do |config|
2
2
  config.pages_table_name = :pages
3
- config.menus_table_name = :menus
4
- config.menu_items_table_name = :menu_items
5
3
 
6
4
  # The menu names a page can belong to
7
5
  config.menus = [:main, :footer]
@@ -52,10 +50,4 @@ EffectivePages.setup do |config|
52
50
  # Layout Settings
53
51
  # config.layout = { admin: 'admin' }
54
52
 
55
- # All effective_page menu options
56
- config.menu = {
57
- apply_active_class: true, # Add an .active class to the appropriate li item based on current page url
58
- maxdepth: 2 # 2 by default, strict bootstrap3 doesnt support dropdowns in your dropdowns
59
- }
60
-
61
53
  end
data/config/routes.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  EffectivePages::Engine.routes.draw do
2
2
  namespace :admin do
3
3
  resources :pages, except: [:show]
4
- resources :menus
4
+ resources :menus, only: [:index]
5
5
  end
6
6
 
7
7
  scope module: 'effective' do
@@ -15,7 +15,7 @@ class CreateEffectivePages < ActiveRecord::Migration[4.2]
15
15
  t.integer :roles_mask, default: 0
16
16
 
17
17
  t.integer :menu_parent_id
18
- t.boolean :menu, default: true
18
+ t.boolean :menu, default: false
19
19
  t.string :menu_name
20
20
  t.string :menu_url
21
21
  t.integer :menu_position
@@ -23,38 +23,12 @@ class CreateEffectivePages < ActiveRecord::Migration[4.2]
23
23
  t.datetime :updated_at
24
24
  t.datetime :created_at
25
25
  end
26
- add_index <%= @pages_table_name %>, :slug, :unique => true
27
-
28
- create_table <%= @menus_table_name %> do |t|
29
- t.string :title
30
- t.timestamps
31
- end
32
-
33
- create_table <%= @menu_items_table_name %> do |t|
34
- t.integer :menu_id
35
-
36
- t.integer :menuable_id
37
- t.string :menuable_type
38
26
 
39
- t.string :title
40
-
41
- t.string :url
42
- t.string :special
43
-
44
- t.string :classes
45
- t.boolean :new_window, :default => false
46
- t.integer :roles_mask, :default => nil
47
-
48
- t.integer :lft
49
- t.integer :rgt
50
- end
51
- add_index <%= @menu_items_table_name %>, :lft
27
+ add_index <%= @pages_table_name %>, :slug, :unique => true
52
28
  end
53
29
 
54
30
  def self.down
55
31
  drop_table <%= @pages_table_name %>
56
- drop_table <%= @menus_table_name %>
57
- drop_table <%= @menu_items_table_name %>
58
32
  end
59
33
 
60
34
  end
@@ -7,12 +7,12 @@ require 'effective_pages/version'
7
7
  module EffectivePages
8
8
  def self.config_keys
9
9
  [
10
- :pages_table_name, :menus_table_name, :menu_items_table_name,
10
+ :pages_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, :menu, :layout
15
+ :use_effective_roles, :menus, :layout
16
16
  ]
17
17
  end
18
18
 
@@ -1,3 +1,3 @@
1
1
  module EffectivePages
2
- VERSION = '3.0.1'.freeze
2
+ VERSION = '3.0.2'.freeze
3
3
  end
@@ -1,2 +1,5 @@
1
1
  %h1= page.title
2
- = page.body
2
+
3
+ .row
4
+ .col-9= page.rich_text_body
5
+ .col-3= page.rich_text_sidebar
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.0.1
4
+ version: 3.0.2
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: 2021-03-05 00:00:00.000000000 Z
11
+ date: 2021-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -78,25 +78,20 @@ files:
78
78
  - app/controllers/admin/menus_controller.rb
79
79
  - app/controllers/admin/pages_controller.rb
80
80
  - app/controllers/effective/pages_controller.rb
81
- - app/datatables/effective_menus_datatable.rb
82
81
  - app/datatables/effective_pages_datatable.rb
83
- - app/helpers/effective_breadcrumbs_helper.rb
84
- - app/helpers/effective_menus_admin_helper.rb
82
+ - app/datatables/effective_pages_menu_datatable.rb
85
83
  - app/helpers/effective_menus_helper.rb
86
84
  - app/helpers/effective_pages_helper.rb
87
- - app/models/effective/menu.rb
88
- - app/models/effective/menu_item.rb
89
85
  - app/models/effective/page.rb
90
- - app/views/admin/menu_items/_actions.html.haml
91
- - app/views/admin/menu_items/_expand.html.haml
92
- - app/views/admin/menu_items/_item.html.haml
93
- - app/views/admin/menu_items/_new.html.haml
94
- - app/views/admin/menus/_form.html.haml
95
- - app/views/admin/menus/show.html.haml
86
+ - app/views/admin/menus/index.html.haml
96
87
  - app/views/admin/pages/_additional_fields.html.haml
97
88
  - app/views/admin/pages/_form.html.haml
98
- - app/views/admin/pages/_rich_texts.html.haml
99
- - app/views/admin/pages/_roles.html.haml
89
+ - app/views/admin/pages/_form_access.html.haml
90
+ - app/views/admin/pages/_form_content.html.haml
91
+ - app/views/admin/pages/_form_menu.html.haml
92
+ - app/views/admin/pages/_form_page.html.haml
93
+ - app/views/admin/pages/_rich_text_areas.html.haml
94
+ - app/views/effective/pages/_menu.html.haml
100
95
  - config/effective_pages.rb
101
96
  - config/routes.rb
102
97
  - db/migrate/01_create_effective_pages.rb.erb
@@ -1,16 +0,0 @@
1
- class EffectiveMenusDatatable < Effective::Datatable
2
-
3
- datatable do
4
- col :id, visible: false
5
- col :updated_at, visible: false
6
-
7
- col :title
8
-
9
- actions_col
10
- end
11
-
12
- collection do
13
- Effective::Menu.all
14
- end
15
-
16
- end
@@ -1,41 +0,0 @@
1
- module EffectiveBreadcrumbsHelper
2
- def render_breadcrumbs(menu, page)
3
- menu = Effective::Menu.find_by_title(menu.to_s) if menu.kind_of?(String) || menu.kind_of?(Symbol)
4
- return "Menu '#{menu}' does not exist".html_safe unless menu.present?
5
-
6
- return breadcrumbs_fallback(page) if !page.present?
7
-
8
- menu_item = if page.kind_of?(Effective::Page)
9
- url = effective_pages.page_path(page)
10
- menu.menu_items.find { |item| item.menuable == page || item.title == page.title || item.url == url }
11
- elsif page.kind_of?(String)
12
- downcased = page.downcase
13
- menu.menu_items.find { |item| item.title.downcase == downcased || item.url == downcased }
14
- else
15
- menu.menu_items.find { |item| item.menuable == page || item.title == page || item.url == page }
16
- end
17
-
18
- return breadcrumbs_fallback(page) unless menu_item.present?
19
-
20
- parents = menu.menu_items.select { |item| item.lft < menu_item.lft && item.rgt > menu_item.rgt }
21
-
22
- content_tag(:ol, class: 'breadcrumb') do
23
- (
24
- parents.map { |parent| content_tag(:li, link_to(parent.title, parent.url.presence || '#', title: parent.title)) } +
25
- [content_tag(:li, page.try(:title) || page, class: 'active')]
26
- ).join().html_safe
27
- end
28
- end
29
-
30
- alias_method :render_breadcrumb, :render_breadcrumbs
31
-
32
- def breadcrumbs_fallback(page = nil, root: 'Home')
33
- content_tag(:ol, class: 'breadcrumb') do
34
- [
35
- content_tag(:li, link_to(root, root_path, title: root)),
36
- content_tag(:li, ((page.title if page.respond_to?(:title)) || page || @page_title || 'Here'), class: 'active')
37
- ].join().html_safe
38
- end
39
- end
40
-
41
- end
@@ -1,8 +0,0 @@
1
- module EffectiveMenusAdminHelper
2
-
3
- def visible_badge(menu_item, stack, comparator)
4
- visible = comparator.call(menu_item) && stack.all? { |parent_menu_item| parent_menu_item.lft == 1 || comparator.call(parent_menu_item) }
5
- content_tag(:span, (visible ? 'YES'.freeze : 'NO'.freeze), :class => "label label-#{(visible ? 'primary' : 'warning')}")
6
- end
7
-
8
- end
@@ -1,148 +0,0 @@
1
- module Effective
2
- class Menu < ActiveRecord::Base
3
- attr_accessor :current_user
4
-
5
- log_changes if respond_to?(:log_changes)
6
-
7
- self.table_name = EffectivePages.menus_table_name.to_s
8
-
9
- effective_resource do
10
- title :string
11
- timestamps
12
- end
13
-
14
- validates :title, presence: true, uniqueness: true, length: { maximum: 255 }
15
-
16
- has_many :menu_items, -> { MenuItem.sorted }, inverse_of: :menu, dependent: :delete_all
17
- accepts_nested_attributes_for :menu_items, allow_destroy: true
18
-
19
- before_save do
20
- if self.menu_items.find { |menu_item| menu_item.lft == 1 }.blank?
21
- menu_items.build(title: 'Home', url: '/', lft: 1, rgt: 2)
22
- end
23
- end
24
-
25
- def to_s
26
- self[:title] || 'New Menu'
27
- end
28
-
29
- def contains?(obj)
30
- menu_items.find { |menu_item| menu_item.url == obj || menu_item.menuable == obj }.present?
31
- end
32
-
33
- # This is the entry point to the DSL method for creating menu items
34
- def build(&block)
35
- raise 'build must be called with a block' if !block_given?
36
-
37
- root = menu_items.build(title: 'Home', url: '/', lft: 1, rgt: 2)
38
- root.parent = true
39
- instance_exec(&block) # A call to dropdown or item
40
- root.rgt = menu_items.map(&:rgt).max
41
- self
42
- end
43
-
44
- private
45
-
46
- def dropdown(title, options = {}, &block)
47
- raise 'dropdown must be called with a block' if !block_given?
48
- raise 'dropdown menu_items may not have a URL' if options.kind_of?(String) || options.kind_of?(Symbol)
49
- raise 'dropdown second parameter expects a Hash' unless options.kind_of?(Hash)
50
-
51
- prev_item = menu_items.last
52
-
53
- if prev_item.parent == true # This came from root or dropdown
54
- lft = prev_item.lft + 1 # Go down. from lft
55
- rgt = prev_item.rgt + 1
56
- else
57
- lft = prev_item.rgt + 1 # Go accross. from rgt
58
- rgt = prev_item.rgt + 2
59
- end
60
-
61
- # Make room for new item by shifting everything after me up by 2
62
- menu_items.each do |item|
63
- item.rgt = (item.rgt + 2) if item.rgt > (lft - 1)
64
- item.lft = (item.lft + 2) if item.lft > (lft - 1)
65
- end
66
-
67
- atts = build_menu_item_attributes(title, '', options).merge({:lft => lft, :rgt => rgt})
68
-
69
- dropdown = menu_items.build(atts)
70
- dropdown.parent = true
71
-
72
- instance_exec(&block)
73
-
74
- # Level up
75
- dropdown.rgt = menu_items.last.rgt + 1 # Level up
76
- dropdown.parent = false
77
- menu_items << menu_items.delete(dropdown) # Put myself on the end of the array
78
- end
79
-
80
- # The URL parameter can be:
81
- # - an Effective::Page object
82
- # - the symbol :divider
83
- # - a symbol or string that ends with _path
84
- # - or a string that is the url
85
-
86
- def item(title, url = '#', options = {})
87
- raise 'item third parameter expects a Hash' unless options.kind_of?(Hash)
88
-
89
- prev_item = menu_items.last
90
-
91
- if prev_item.parent == true # This came from root or dropdown
92
- lft = prev_item.lft + 1 # Go down. from lft
93
- rgt = prev_item.rgt + 1
94
- else
95
- lft = prev_item.rgt + 1 # Go accross, from rgt
96
- rgt = prev_item.rgt + 2
97
- end
98
-
99
- menu_items.each do |item|
100
- item.rgt = (item.rgt + 2) if item.rgt > (lft - 1)
101
- item.lft = (item.lft + 2) if item.lft > (lft - 1)
102
- end
103
-
104
- atts = build_menu_item_attributes(title, url, options).merge({:lft => lft, :rgt => rgt})
105
-
106
- menu_items.build(atts)
107
- end
108
-
109
- def divider(options = {})
110
- item(:divider, :divider, options)
111
- end
112
-
113
- def build_menu_item_attributes(title, url, options)
114
- options[:roles_mask] ||= 0 if (options.delete(:signed_in) || options.delete(:private))
115
- options[:roles_mask] ||= -1 if (options.delete(:signed_out) || options.delete(:guest))
116
-
117
- if options[:roles]
118
- options[:roles_mask] = EffectiveRoles.roles_mask_for(options.delete(:roles))
119
- end
120
-
121
- options[:classes] = options.delete(:class)
122
-
123
- if title == :divider || url == :divider || options[:divider] == true
124
- options[:title] = 'divider'
125
- options[:special] = 'divider'
126
- elsif title.kind_of?(Effective::Page)
127
- options[:title] = title.title
128
- options[:menuable] = title
129
- options[:url] = '#'
130
- elsif url.kind_of?(Effective::Page)
131
- options[:title] = title.presence || url.title
132
- options[:menuable] = url
133
- options[:url] = '#'
134
- elsif url.to_s.end_with?('_path')
135
- options[:title] = title
136
- options[:special] = url
137
- else
138
- options[:title] = title
139
- options[:url] = url
140
- end
141
-
142
- options
143
- end
144
-
145
-
146
- end
147
-
148
- end
@@ -1,81 +0,0 @@
1
- module Effective
2
- class MenuItem < ActiveRecord::Base
3
- attr_accessor :parent # This gets set on the Root node and a node created by Dropdown, so the item function knows whether to go down or to go accross
4
-
5
- belongs_to :menu, inverse_of: :menu_items
6
- belongs_to :menuable, polymorphic: true # Optionaly belong to an object
7
-
8
- self.table_name = EffectivePages.menu_items_table_name.to_s
9
-
10
- acts_as_role_restricted
11
-
12
- effective_resource do
13
- title :string
14
-
15
- url :string
16
- special :string # divider / search / *_path
17
-
18
- classes :string
19
- new_window :boolean
20
- roles_mask :integer # 0 is going to mean logged in, -1 is going to mean public, > 0 will be future implementation of roles masking
21
-
22
- lft :integer
23
- rgt :integer
24
-
25
- timestamps
26
- end
27
-
28
- validates :title, presence: true, length: { maximum: 255 }
29
- validates :url, length: { maximum: 255 }
30
- validates :special, length: { maximum: 255 }
31
- validates :classes, length: { maximum: 255 }
32
- validates :new_window, inclusion: { in: [true, false] }
33
-
34
- validates :lft, presence: true
35
- validates :rgt, presence: true
36
-
37
- scope :deep, -> { includes(:menuable) }
38
- scope :sorted, -> { order(:lft) }
39
-
40
- def leaf?
41
- (rgt.to_i - lft.to_i) == 1
42
- end
43
-
44
- def dropdown?
45
- !leaf?
46
- end
47
-
48
- def divider?
49
- leaf? && special == 'divider'
50
- end
51
-
52
- # For now it's just logged in or not?
53
- # This will work with effective_roles one day...
54
- def visible_for?(user)
55
- can_view_page = (
56
- if dropdown?
57
- true
58
- elsif menuable.kind_of?(Effective::Page)
59
- menuable.roles_permit?(user)
60
- else
61
- true
62
- end
63
- )
64
-
65
- can_view_menu_item = (
66
- if roles_mask == nil
67
- true
68
- elsif roles_mask == -1 # Am I logged out?
69
- user.blank?
70
- elsif roles_mask == 0 # Am I logged in?
71
- user.present?
72
- else
73
- roles_permit?(user)
74
- end
75
- )
76
-
77
- can_view_page && can_view_menu_item
78
- end
79
-
80
- end
81
- end
@@ -1,4 +0,0 @@
1
- .actions
2
- %span.add-item.glyphicon.glyphicon-plus-sign
3
- %span.remove-item.glyphicon.glyphicon-trash
4
-
@@ -1,2 +0,0 @@
1
- %ul.dropdown-menu
2
- %li.effective-menu-expand &nbsp;
@@ -1,13 +0,0 @@
1
- .menu-item
2
- = form.fields_for :menu_items, item do |f|
3
- = f.hidden_field :title, :autocomplete => 'off'
4
- = f.hidden_field :menuable_id, :autocomplete => 'off'
5
- = f.hidden_field :menuable_type, :autocomplete => 'off'
6
- = f.hidden_field :url, :autocomplete => 'off'
7
- = f.hidden_field :special, :autocomplete => 'off'
8
- = f.hidden_field :new_window, :autocomplete => 'off'
9
- = f.hidden_field :classes, :autocomplete => 'off'
10
- = f.hidden_field :roles_mask, :autocomplete => 'off'
11
- = f.hidden_field :lft, :autocomplete => 'off'
12
- = f.hidden_field :rgt, :autocomplete => 'off'
13
- = f.hidden_field :_destroy, :autocomplete => 'off'
@@ -1,3 +0,0 @@
1
- %li.new-item
2
- %a{:href => ''}
3
- = render :partial => 'admin/menu_items/item', :locals => {:item => item, :form => form}
@@ -1,4 +0,0 @@
1
- = effective_form_with(model: menu, url: (menu.persisted? ? effective_pages.admin_menu_path(menu) : effective_pages.admin_menus_path)) do |f|
2
- = f.text_field :title, hint: 'Give this menu a title'
3
-
4
- = f.submit
@@ -1,39 +0,0 @@
1
- %h1.effective-admin-heading= @page_title
2
-
3
- - if defined?(EffectiveRegions)
4
- .row.effective-admin-actions
5
- .col-sm-6
6
- %p
7
- All menu editing may be done from the fullscreen editor. Just drag and drop menu items.
8
- .col-sm-6
9
- %p.text-right
10
- = link_to "Edit #{@menu}", effective_regions.edit_path('/'), class: 'btn btn-primary', 'data-no-turbolink': true, 'data-turbolinks': false, target: '_blank'
11
-
12
- - if defined?(EffectiveRoles)
13
- %h2 Menu Items
14
-
15
- - if @menu.menu_items.length > 1
16
- %table.table
17
- %thead
18
- %th Menu Item
19
- %th.text-center Public
20
- %th.text-center Signed In
21
- - EffectiveRoles.roles.each do |role|
22
- %th.text-center= ":#{role}"
23
-
24
- %tbody
25
- - stack = [@menu.menu_items.first]
26
- - @menu.menu_items.each_with_index do |menu_item, index|
27
- - next if index == 0
28
- - stack.pop while menu_item.rgt > stack.last.rgt if stack.size > 1
29
- %tr
30
- %td
31
- = ("&nbsp;&nbsp;" * (stack.size-1)).html_safe
32
- = (menu_item.divider? ? ':divider' : menu_item.title)
33
- %td.text-center= visible_badge(menu_item, stack, Proc.new { |item| item.roles_mask == nil || item.roles_mask == -1 })
34
- %td.text-center= visible_badge(menu_item, stack, Proc.new { |item| item.roles_mask == nil || item.roles_mask == 0 })
35
- - EffectiveRoles.roles.each do |role|
36
- %td.text-center= visible_badge(menu_item, stack, Proc.new { |item| item.visible_for?(role) })
37
- - stack.push(menu_item)
38
- - else
39
- %p No menu items.
@@ -1,2 +0,0 @@
1
- = f.rich_text_area :rich_text_body, hint: 'The main body of your page'
2
- = f.rich_text_area :rich_text_sidebar, hint: 'The sidebar content of your page'
@@ -1 +0,0 @@
1
- = f.checks :roles, EffectiveRoles.roles_collection(f.object), hint: '* leave blank for a regular public page that anyone can view'