refinerycms-pages 2.0.10 → 2.1.0
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/app/controllers/refinery/admin/pages_controller.rb +23 -17
- data/app/controllers/refinery/admin/pages_dialogs_controller.rb +8 -45
- data/app/controllers/refinery/pages/admin/preview_controller.rb +38 -0
- data/app/controllers/refinery/pages_controller.rb +26 -43
- data/app/helpers/refinery/admin/pages_helper.rb +19 -14
- data/app/models/refinery/page.rb +133 -194
- data/app/models/refinery/page_part.rb +1 -1
- data/{lib → app/presenters}/refinery/pages/content_page_presenter.rb +1 -5
- data/{lib → app/presenters}/refinery/pages/content_presenter.rb +1 -15
- data/app/presenters/refinery/pages/menu_presenter.rb +118 -0
- data/{lib → app/presenters}/refinery/pages/page_part_section_presenter.rb +0 -0
- data/{lib → app/presenters}/refinery/pages/section_presenter.rb +0 -0
- data/{lib → app/presenters}/refinery/pages/title_section_presenter.rb +0 -0
- data/app/sweepers/refinery/pages/page_sweeper.rb +29 -0
- data/app/views/refinery/admin/pages/_form.html.erb +4 -4
- data/app/views/refinery/admin/pages/_form_advanced_options.html.erb +3 -18
- data/app/views/refinery/admin/pages/_form_page_parts.html.erb +2 -2
- data/app/views/refinery/admin/pages/_page.html.erb +5 -5
- data/app/views/refinery/admin/pages/_records.html.erb +1 -3
- data/app/views/refinery/admin/pages/_sortable_list.html.erb +1 -1
- data/app/views/refinery/admin/pages/index.html.erb +1 -1
- data/app/views/refinery/admin/pages_dialogs/link_to.html.erb +0 -2
- data/config/locales/bg.yml +0 -11
- data/config/locales/cs.yml +1 -3
- data/config/locales/da.yml +15 -5
- data/config/locales/de.yml +16 -5
- data/config/locales/el.yml +0 -3
- data/config/locales/en.yml +1 -12
- data/config/locales/es.yml +0 -3
- data/config/locales/fi.yml +0 -3
- data/config/locales/fr.yml +0 -11
- data/config/locales/hu.yml +85 -0
- data/config/locales/it.yml +0 -10
- data/config/locales/ja.yml +0 -3
- data/config/locales/ko.yml +0 -11
- data/config/locales/lt.yml +0 -3
- data/config/locales/lv.yml +0 -3
- data/config/locales/nb.yml +0 -3
- data/config/locales/nl.yml +51 -40
- data/config/locales/pl.yml +23 -4
- data/config/locales/pt-BR.yml +0 -3
- data/config/locales/pt.yml +85 -0
- data/config/locales/rs.yml +0 -3
- data/config/locales/ru.yml +0 -3
- data/config/locales/sk.yml +0 -11
- data/config/locales/sl.yml +0 -3
- data/config/locales/sv.yml +0 -3
- data/config/locales/tr.yml +85 -0
- data/config/locales/uk.yml +82 -0
- data/config/locales/vi.yml +0 -3
- data/config/locales/zh-CN.yml +8 -11
- data/config/locales/zh-TW.yml +0 -3
- data/config/routes.rb +11 -5
- data/db/seeds.rb +16 -14
- data/lib/generators/refinery/pages/templates/config/initializers/refinery/pages.rb.erb +8 -4
- data/lib/refinery/pages.rb +5 -9
- data/lib/refinery/pages/caching.rb +60 -0
- data/lib/refinery/pages/configuration.rb +11 -7
- data/lib/refinery/pages/engine.rb +7 -8
- data/lib/refinery/pages/instance_methods.rb +4 -11
- data/lib/refinery/pages/render_options.rb +27 -0
- data/lib/refinery/pages/tab.rb +15 -4
- data/lib/refinery/pages/url.rb +74 -0
- data/refinerycms-pages.gemspec +4 -3
- data/spec/controllers/refinery/pages_controller_spec.rb +24 -0
- data/spec/factories/pages.rb +1 -1
- data/spec/{requests → features}/refinery/admin/pages_spec.rb +125 -42
- data/spec/{requests → features}/refinery/pages_spec.rb +139 -23
- data/spec/helpers/refinery/pages/admin/pages_helper_spec.rb +25 -25
- data/spec/lib/refinery/pages/caching_spec.rb +90 -0
- data/spec/lib/refinery/pages/tab_spec.rb +89 -0
- data/spec/lib/refinery/pages/url_spec.rb +74 -0
- data/spec/models/refinery/page_spec.rb +196 -71
- data/spec/{lib → presenters/refinery}/pages/content_page_presenter_spec.rb +0 -0
- data/spec/{lib → presenters/refinery}/pages/content_presenter_spec.rb +0 -0
- data/spec/presenters/refinery/pages/menu_presenter_spec.rb +58 -0
- data/spec/{lib → presenters/refinery}/pages/page_part_section_presenter_spec.rb +0 -0
- data/spec/{lib → presenters/refinery}/pages/section_presenter_spec.rb +0 -0
- data/spec/{lib → presenters/refinery}/pages/title_section_presenter_spec.rb +0 -0
- data/spec/support/refinery/pages/caching.rb +19 -0
- data/spec/support/refinery/pages/caching_helpers.rb +22 -0
- metadata +77 -33
- data/app/controllers/refinery/page_sweeper.rb +0 -34
- data/app/helpers/refinery/pages_helper.rb +0 -20
- data/app/views/refinery/admin/pages/_locale_picker.html.erb +0 -11
- data/config/locales/pt-PT.yml +0 -75
- data/spec/controllers/refinery/admin/pages_controller_spec.rb +0 -17
- data/spec/helpers/refinery/pages/pages_helper_spec.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4780e7414495d270398ae05f97f184a229536571
|
4
|
+
data.tar.gz: 570c24e94417d1eec341292220e105a8ee162261
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69fd5760bf9f85414fe6fbc03bb099b0a48009add74178c43fba435e5264ef2a1234d1b29608a2d7a32dd7a82c2710df35c46d526d907db3c0849542d91c0ce5
|
7
|
+
data.tar.gz: f99adadf7d2ee66c289f89789a2d0b54c1a80d1511f6a1a026dc085330b0872cdd2e4e07e91ff42eebfafb5057464cf3bf65c89b2d0926590c603c22432ec1df
|
@@ -1,24 +1,22 @@
|
|
1
1
|
module Refinery
|
2
2
|
module Admin
|
3
3
|
class PagesController < Refinery::AdminController
|
4
|
-
|
4
|
+
include Pages::InstanceMethods
|
5
|
+
cache_sweeper Pages::PageSweeper
|
5
6
|
|
6
7
|
crudify :'refinery/page',
|
7
8
|
:order => "lft ASC",
|
8
9
|
:include => [:translations, :children],
|
9
10
|
:paging => false
|
10
11
|
|
11
|
-
after_filter lambda{::Refinery::Page.expire_page_caching}, :only => [:update_positions]
|
12
|
-
|
13
12
|
before_filter :load_valid_templates, :only => [:edit, :new]
|
14
|
-
|
15
|
-
|
16
|
-
:if => proc { Refinery.i18n_enabled? }
|
13
|
+
before_filter :restrict_access, :only => [:create, :update, :update_positions, :destroy]
|
14
|
+
after_filter proc { Pages::Caching.new().expire! }, :only => :update_positions
|
17
15
|
|
18
16
|
def new
|
19
|
-
@page =
|
20
|
-
|
21
|
-
@page.parts <<
|
17
|
+
@page = Page.new(params.except(:controller, :action, :switch_locale))
|
18
|
+
Pages.default_parts_for(@page).each_with_index do |page_part, index|
|
19
|
+
@page.parts << PagePart.new(:title => page_part, :position => index)
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
@@ -42,8 +40,8 @@ module Refinery
|
|
42
40
|
redirect_to :back
|
43
41
|
else
|
44
42
|
render :partial => 'save_and_continue_callback', :locals => {
|
45
|
-
:new_refinery_page_path => refinery.admin_page_path(@page.
|
46
|
-
:new_page_path => refinery.
|
43
|
+
:new_refinery_page_path => refinery.admin_page_path(@page.nested_url),
|
44
|
+
:new_page_path => refinery.pages_admin_preview_page_path(@page.nested_url)
|
47
45
|
}
|
48
46
|
end
|
49
47
|
end
|
@@ -66,8 +64,13 @@ module Refinery
|
|
66
64
|
|
67
65
|
protected
|
68
66
|
|
67
|
+
def after_update_positions
|
68
|
+
find_all_pages
|
69
|
+
render :partial => '/refinery/admin/pages/sortable_list' and return
|
70
|
+
end
|
71
|
+
|
69
72
|
def find_page
|
70
|
-
@page =
|
73
|
+
@page = Page.find_by_path_or_id(params[:path], params[:id])
|
71
74
|
end
|
72
75
|
alias_method :page, :find_page
|
73
76
|
|
@@ -77,15 +80,18 @@ module Refinery
|
|
77
80
|
return super unless action_name.to_s == 'index'
|
78
81
|
|
79
82
|
# Always display the tree of pages from the default frontend locale.
|
80
|
-
|
83
|
+
if Refinery::I18n.built_in_locales.keys.map(&:to_s).include?(params[:switch_locale])
|
84
|
+
Globalize.locale = params[:switch_locale].try(:to_sym)
|
85
|
+
else
|
86
|
+
Globalize.locale = Refinery::I18n.default_frontend_locale
|
87
|
+
end
|
81
88
|
end
|
82
89
|
|
83
90
|
def load_valid_templates
|
84
|
-
@valid_layout_templates =
|
85
|
-
|
91
|
+
@valid_layout_templates = Pages.layout_template_whitelist &
|
92
|
+
Pages.valid_templates('app', 'views', '{layouts,refinery/layouts}', '*html*')
|
86
93
|
|
87
|
-
@valid_view_templates =
|
88
|
-
Refinery::Pages.valid_templates('app', 'views', '{pages,refinery/pages}', '*html*')
|
94
|
+
@valid_view_templates = Pages.valid_templates('app', 'views', '{pages,refinery/pages}', '*html*')
|
89
95
|
end
|
90
96
|
|
91
97
|
def restrict_access
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
1
|
module Refinery
|
4
2
|
module Admin
|
5
3
|
class PagesDialogsController < ::Refinery::Admin::DialogsController
|
@@ -9,21 +7,23 @@ module Refinery
|
|
9
7
|
def link_to
|
10
8
|
# Get the switch_local variable to determine the locale we're currently editing
|
11
9
|
# Set up Globalize with our current locale
|
12
|
-
if ::
|
13
|
-
|
10
|
+
Globalize.locale = if params[:switch_locale].present? && Refinery::I18n.built_in_locales.keys.map(&:to_s).include?(params[:switch_locale])
|
11
|
+
Globalize.locale = params[:switch_locale]
|
12
|
+
else
|
13
|
+
Refinery::I18n.default_locale
|
14
14
|
end
|
15
15
|
|
16
16
|
@pages = ::Refinery::Page.roots.paginate(:page => params[:page], :per_page => ::Refinery::Page.per_page(true))
|
17
17
|
|
18
|
-
@pages = @pages.with_globalize
|
18
|
+
@pages = @pages.with_globalize
|
19
19
|
|
20
20
|
if ::Refinery::Plugins.registered.names.include?('refinery_files')
|
21
|
-
|
22
|
-
|
21
|
+
@resources = Resource.paginate(:page => params[:resource_page], :per_page => Resource.per_page(true)).
|
22
|
+
order('created_at DESC')
|
23
23
|
|
24
24
|
# resource link
|
25
25
|
if params[:current_link].present?
|
26
|
-
|
26
|
+
is_resource_link = params[:current_link].include?("/system/resources")
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -52,43 +52,6 @@ module Refinery
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def test_url
|
56
|
-
result = 'failure'
|
57
|
-
begin
|
58
|
-
timeout(5) do
|
59
|
-
unless params[:url].blank?
|
60
|
-
url = URI.parse(params[:url])
|
61
|
-
if url.host.nil? && params[:url].start_with?('/')
|
62
|
-
url.host = URI.parse(request.url).host
|
63
|
-
end
|
64
|
-
|
65
|
-
result = case Net::HTTP.get_response(url)
|
66
|
-
when Net::HTTPSuccess, Net::HTTPRedirection
|
67
|
-
'success'
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
rescue
|
74
|
-
# be quiet
|
75
|
-
end
|
76
|
-
|
77
|
-
render :json => {:result => result}
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_email
|
81
|
-
if params[:email].present?
|
82
|
-
valid = params[:email] =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
|
83
|
-
|
84
|
-
render :json => if valid
|
85
|
-
{:result => 'success'}
|
86
|
-
else
|
87
|
-
{:result => 'failure'}
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
55
|
end
|
93
56
|
end
|
94
57
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Refinery
|
2
|
+
module Pages
|
3
|
+
module Admin
|
4
|
+
class PreviewController < AdminController
|
5
|
+
include Pages::InstanceMethods
|
6
|
+
include Pages::RenderOptions
|
7
|
+
|
8
|
+
before_filter :find_page
|
9
|
+
|
10
|
+
layout :layout
|
11
|
+
|
12
|
+
def show
|
13
|
+
render_with_templates?
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def admin?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_page
|
22
|
+
if @page = Refinery::Page.find_by_path_or_id(params[:path], params[:id])
|
23
|
+
# Preview existing pages
|
24
|
+
@page.attributes = params[:page]
|
25
|
+
elsif params[:page]
|
26
|
+
# Preview a non-persisted page
|
27
|
+
@page = Page.new params[:page]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias_method :page, :find_page
|
31
|
+
|
32
|
+
def layout
|
33
|
+
'application'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module Refinery
|
2
2
|
class PagesController < ::ApplicationController
|
3
|
-
|
4
|
-
|
3
|
+
include Pages::RenderOptions
|
4
|
+
|
5
|
+
before_filter :find_page, :set_canonical
|
6
|
+
before_filter :error_404, :unless => :current_user_can_view_page?
|
5
7
|
|
6
8
|
# Save whole Page after delivery
|
7
|
-
after_filter
|
9
|
+
after_filter :write_cache?
|
8
10
|
|
9
11
|
# This action is usually accessed with the root path, normally '/'
|
10
12
|
def home
|
@@ -22,37 +24,38 @@ module Refinery
|
|
22
24
|
# GET /about/mission
|
23
25
|
#
|
24
26
|
def show
|
25
|
-
if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if requested_friendly_id != page.friendly_id
|
32
|
-
redirect_to refinery.url_for(page.url), :status => 301
|
33
|
-
else
|
34
|
-
render_with_templates?
|
35
|
-
end
|
36
|
-
end
|
37
|
-
else
|
38
|
-
error_404
|
27
|
+
if should_skip_to_first_child?
|
28
|
+
redirect_to refinery.url_for(first_live_child.url) and return
|
29
|
+
elsif page.link_url.present?
|
30
|
+
redirect_to page.link_url and return
|
31
|
+
elsif should_redirect_to_friendly_url?
|
32
|
+
redirect_to refinery.url_for(page.url), :status => 301 and return
|
39
33
|
end
|
40
|
-
end
|
41
34
|
|
42
|
-
|
43
|
-
render_with_templates?(:action => :show)
|
35
|
+
render_with_templates?
|
44
36
|
end
|
45
37
|
|
46
38
|
protected
|
47
39
|
|
48
40
|
def requested_friendly_id
|
49
|
-
|
41
|
+
if ::Refinery::Pages.scope_slug_by_parent
|
42
|
+
# Pick out last path component, or id if present
|
43
|
+
"#{params[:path]}/#{params[:id]}".split('/').last
|
44
|
+
else
|
45
|
+
# Remove leading and trailing slashes in path, but leave internal
|
46
|
+
# ones for global slug scoping
|
47
|
+
params[:path].to_s.gsub(%r{\A/+}, '').presence || params[:id]
|
48
|
+
end
|
50
49
|
end
|
51
50
|
|
52
51
|
def should_skip_to_first_child?
|
53
52
|
page.skip_to_first_child && first_live_child
|
54
53
|
end
|
55
54
|
|
55
|
+
def should_redirect_to_friendly_url?
|
56
|
+
requested_friendly_id != page.friendly_id || ::Refinery::Pages.scope_slug_by_parent && params[:path].present? && params[:path].match(page.root.slug).nil?
|
57
|
+
end
|
58
|
+
|
56
59
|
def current_user_can_view_page?
|
57
60
|
page.live? || current_refinery_user_can_access?("refinery_pages")
|
58
61
|
end
|
@@ -65,21 +68,11 @@ module Refinery
|
|
65
68
|
page.children.order('lft ASC').live.first
|
66
69
|
end
|
67
70
|
|
68
|
-
def find_page_for_preview
|
69
|
-
if page(fallback_to_404 = false)
|
70
|
-
# Preview existing pages
|
71
|
-
@page.attributes = view_context.sanitize_hash params[:page]
|
72
|
-
elsif params[:page]
|
73
|
-
# Preview a non-persisted page
|
74
|
-
@page = Page.new params[:page]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
71
|
def find_page(fallback_to_404 = true)
|
79
72
|
@page ||= case action_name
|
80
73
|
when "home"
|
81
74
|
Refinery::Page.where(:link_url => '/').first
|
82
|
-
when "show"
|
75
|
+
when "show"
|
83
76
|
Refinery::Page.find_by_path_or_id(params[:path], params[:id])
|
84
77
|
end
|
85
78
|
@page || (error_404 if fallback_to_404)
|
@@ -87,23 +80,13 @@ module Refinery
|
|
87
80
|
|
88
81
|
alias_method :page, :find_page
|
89
82
|
|
90
|
-
def render_with_templates?(render_options = {})
|
91
|
-
if Refinery::Pages.use_layout_templates && page.layout_template.present?
|
92
|
-
render_options[:layout] = page.layout_template
|
93
|
-
end
|
94
|
-
if Refinery::Pages.use_view_templates && page.view_template.present?
|
95
|
-
render_options[:action] = page.view_template
|
96
|
-
end
|
97
|
-
render render_options if render_options.any?
|
98
|
-
end
|
99
|
-
|
100
83
|
def set_canonical
|
101
84
|
@canonical = refinery.url_for @page.canonical if @page.present?
|
102
85
|
end
|
103
86
|
|
104
87
|
def write_cache?
|
105
88
|
if Refinery::Pages.cache_pages_full && !refinery_user?
|
106
|
-
cache_page(response.body, File.join('', 'refinery', 'cache', 'pages', request.path
|
89
|
+
cache_page(response.body, File.join('', 'refinery', 'cache', 'pages', request.path).to_s)
|
107
90
|
end
|
108
91
|
end
|
109
92
|
end
|
@@ -12,15 +12,24 @@ module Refinery
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def template_options(template_type, current_page)
|
15
|
-
|
16
|
-
|
17
|
-
if current_page.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
{ :selected => Refinery::Pages.send("#{template_type}_whitelist").first }
|
15
|
+
html_options = { :selected => send("default_#{template_type}", current_page) }
|
16
|
+
|
17
|
+
if (template = current_page.send(template_type).presence)
|
18
|
+
html_options.update :selected => template
|
19
|
+
elsif current_page.parent_id? && !current_page.send(template_type).presence
|
20
|
+
template = current_page.parent.send(template_type).presence
|
21
|
+
html_options.update :selected => template if template
|
23
22
|
end
|
23
|
+
|
24
|
+
html_options
|
25
|
+
end
|
26
|
+
|
27
|
+
def default_view_template(current_page)
|
28
|
+
current_page.link_url == "/" ? "home" : "show"
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_layout_template(current_page)
|
32
|
+
"application"
|
24
33
|
end
|
25
34
|
|
26
35
|
# In the admin area we use a slightly different title
|
@@ -35,17 +44,13 @@ module Refinery
|
|
35
44
|
::I18n.t('draft', :scope => 'refinery.admin.pages.page')
|
36
45
|
end if page.draft?
|
37
46
|
|
38
|
-
meta_information
|
47
|
+
meta_information
|
39
48
|
end
|
40
49
|
|
41
50
|
# We show the title from the next available locale
|
42
51
|
# if there is no title for the current locale
|
43
52
|
def page_title_with_translations(page)
|
44
|
-
|
45
|
-
page.title
|
46
|
-
else
|
47
|
-
page.translations.detect {|t| t.title.present?}.title
|
48
|
-
end
|
53
|
+
page.title.presence || page.translations.detect {|t| t.title.present?}.title
|
49
54
|
end
|
50
55
|
end
|
51
56
|
end
|
data/app/models/refinery/page.rb
CHANGED
@@ -1,49 +1,44 @@
|
|
1
1
|
# Encoding: utf-8
|
2
|
-
require 'refinerycms-core'
|
3
|
-
require 'acts_as_indexed'
|
4
2
|
require 'friendly_id'
|
3
|
+
require 'refinery/core/base_model'
|
5
4
|
|
6
5
|
module Refinery
|
7
6
|
class Page < Core::BaseModel
|
8
7
|
extend FriendlyId
|
9
8
|
|
10
|
-
# when collecting the pages path how is each of the pages seperated?
|
11
|
-
PATH_SEPARATOR = " - "
|
12
|
-
|
13
9
|
translates :title, :menu_title, :custom_slug, :slug, :include => :seo_meta
|
14
10
|
|
15
11
|
class Translation
|
16
12
|
is_seo_meta
|
17
|
-
attr_accessible
|
13
|
+
attr_accessible *::SeoMeta.attributes.keys, :locale
|
18
14
|
end
|
19
15
|
|
20
|
-
attr_accessible :title
|
21
|
-
|
22
16
|
# Delegate SEO Attributes to globalize3 translation
|
23
17
|
seo_fields = ::SeoMeta.attributes.keys.map{|a| [a, :"#{a}="]}.flatten
|
24
18
|
delegate(*(seo_fields << {:to => :translation}))
|
25
19
|
|
26
|
-
attr_accessible :id, :deletable, :link_url, :menu_match,
|
20
|
+
attr_accessible :id, :deletable, :link_url, :menu_match,
|
27
21
|
:skip_to_first_child, :position, :show_in_menu, :draft,
|
28
|
-
:parts_attributes, :
|
29
|
-
:
|
30
|
-
:
|
22
|
+
:parts_attributes, :parent_id, :menu_title, :page_id,
|
23
|
+
:layout_template, :view_template, :custom_slug, :slug,
|
24
|
+
:title, *::SeoMeta.attributes.keys
|
31
25
|
|
32
|
-
attr_accessor :locale, :page_title, :page_menu_title # to hold temporarily
|
33
26
|
validates :title, :presence => true
|
34
27
|
|
28
|
+
validates :custom_slug, :uniqueness => true, :allow_blank => true
|
29
|
+
|
35
30
|
# Docs for acts_as_nested_set https://github.com/collectiveidea/awesome_nested_set
|
36
31
|
# rather than :delete_all we want :destroy
|
37
32
|
acts_as_nested_set :dependent => :destroy
|
38
33
|
|
39
34
|
# Docs for friendly_id http://github.com/norman/friendly_id
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
friendly_id_options = {:use => [:reserved, :globalize], :reserved_words => %w(index new session login logout users refinery admin images wymiframe)}
|
36
|
+
if ::Refinery::Pages.scope_slug_by_parent
|
37
|
+
friendly_id_options[:use] << :scoped
|
38
|
+
friendly_id_options.merge!(:scope => :parent)
|
39
|
+
end
|
43
40
|
|
44
|
-
|
45
|
-
acts_as_indexed :fields => [:title, :meta_keywords, :meta_description,
|
46
|
-
:menu_title, :browser_title, :all_page_part_content]
|
41
|
+
friendly_id :custom_slug_or_title, friendly_id_options
|
47
42
|
|
48
43
|
has_many :parts,
|
49
44
|
:foreign_key => :refinery_page_id,
|
@@ -56,10 +51,9 @@ module Refinery
|
|
56
51
|
accepts_nested_attributes_for :parts, :allow_destroy => true
|
57
52
|
|
58
53
|
before_save { |m| m.translation.save }
|
59
|
-
before_create :ensure_locale
|
54
|
+
before_create :ensure_locale!
|
60
55
|
before_destroy :deletable?
|
61
|
-
after_save :reposition_parts
|
62
|
-
after_destroy :expire_page_caching
|
56
|
+
after_save :reposition_parts!
|
63
57
|
|
64
58
|
class << self
|
65
59
|
# Live pages are 'allowed' to be shown in the frontend of your website.
|
@@ -68,13 +62,18 @@ module Refinery
|
|
68
62
|
where(:draft => false)
|
69
63
|
end
|
70
64
|
|
71
|
-
#
|
72
|
-
# For example with about/example we would need to find 'about' and then its child
|
73
|
-
# called 'example' otherwise it may clash with another page called /example.
|
65
|
+
# Find page by path, checking for scoping rules
|
74
66
|
def find_by_path(path)
|
75
|
-
|
76
|
-
|
77
|
-
|
67
|
+
if ::Refinery::Pages.scope_slug_by_parent
|
68
|
+
# With slugs scoped to the parent page we need to find a page by its full path.
|
69
|
+
# For example with about/example we would need to find 'about' and then its child
|
70
|
+
# called 'example' otherwise it may clash with another page called /example.
|
71
|
+
path = path.split('/').select(&:present?)
|
72
|
+
page = by_slug(path.shift, :parent_id => nil).first
|
73
|
+
page = page.children.by_slug(path.shift).first while page && path.any?
|
74
|
+
else
|
75
|
+
page = by_slug(path).first
|
76
|
+
end
|
78
77
|
|
79
78
|
page
|
80
79
|
end
|
@@ -83,7 +82,7 @@ module Refinery
|
|
83
82
|
# and if the path is unfriendly then a different finder method is required
|
84
83
|
# than find_by_path.
|
85
84
|
def find_by_path_or_id(path, id)
|
86
|
-
if
|
85
|
+
if path.present?
|
87
86
|
if path.friendly_id?
|
88
87
|
find_by_path(path)
|
89
88
|
else
|
@@ -102,10 +101,15 @@ module Refinery
|
|
102
101
|
with_globalize(:title => title)
|
103
102
|
end
|
104
103
|
|
105
|
-
# Finds pages by their slug.
|
104
|
+
# Finds pages by their slug. This method is necessary because pages
|
105
|
+
# are translated which means the slug attribute does not exist on the
|
106
|
+
# pages table thus requiring us to find the attribute on the translations table
|
107
|
+
# and then join to the pages table again to return the associated record.
|
106
108
|
def by_slug(slug, conditions={})
|
107
|
-
|
108
|
-
|
109
|
+
with_globalize({
|
110
|
+
:locale => Refinery::I18n.frontend_locales.map(&:to_s),
|
111
|
+
:slug => slug
|
112
|
+
}.merge(conditions))
|
109
113
|
end
|
110
114
|
|
111
115
|
# Shows all pages with :show_in_menu set to true, but it also
|
@@ -116,59 +120,26 @@ module Refinery
|
|
116
120
|
where(:show_in_menu => true).with_globalize
|
117
121
|
end
|
118
122
|
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
# using only one SQL query. This has limitations, including not being able
|
123
|
-
# to access any other attributes of the pages but you can specify more columns
|
124
|
-
# by passing in an array e.g. fast_menu([:column1, :column2])
|
125
|
-
def fast_menu(columns = [])
|
126
|
-
# First, apply a filter to determine which pages to show.
|
127
|
-
pages = live.in_menu.order('lft ASC').includes(:translations)
|
128
|
-
|
129
|
-
# Now we only want to select particular columns to avoid any further queries.
|
130
|
-
# Title and menu_title are retrieved in the next block below so they are not here.
|
131
|
-
(menu_columns | columns).each do |column|
|
132
|
-
pages = pages.select(arel_table[column.to_sym])
|
133
|
-
end
|
134
|
-
|
135
|
-
# We have to get title and menu_title from the translations table.
|
136
|
-
# To avoid calling globalize3 an extra time, we get title as page_title
|
137
|
-
# and we get menu_title as page_menu_title.
|
138
|
-
# These is used in 'to_refinery_menu_item' in the Page model.
|
139
|
-
%w(title menu_title).each do |column|
|
140
|
-
pages = pages.joins(:translations).select(
|
141
|
-
"#{translation_class.table_name}.#{column} as page_#{column}"
|
142
|
-
)
|
143
|
-
end
|
144
|
-
|
145
|
-
pages
|
123
|
+
# An optimised scope containing only live pages ordered for display in a menu.
|
124
|
+
def fast_menu
|
125
|
+
live.in_menu.order(arel_table[:lft]).includes(:parent, :translations)
|
146
126
|
end
|
147
127
|
|
148
128
|
# Wrap up the logic of finding the pages based on the translations table.
|
149
129
|
def with_globalize(conditions = {})
|
150
130
|
conditions = {:locale => ::Globalize.locale.to_s}.merge(conditions)
|
151
|
-
|
131
|
+
translations_conditions = {}
|
132
|
+
translated_attrs = translated_attribute_names.map(&:to_s) | %w(locale)
|
133
|
+
|
152
134
|
conditions.keys.each do |key|
|
153
|
-
if
|
154
|
-
|
135
|
+
if translated_attrs.include? key.to_s
|
136
|
+
translations_conditions["#{self.translation_class.table_name}.#{key}"] = conditions.delete(key)
|
155
137
|
end
|
156
138
|
end
|
157
|
-
# A join implies readonly which we don't really want.
|
158
|
-
joins(:translations).where(globalized_conditions).where(conditions).readonly(false)
|
159
|
-
end
|
160
|
-
|
161
|
-
# Wraps up all the checks that we need to do to figure out whether
|
162
|
-
# the current frontend locale is different to the current one set by ::I18n.locale.
|
163
|
-
# This terminates in a false if i18n extension is not defined or enabled.
|
164
|
-
def different_frontend_locale?
|
165
|
-
::Refinery.i18n_enabled? && ::Refinery::I18n.current_frontend_locale != ::I18n.locale
|
166
|
-
end
|
167
139
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
%w(id depth parent_id lft rgt link_url menu_match slug)
|
140
|
+
# A join implies readonly which we don't really want.
|
141
|
+
where(conditions).joins(:translations).where(translations_conditions).
|
142
|
+
readonly(false)
|
172
143
|
end
|
173
144
|
|
174
145
|
# Returns how many pages per page should there be when paginating pages
|
@@ -176,46 +147,53 @@ module Refinery
|
|
176
147
|
dialog ? Pages.pages_per_dialog : Pages.pages_per_admin_index
|
177
148
|
end
|
178
149
|
|
179
|
-
def
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
150
|
+
def rebuild_with_slug_nullification!
|
151
|
+
rebuild_without_slug_nullification!
|
152
|
+
nullify_duplicate_slugs_under_the_same_parent!
|
153
|
+
end
|
154
|
+
alias_method_chain :rebuild!, :slug_nullification
|
155
|
+
|
156
|
+
protected
|
157
|
+
def nullify_duplicate_slugs_under_the_same_parent!
|
158
|
+
t_slug = translation_class.arel_table[:slug]
|
159
|
+
joins(:translations).group(:locale, :parent_id, t_slug).having(t_slug.count.gt(1)).count.
|
160
|
+
each do |(locale, parent_id, slug), count|
|
161
|
+
by_slug(slug, :locale => locale).where(:parent_id => parent_id).drop(1).each do |page|
|
162
|
+
page.slug = nil # kill the duplicate slug
|
163
|
+
page.save # regenerate the slug
|
164
|
+
end
|
187
165
|
end
|
188
166
|
end
|
189
167
|
end
|
190
168
|
|
191
169
|
def translated_to_default_locale?
|
192
|
-
persisted? &&
|
170
|
+
persisted? && translations.where(:locale => Refinery::I18n.default_frontend_locale).any?
|
193
171
|
end
|
194
172
|
|
195
173
|
# The canonical page for this particular page.
|
196
174
|
# Consists of:
|
197
175
|
# * The default locale's translated slug
|
198
176
|
def canonical
|
199
|
-
Globalize.with_locale(Refinery
|
177
|
+
Globalize.with_locale(::Refinery::I18n.default_frontend_locale) { url }
|
200
178
|
end
|
201
179
|
|
202
180
|
# The canonical slug for this particular page.
|
203
181
|
# This is the slug for the default frontend locale.
|
204
182
|
def canonical_slug
|
205
|
-
Globalize.with_locale(Refinery
|
183
|
+
Globalize.with_locale(::Refinery::I18n.default_frontend_locale) { slug }
|
206
184
|
end
|
207
185
|
|
208
186
|
# Returns in cascading order: custom_slug or menu_title or title depending on
|
209
187
|
# which attribute is first found to be present for this page.
|
210
188
|
def custom_slug_or_title
|
211
|
-
custom_slug.presence || menu_title.presence || title
|
189
|
+
custom_slug.presence || menu_title.presence || title.presence
|
212
190
|
end
|
213
191
|
|
214
192
|
# Am I allowed to delete this page?
|
215
193
|
# If a link_url is set we don't want to break the link so we don't allow them to delete
|
216
194
|
# If deletable is set to false then we don't allow this page to be deleted. These are often Refinery system pages
|
217
195
|
def deletable?
|
218
|
-
deletable && link_url.blank?
|
196
|
+
deletable && link_url.blank? && menu_match.blank?
|
219
197
|
end
|
220
198
|
|
221
199
|
# Repositions the child page_parts that belong to this page.
|
@@ -231,13 +209,7 @@ module Refinery
|
|
231
209
|
def destroy
|
232
210
|
return super if deletable?
|
233
211
|
|
234
|
-
|
235
|
-
# give useful feedback when trying to delete from console
|
236
|
-
puts "This page is not deletable. Please use .destroy! if you really want it deleted "
|
237
|
-
puts "unset .link_url," if link_url.present?
|
238
|
-
puts "unset .menu_match," if menu_match.present?
|
239
|
-
puts "set .deletable to true" unless deletable
|
240
|
-
end
|
212
|
+
puts_destroy_help
|
241
213
|
|
242
214
|
false
|
243
215
|
end
|
@@ -257,73 +229,44 @@ module Refinery
|
|
257
229
|
# Override default options with any supplied.
|
258
230
|
options = {:reversed => true}.merge(options)
|
259
231
|
|
260
|
-
|
232
|
+
if parent_id
|
261
233
|
parts = [title, parent.path(options)]
|
262
234
|
parts.reverse! if options[:reversed]
|
263
|
-
parts.join(
|
235
|
+
parts.join(' - ')
|
264
236
|
else
|
265
237
|
title
|
266
238
|
end
|
267
239
|
end
|
268
240
|
|
269
|
-
# When this page is rendered in the navigation, where should it link?
|
270
|
-
# If a custom "link_url" is set, it uses that otherwise it defaults to a normal page URL.
|
271
|
-
# The "link_url" is often used to link to a plugin rather than a page.
|
272
|
-
#
|
273
|
-
# For example if I had a "Contact" page I don't want it to just render a contact us page
|
274
|
-
# I want it to show the Inquiries form so I can collect inquiries. So I would set the "link_url"
|
275
|
-
# to "/contact"
|
276
241
|
def url
|
277
|
-
|
278
|
-
link_url_localised?
|
279
|
-
elsif Refinery::Pages.marketable_urls
|
280
|
-
with_locale_param url_marketable
|
281
|
-
elsif to_param.present?
|
282
|
-
with_locale_param url_normal
|
283
|
-
end
|
242
|
+
Pages::Url.build(self)
|
284
243
|
end
|
285
244
|
|
286
|
-
# Adds the locale key into the URI for this page's link_url attribute, unless
|
287
|
-
# the current locale is set as the default locale.
|
288
245
|
def link_url_localised?
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
if current_url =~ %r{^/} && ::Refinery::I18n.current_frontend_locale != ::Refinery::I18n.default_frontend_locale
|
294
|
-
current_url = "/#{::Refinery::I18n.current_frontend_locale}#{current_url}"
|
295
|
-
end
|
296
|
-
|
297
|
-
current_url
|
246
|
+
Refinery.deprecate "Refinery::Page#link_url_localised?", :when => '2.2',
|
247
|
+
:replacement => "Refinery::Pages::Url::Localised#url"
|
248
|
+
Pages::Url::Localised.new(self).url
|
298
249
|
end
|
299
250
|
|
300
|
-
# Add 'marketable url' attributes into this page's url.
|
301
|
-
# This sets 'path' as the nested_url value and sets 'id' to nil.
|
302
|
-
# For example, this might evaluate to /about for the "About" page.
|
303
|
-
def url_marketable
|
304
|
-
# :id => nil is important to prevent any other params[:id] from interfering with this route.
|
305
|
-
url_normal.merge :path => nested_url, :id => nil
|
306
|
-
end
|
307
|
-
|
308
|
-
# Returns a url suitable to be used in url_for in Rails (such as link_to).
|
309
|
-
# For example, this might evaluate to /pages/about for the "About" page.
|
310
251
|
def url_normal
|
311
|
-
|
252
|
+
Refinery.deprecate "Refinery::Page#url_normal", :when => '2.2',
|
253
|
+
:replacement => "Refinery::Pages::Url::Normal#url"
|
254
|
+
Pages::Url::Normal.new(self).url
|
312
255
|
end
|
313
256
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
url_hash.update :locale => locale if locale
|
319
|
-
url_hash
|
257
|
+
def url_marketable
|
258
|
+
Refinery.deprecate "Refinery::Page#url_marketable", :when => '2.2',
|
259
|
+
:replacement => "Refinery::Pages::Url::Marketable#url"
|
260
|
+
Pages::Url::Marketable.new(self).url
|
320
261
|
end
|
321
262
|
|
322
|
-
def
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
263
|
+
def nested_url
|
264
|
+
globalized_slug = Globalize.with_locale(slug_locale) { to_param.to_s }
|
265
|
+
if ::Refinery::Pages.scope_slug_by_parent
|
266
|
+
[parent.try(:nested_url), globalized_slug].compact.flatten
|
267
|
+
else
|
268
|
+
[globalized_slug]
|
269
|
+
end
|
327
270
|
end
|
328
271
|
|
329
272
|
# Returns an array with all ancestors to_param, allow with its own
|
@@ -332,29 +275,17 @@ module Refinery
|
|
332
275
|
#
|
333
276
|
# ['about', 'mission']
|
334
277
|
#
|
335
|
-
alias_method :
|
278
|
+
alias_method :uncached_nested_url, :nested_url
|
336
279
|
|
337
|
-
# Returns the string version of nested_url, i.e., the path that should be
|
338
|
-
# by the router
|
280
|
+
# Returns the string version of nested_url, i.e., the path that should be
|
281
|
+
# generated by the router
|
339
282
|
def nested_path
|
340
|
-
|
341
|
-
end
|
342
|
-
|
343
|
-
def path_cache_key(locale = Globalize.locale)
|
344
|
-
[cache_key(locale), 'nested_path'].join('#')
|
345
|
-
end
|
346
|
-
|
347
|
-
def url_cache_key(locale = Globalize.locale)
|
348
|
-
[cache_key(locale), 'nested_url'].join('#')
|
349
|
-
end
|
350
|
-
|
351
|
-
def cache_key(locale)
|
352
|
-
[Refinery::Core.base_cache_key, 'page', locale, id].compact.join('/')
|
283
|
+
['', nested_url].join('/')
|
353
284
|
end
|
354
285
|
|
355
286
|
# Returns true if this page is "published"
|
356
287
|
def live?
|
357
|
-
|
288
|
+
!draft?
|
358
289
|
end
|
359
290
|
|
360
291
|
# Return true if this page can be shown in the navigation.
|
@@ -364,12 +295,7 @@ module Refinery
|
|
364
295
|
end
|
365
296
|
|
366
297
|
def not_in_menu?
|
367
|
-
|
368
|
-
end
|
369
|
-
|
370
|
-
# Returns true if this page is the home page or links to it.
|
371
|
-
def home?
|
372
|
-
link_url == '/'
|
298
|
+
!in_menu?
|
373
299
|
end
|
374
300
|
|
375
301
|
# Returns all visible sibling pages that can be rendered for the menu
|
@@ -377,18 +303,15 @@ module Refinery
|
|
377
303
|
siblings.reject(&:not_in_menu?)
|
378
304
|
end
|
379
305
|
|
380
|
-
def refinery_menu_title
|
381
|
-
[page_menu_title, page_title, menu_title, title].detect(&:present?)
|
382
|
-
end
|
383
|
-
|
384
306
|
def to_refinery_menu_item
|
385
307
|
{
|
386
308
|
:id => id,
|
387
309
|
:lft => lft,
|
310
|
+
:depth => depth,
|
388
311
|
:menu_match => menu_match,
|
389
312
|
:parent_id => parent_id,
|
390
313
|
:rgt => rgt,
|
391
|
-
:title =>
|
314
|
+
:title => menu_title.presence || title.presence,
|
392
315
|
:type => self.class.name,
|
393
316
|
:url => url
|
394
317
|
}
|
@@ -404,6 +327,17 @@ module Refinery
|
|
404
327
|
part_with_title(part_title).try(:body)
|
405
328
|
end
|
406
329
|
|
330
|
+
# Accessor method to test whether a page part
|
331
|
+
# exists and has content for this page.
|
332
|
+
# Example:
|
333
|
+
#
|
334
|
+
# ::Refinery::Page.first.content_for?(:body)
|
335
|
+
#
|
336
|
+
# Will return true if the page has a body page part and it is not blank.
|
337
|
+
def content_for?(part_title)
|
338
|
+
content_for(part_title).present?
|
339
|
+
end
|
340
|
+
|
407
341
|
# Accessor method to get a page part object from a page.
|
408
342
|
# Example:
|
409
343
|
#
|
@@ -420,44 +354,49 @@ module Refinery
|
|
420
354
|
end
|
421
355
|
end
|
422
356
|
|
423
|
-
|
424
|
-
|
425
|
-
|
357
|
+
private
|
358
|
+
|
359
|
+
# Make sures that a translation exists for this page.
|
360
|
+
# The translation is set to the default frontend locale.
|
361
|
+
def ensure_locale!
|
362
|
+
if self.translations.empty?
|
363
|
+
self.translations.build(:locale => Refinery::I18n.default_frontend_locale)
|
364
|
+
end
|
426
365
|
end
|
427
366
|
|
428
|
-
##
|
429
367
|
# Protects generated slugs from title if they are in the list of reserved words
|
430
368
|
# This applies mostly to plugin-generated pages.
|
431
369
|
# This only kicks in when Refinery::Pages.marketable_urls is enabled.
|
370
|
+
# Also check for global scoping, and if enabled, allow slashes in slug.
|
432
371
|
#
|
433
372
|
# Returns the sluggified string
|
434
373
|
def normalize_friendly_id_with_marketable_urls(slug_string)
|
435
|
-
|
436
|
-
|
437
|
-
|
374
|
+
# If we are scoping by parent, no slashes are allowed. Otherwise, slug is potentially
|
375
|
+
# a custom slug that contains a custom route to the page.
|
376
|
+
if !Pages.scope_slug_by_parent && slug_string.include?('/')
|
377
|
+
slug_string.sub!(%r{^/*}, '').sub!(%r{/*$}, '') # Remove leading and trailing slashes, but allow internal
|
378
|
+
slug_string.split('/').select(&:present?).map {|s| normalize_friendly_id_with_marketable_urls(s) }.join('/')
|
379
|
+
else
|
380
|
+
sluggified = slug_string.to_slug.normalize!
|
381
|
+
if Pages.marketable_urls && self.class.friendly_id_config.reserved_words.include?(sluggified)
|
382
|
+
sluggified << "-page"
|
383
|
+
end
|
384
|
+
sluggified
|
438
385
|
end
|
439
|
-
sluggified
|
440
386
|
end
|
441
387
|
alias_method_chain :normalize_friendly_id, :marketable_urls
|
442
388
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
if self.translations.empty?
|
449
|
-
self.translations.build :locale => ::Refinery::I18n.default_frontend_locale
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
def expire_page_caching
|
454
|
-
self.class.expire_page_caching
|
389
|
+
def puts_destroy_help
|
390
|
+
puts "This page is not deletable. Please use .destroy! if you really want it deleted "
|
391
|
+
puts "unset .link_url," if link_url.present?
|
392
|
+
puts "unset .menu_match," if menu_match.present?
|
393
|
+
puts "set .deletable to true" unless deletable
|
455
394
|
end
|
456
395
|
|
457
396
|
def slug_locale
|
458
397
|
return Globalize.locale if translation_for(Globalize.locale).try(:slug).present?
|
459
398
|
|
460
|
-
if
|
399
|
+
if translations.empty? || translation_for(Refinery::I18n.default_frontend_locale).present?
|
461
400
|
Refinery::I18n.default_frontend_locale
|
462
401
|
else
|
463
402
|
translations.first.locale
|