effective_pages 2.0.8 → 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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +11 -70
- data/app/controllers/admin/menus_controller.rb +6 -48
- data/app/controllers/admin/pages_controller.rb +11 -102
- data/app/controllers/effective/pages_controller.rb +14 -8
- data/app/datatables/effective_pages_datatable.rb +20 -2
- data/app/datatables/effective_pages_menu_datatable.rb +38 -0
- data/app/helpers/effective_menus_helper.rb +31 -136
- data/app/helpers/effective_pages_helper.rb +4 -2
- data/app/models/effective/page.rb +65 -22
- data/app/views/admin/menus/index.html.haml +10 -2
- data/app/views/admin/pages/_form.html.haml +20 -25
- data/app/views/admin/pages/_form_access.html.haml +10 -0
- data/app/views/admin/pages/_form_content.html.haml +3 -0
- data/app/views/admin/pages/_form_menu.html.haml +16 -0
- data/app/views/admin/pages/_form_page.html.haml +31 -0
- data/app/views/admin/pages/_rich_text_areas.html.haml +2 -0
- data/app/views/effective/pages/_menu.html.haml +20 -0
- data/config/effective_pages.rb +9 -38
- data/config/routes.rb +6 -9
- data/db/migrate/01_create_effective_pages.rb.erb +12 -30
- data/lib/effective_pages.rb +17 -61
- data/lib/effective_pages/version.rb +1 -1
- data/lib/generators/effective_pages/install_generator.rb +1 -1
- data/lib/generators/templates/example.html.haml +4 -5
- data/lib/tasks/effective_pages_tasks.rake +1 -1
- metadata +11 -38
- data/app/datatables/effective_menus_datatable.rb +0 -16
- data/app/helpers/effective_breadcrumbs_helper.rb +0 -41
- data/app/helpers/effective_menus_admin_helper.rb +0 -8
- data/app/models/effective/access_denied.rb +0 -17
- data/app/models/effective/menu.rb +0 -172
- data/app/models/effective/menu_item.rb +0 -78
- data/app/views/admin/menu_items/_actions.html.haml +0 -4
- data/app/views/admin/menu_items/_expand.html.haml +0 -2
- data/app/views/admin/menu_items/_item.html.haml +0 -13
- data/app/views/admin/menu_items/_new.html.haml +0 -3
- data/app/views/admin/menus/_actions.html.haml +0 -2
- data/app/views/admin/menus/_form.html.haml +0 -4
- data/app/views/admin/menus/edit.html.haml +0 -3
- data/app/views/admin/menus/new.html.haml +0 -3
- data/app/views/admin/menus/show.html.haml +0 -39
- data/app/views/admin/pages/_actions.html.haml +0 -7
- data/app/views/admin/pages/_roles.html.haml +0 -1
- data/app/views/admin/pages/edit.html.haml +0 -3
- data/app/views/admin/pages/index.html.haml +0 -6
- data/app/views/admin/pages/new.html.haml +0 -3
@@ -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
|
-
|
7
|
-
|
8
|
-
|
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
|
18
|
-
|
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
|
-
|
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
|
30
|
-
|
31
|
-
|
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
|
-
|
43
|
-
html << " data-effective-menu-maxdepth='#{maxdepth}'" if maxdepth > 0
|
19
|
+
parents = [page.menu_parent].compact
|
44
20
|
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
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
|
-
|
112
|
-
|
113
|
-
|
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
|
142
|
-
|
41
|
+
def breadcrumbs_fallback(page = @page, root: 'Home')
|
42
|
+
label = (page if page.kind_of?(Effective::Page)) || @page_title || 'Here'
|
143
43
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module EffectivePagesHelper
|
2
4
|
|
3
5
|
def effective_pages_body_classes
|
4
6
|
[
|
5
7
|
params[:controller].to_s.parameterize,
|
6
8
|
params[:action],
|
7
|
-
(
|
8
|
-
(@page.template
|
9
|
+
(user_signed_in? ? 'signed-in' : 'not-signed-in'),
|
10
|
+
(@page.template if @page && @page.respond_to?(:template)),
|
9
11
|
@body_classes
|
10
12
|
].compact.join(' ')
|
11
13
|
end
|
@@ -1,27 +1,55 @@
|
|
1
1
|
module Effective
|
2
2
|
class Page < ActiveRecord::Base
|
3
|
+
attr_accessor :current_user
|
4
|
+
|
5
|
+
# These parent / children are for the menu as well
|
6
|
+
belongs_to :menu_parent, class_name: 'Effective::Page', optional: true
|
7
|
+
|
8
|
+
has_many :menu_children, -> { Effective::Page.menuable }, class_name: 'Effective::Page',
|
9
|
+
foreign_key: :menu_parent_id, inverse_of: :menu_parent
|
10
|
+
|
3
11
|
acts_as_role_restricted
|
4
|
-
acts_as_regionable
|
5
12
|
acts_as_slugged
|
13
|
+
has_many_rich_texts
|
6
14
|
|
7
|
-
|
15
|
+
log_changes if respond_to?(:log_changes)
|
8
16
|
|
9
17
|
self.table_name = EffectivePages.pages_table_name.to_s
|
10
18
|
|
11
|
-
|
12
|
-
|
13
|
-
|
19
|
+
effective_resource do
|
20
|
+
title :string
|
21
|
+
meta_description :string
|
22
|
+
|
23
|
+
draft :boolean
|
24
|
+
|
25
|
+
layout :string
|
26
|
+
template :string
|
27
|
+
|
28
|
+
slug :string
|
29
|
+
|
30
|
+
# Menu stuff
|
31
|
+
menu :boolean
|
32
|
+
menu_name :string
|
14
33
|
|
15
|
-
|
34
|
+
menu_url :string
|
35
|
+
menu_position :integer
|
16
36
|
|
17
|
-
|
18
|
-
|
37
|
+
# Access
|
38
|
+
roles_mask :integer
|
39
|
+
authenticate_user :boolean
|
19
40
|
|
20
|
-
|
21
|
-
|
41
|
+
timestamps
|
42
|
+
end
|
22
43
|
|
23
|
-
|
24
|
-
|
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
|
25
53
|
|
26
54
|
validates :title, presence: true, length: { maximum: 255 }
|
27
55
|
validates :meta_description, presence: true, length: { maximum: 150 }
|
@@ -29,11 +57,27 @@ module Effective
|
|
29
57
|
validates :layout, presence: true
|
30
58
|
validates :template, presence: true
|
31
59
|
|
32
|
-
|
60
|
+
validates :menu_name, if: -> { menu? && EffectivePages.menus.present? },
|
61
|
+
presence: true, inclusion: { in: EffectivePages.menus.map(&:to_s) }
|
62
|
+
|
63
|
+
# validates :menu_position, if: -> { menu? },
|
64
|
+
# presence: true, uniqueness: { scope: [:menu_name, :menu_parent_id] }
|
65
|
+
|
66
|
+
scope :deep, -> { includes(:menu_parent, menu_children: :menu_parent) }
|
67
|
+
|
68
|
+
scope :draft, -> { where(draft: true) }
|
33
69
|
scope :published, -> { where(draft: false) }
|
34
70
|
scope :sorted, -> { order(:title) }
|
71
|
+
scope :on_menu, -> { where(menu: true) }
|
35
72
|
scope :except_home, -> { where.not(title: 'Home') }
|
36
73
|
|
74
|
+
scope :menuable, -> { where(menu: true).order(:menu_position) }
|
75
|
+
scope :menu_deep, -> { includes(:menu_parent, :menu_children) }
|
76
|
+
|
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) }
|
80
|
+
|
37
81
|
def to_s
|
38
82
|
title
|
39
83
|
end
|
@@ -43,24 +87,23 @@ module Effective
|
|
43
87
|
end
|
44
88
|
|
45
89
|
# Returns a duplicated post object, or throws an exception
|
46
|
-
def duplicate
|
90
|
+
def duplicate
|
47
91
|
Page.new(attributes.except('id', 'updated_at', 'created_at')).tap do |page|
|
48
92
|
page.title = page.title + ' (Copy)'
|
49
93
|
page.slug = page.slug + '-copy'
|
50
|
-
page.draft = true
|
51
94
|
|
52
|
-
|
53
|
-
page.
|
95
|
+
rich_texts.each do |rt|
|
96
|
+
page.send("rich_text_#{rt.name}=", rt.body)
|
54
97
|
end
|
55
98
|
|
56
|
-
page.
|
99
|
+
page.draft = true
|
57
100
|
end
|
58
101
|
end
|
59
102
|
|
103
|
+
def duplicate!
|
104
|
+
duplicate.tap { |page| page.save! }
|
105
|
+
end
|
106
|
+
|
60
107
|
end
|
61
108
|
|
62
109
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
@@ -1,3 +1,11 @@
|
|
1
|
-
%h1
|
1
|
+
%h1= @page_title
|
2
2
|
|
3
|
-
|
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,32 +1,27 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
5
|
-
= f.hidden_field :template, value: templates.first
|
6
|
-
- else
|
7
|
-
= f.select :template, templates
|
5
|
+
= render '/admin/pages/form_menu', page: page
|
8
6
|
|
9
|
-
- if (
|
10
|
-
|
11
|
-
|
12
|
-
= f.select :layout, layouts
|
7
|
+
- if datatable.present?(self)
|
8
|
+
%h3 Children
|
9
|
+
= render_datatable(datatable, simple: true, inline: true)
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
=
|
11
|
+
- else
|
12
|
+
= tabs do
|
13
|
+
= tab 'Page' do
|
14
|
+
= render '/admin/pages/form_page', page: page
|
17
15
|
|
18
|
-
|
16
|
+
- if page.persisted?
|
17
|
+
= tab 'Content' do
|
18
|
+
= render '/admin/pages/form_content', page: page
|
19
19
|
|
20
|
-
|
20
|
+
= tab 'Menu' do
|
21
|
+
= render '/admin/pages/form_menu', page: page
|
21
22
|
|
22
|
-
|
23
|
+
= tab 'Access' do
|
24
|
+
= render '/admin/pages/form_access', page: page
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
= f.submit do
|
28
|
-
= f.save 'Save'
|
29
|
-
= f.save 'Save and Edit Content', class: 'btn btn-secondary'
|
30
|
-
= f.save 'Save and View', class: 'btn btn-secondary'
|
31
|
-
- if f.object.persisted?
|
32
|
-
= f.save 'Duplicate', class: 'btn btn-info'
|
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,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)
|