effective_pages 3.0.1 → 3.0.2

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