refinerycms-pages 1.0.11 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/refinery/admin/page_parts_controller.rb +26 -0
- data/app/controllers/refinery/admin/pages_controller.rb +77 -0
- data/app/controllers/refinery/admin/pages_dialogs_controller.rb +91 -0
- data/app/controllers/refinery/page_sweeper.rb +29 -0
- data/app/controllers/refinery/pages_controller.rb +103 -0
- data/app/helpers/refinery/pages/content_pages_helper.rb +26 -0
- data/app/helpers/refinery/pages_helper.rb +4 -0
- data/app/models/refinery/page.rb +467 -0
- data/app/models/refinery/page_part.rb +33 -0
- data/app/presenters/refinery/page_presenter.rb +7 -0
- data/app/views/admin/pages/_sortable_list.html.erb +7 -4
- data/app/views/{admin → refinery/admin}/pages/_actions.html.erb +5 -4
- data/app/views/refinery/admin/pages/_form.html.erb +63 -0
- data/app/views/{admin → refinery/admin}/pages/_form_advanced_options.html.erb +35 -16
- data/app/views/refinery/admin/pages/_form_advanced_options_seo.html.erb +3 -0
- data/app/views/{admin → refinery/admin}/pages/_form_fields_after_title.html.erb +0 -0
- data/app/views/{admin → refinery/admin}/pages/_form_new_page_parts.html.erb +5 -7
- data/app/views/{admin → refinery/admin}/pages/_form_page_parts.html.erb +19 -11
- data/app/views/{admin → refinery/admin}/pages/_locale_picker.html.erb +3 -3
- data/app/views/refinery/admin/pages/_page.html.erb +48 -0
- data/app/views/{admin → refinery/admin}/pages/_page_part_field.html.erb +1 -1
- data/app/views/refinery/admin/pages/_records.html.erb +14 -0
- data/app/views/refinery/admin/pages/_sortable_list.html.erb +4 -0
- data/app/views/refinery/admin/pages/children.html.erb +1 -0
- data/app/views/refinery/admin/pages/edit.html.erb +1 -0
- data/app/views/refinery/admin/pages/index.html.erb +9 -0
- data/app/views/refinery/admin/pages/new.html.erb +1 -0
- data/app/views/refinery/admin/pages_dialogs/_page_link.html.erb +20 -0
- data/app/views/{admin → refinery/admin}/pages_dialogs/link_to.html.erb +31 -36
- data/app/views/refinery/pages/home.html.erb +1 -0
- data/app/views/refinery/pages/show.html.erb +1 -0
- data/config/locales/bg.yml +81 -73
- data/config/locales/cs.yml +71 -72
- data/config/locales/da.yml +69 -72
- data/config/locales/de.yml +69 -72
- data/config/locales/el.yml +70 -72
- data/config/locales/en.yml +88 -73
- data/config/locales/es.yml +70 -73
- data/config/locales/fi.yml +70 -73
- data/config/locales/fr.yml +69 -72
- data/config/locales/it.yml +92 -89
- data/config/locales/ja.yml +72 -0
- data/config/locales/ko.yml +83 -0
- data/config/locales/lt.yml +71 -73
- data/config/locales/lv.yml +71 -74
- data/config/locales/nb.yml +69 -72
- data/config/locales/nl.yml +68 -71
- data/config/locales/pl.yml +70 -73
- data/config/locales/pt-BR.yml +70 -73
- data/config/locales/pt-PT.yml +75 -0
- data/config/locales/rs.yml +69 -72
- data/config/locales/ru.yml +77 -96
- data/config/locales/sk.yml +69 -72
- data/config/locales/sl.yml +68 -71
- data/config/locales/sv.yml +69 -72
- data/config/locales/vi.yml +69 -72
- data/config/locales/zh-CN.yml +75 -72
- data/config/locales/zh-TW.yml +69 -72
- data/config/routes.rb +10 -5
- data/db/migrate/20100913234708_create_refinerycms_pages_schema.rb +49 -43
- data/db/seeds.rb +41 -0
- data/lib/generators/refinery/pages/pages_generator.rb +21 -0
- data/lib/generators/refinery/pages/templates/config/initializers/refinery/pages.rb.erb +44 -0
- data/lib/refinery/pages/admin/instance_methods.rb +10 -8
- data/lib/refinery/pages/configuration.rb +44 -0
- data/lib/refinery/pages/content_page_presenter.rb +33 -0
- data/lib/refinery/pages/content_presenter.rb +56 -0
- data/lib/refinery/pages/engine.rb +73 -0
- data/lib/refinery/pages/instance_methods.rb +12 -26
- data/lib/refinery/pages/page_part_section_presenter.rb +19 -0
- data/lib/refinery/pages/section_presenter.rb +69 -0
- data/lib/{pages/tabs.rb → refinery/pages/tab.rb} +0 -0
- data/lib/refinery/pages/title_section_presenter.rb +14 -0
- data/lib/refinery/pages/type.rb +17 -0
- data/lib/refinery/pages/types.rb +32 -0
- data/lib/refinery/pages.rb +55 -0
- data/lib/refinerycms-pages.rb +1 -61
- data/refinerycms-pages.gemspec +17 -118
- data/spec/factories/pages.rb +5 -0
- data/spec/helpers/refinery/pages/content_pages_helper_spec.rb +44 -0
- data/spec/lib/generators/refinery/pages/pages_generator_spec.rb +29 -0
- data/spec/lib/pages/content_page_presenter_spec.rb +43 -0
- data/spec/lib/pages/content_presenter_spec.rb +97 -0
- data/spec/lib/pages/page_part_section_presenter_spec.rb +35 -0
- data/spec/lib/pages/section_presenter_spec.rb +86 -0
- data/spec/lib/pages/title_section_presenter_spec.rb +21 -0
- data/spec/lib/pages_spec.rb +26 -0
- data/spec/models/refinery/page_spec.rb +415 -0
- data/spec/requests/refinery/admin/pages_spec.rb +581 -0
- data/spec/requests/refinery/pages_spec.rb +302 -0
- metadata +162 -153
- data/app/controllers/admin/page_parts_controller.rb +0 -24
- data/app/controllers/admin/pages_controller.rb +0 -68
- data/app/controllers/admin/pages_dialogs_controller.rb +0 -85
- data/app/controllers/pages_controller.rb +0 -33
- data/app/helpers/pages_helper.rb +0 -2
- data/app/models/page.rb +0 -391
- data/app/models/page_part.rb +0 -29
- data/app/presenters/page_presenter.rb +0 -7
- data/app/views/admin/pages/_form.html.erb +0 -61
- data/app/views/admin/pages/_form_advanced_options_seo.html.erb +0 -4
- data/app/views/admin/pages/_page.html.erb +0 -33
- data/app/views/admin/pages/_records.html.erb +0 -14
- data/app/views/admin/pages/edit.html.erb +0 -1
- data/app/views/admin/pages/index.html.erb +0 -11
- data/app/views/admin/pages/new.html.erb +0 -1
- data/app/views/admin/pages_dialogs/_page_link.html.erb +0 -14
- data/app/views/pages/home.html.erb +0 -1
- data/app/views/pages/show.html.erb +0 -1
- data/config/locales/jp.yml +0 -75
- data/config/locales/lolcat.yml +0 -76
- data/db/migrate/20101214040815_translate_page_plugin.rb +0 -29
- data/db/migrate/20101216194133_remove_cached_slug_from_pages.rb +0 -11
- data/db/migrate/20110307025652_translate_custom_title_on_pages.rb +0 -26
- data/db/migrate/20110314213540_remove_translated_fields_from_pages.rb +0 -13
- data/db/migrate/20110329080451_create_seo_meta.rb +0 -89
- data/db/seeds/pages.rb +0 -42
- data/features/manage_pages.feature +0 -48
- data/features/step_definitions/page_steps.rb +0 -72
- data/features/support/paths.rb +0 -28
- data/features/translate_pages.feature +0 -40
- data/features/visit_pages.feature +0 -68
- data/lib/gemspec.rb +0 -40
- data/lib/generators/refinerycms_pages_generator.rb +0 -8
- data/lib/pages/marketable_routes.rb +0 -12
- data/spec/models/page_spec.rb +0 -235
@@ -0,0 +1,467 @@
|
|
1
|
+
# Encoding: utf-8
|
2
|
+
|
3
|
+
module Refinery
|
4
|
+
class Page < Refinery::Core::BaseModel
|
5
|
+
extend FriendlyId
|
6
|
+
|
7
|
+
# when collecting the pages path how is each of the pages seperated?
|
8
|
+
PATH_SEPARATOR = " - "
|
9
|
+
|
10
|
+
translates :title, :menu_title, :custom_slug, :slug, :include => :seo_meta
|
11
|
+
|
12
|
+
attr_accessible :title
|
13
|
+
|
14
|
+
# Delegate SEO Attributes to globalize3 translation
|
15
|
+
seo_fields = ::SeoMeta.attributes.keys.map{|a| [a, :"#{a}="]}.flatten
|
16
|
+
delegate(*(seo_fields << {:to => :translation}))
|
17
|
+
|
18
|
+
attr_accessible :id, :deletable, :link_url, :menu_match, :meta_keywords,
|
19
|
+
:skip_to_first_child, :position, :show_in_menu, :draft,
|
20
|
+
:parts_attributes, :browser_title, :meta_description,
|
21
|
+
:parent_id, :menu_title, :created_at, :updated_at,
|
22
|
+
:page_id, :layout_template, :view_template, :custom_slug
|
23
|
+
|
24
|
+
attr_accessor :locale, :page_title, :page_menu_title # to hold temporarily
|
25
|
+
validates :title, :presence => true
|
26
|
+
|
27
|
+
# Docs for acts_as_nested_set https://github.com/collectiveidea/awesome_nested_set
|
28
|
+
# rather than :delete_all we want :destroy
|
29
|
+
acts_as_nested_set :dependent => :destroy
|
30
|
+
|
31
|
+
# Docs for friendly_id http://github.com/norman/friendly_id
|
32
|
+
friendly_id :custom_slug_or_title, :use => [:reserved, :globalize, :scoped],
|
33
|
+
:reserved_words => %w(index new session login logout users refinery admin images wymiframe),
|
34
|
+
:scope => :parent
|
35
|
+
|
36
|
+
# Docs for acts_as_indexed http://github.com/dougal/acts_as_indexed
|
37
|
+
acts_as_indexed :fields => [:title, :meta_keywords, :meta_description,
|
38
|
+
:menu_title, :browser_title, :all_page_part_content]
|
39
|
+
|
40
|
+
has_many :parts,
|
41
|
+
:foreign_key => :refinery_page_id,
|
42
|
+
:class_name => '::Refinery::PagePart',
|
43
|
+
:order => 'position ASC',
|
44
|
+
:inverse_of => :page,
|
45
|
+
:dependent => :destroy,
|
46
|
+
:include => ((:translations) if ::Refinery::PagePart.respond_to?(:translation_class))
|
47
|
+
|
48
|
+
accepts_nested_attributes_for :parts, :allow_destroy => true
|
49
|
+
|
50
|
+
before_save { |m| m.translation.save }
|
51
|
+
before_create :ensure_locale, :if => proc { ::Refinery.i18n_enabled? }
|
52
|
+
before_destroy :deletable?
|
53
|
+
after_save :reposition_parts!, :invalidate_cached_urls, :expire_page_caching
|
54
|
+
after_update :invalidate_cached_urls
|
55
|
+
after_destroy :expire_page_caching
|
56
|
+
|
57
|
+
class << self
|
58
|
+
# Live pages are 'allowed' to be shown in the frontend of your website.
|
59
|
+
# By default, this is all pages that are not set as 'draft'.
|
60
|
+
def live
|
61
|
+
where(:draft => false)
|
62
|
+
end
|
63
|
+
|
64
|
+
# With slugs scoped to the parent page we need to find a page by its full path.
|
65
|
+
# For example with about/example we would need to find 'about' and then its child
|
66
|
+
# called 'example' otherwise it may clash with another page called /example.
|
67
|
+
def find_by_path(path)
|
68
|
+
split_path = path.to_s.split('/')
|
69
|
+
page = ::Refinery::Page.by_slug(split_path.shift).first
|
70
|
+
page = page.children.by_slug(split_path.shift).first until page.nil? || split_path.empty?
|
71
|
+
|
72
|
+
page
|
73
|
+
end
|
74
|
+
|
75
|
+
# Helps to resolve the situation where you have a path and an id
|
76
|
+
# and if the path is unfriendly then a different finder method is required
|
77
|
+
# than find_by_path.
|
78
|
+
def find_by_path_or_id(path, id)
|
79
|
+
if Refinery::Pages.marketable_urls && path.present?
|
80
|
+
if path.friendly_id?
|
81
|
+
find_by_path(path)
|
82
|
+
else
|
83
|
+
find(path)
|
84
|
+
end
|
85
|
+
elsif id.present?
|
86
|
+
find(id)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Finds a page using its title. This method is necessary because pages
|
91
|
+
# are translated which means the title attribute does not exist on the
|
92
|
+
# pages table thus requiring us to find the attribute on the translations table
|
93
|
+
# and then join to the pages table again to return the associated record.
|
94
|
+
def by_title(title)
|
95
|
+
with_globalize(:title => title)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Finds a page using its slug. See by_title
|
99
|
+
def by_slug(slug)
|
100
|
+
if defined?(::Refinery::I18n)
|
101
|
+
with_globalize(:locale => Refinery::I18n.frontend_locales, :slug => slug)
|
102
|
+
else
|
103
|
+
with_globalize(:locale => ::I18n.locale, :slug => slug)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Shows all pages with :show_in_menu set to true, but it also
|
108
|
+
# rejects any page that has not been translated to the current locale.
|
109
|
+
# This works using a query against the translated content first and then
|
110
|
+
# using all of the page_ids we further filter against this model's table.
|
111
|
+
def in_menu
|
112
|
+
where(:show_in_menu => true).with_globalize
|
113
|
+
end
|
114
|
+
|
115
|
+
# Because pages are translated this can have a negative performance impact
|
116
|
+
# on your website and can introduce scaling issues. What fast_menu does is
|
117
|
+
# finds all of the columns necessary to render a +Refinery::Menu+ structure
|
118
|
+
# using only one SQL query. This has limitations, including not being able
|
119
|
+
# to access any other attributes of the pages but you can specify more columns
|
120
|
+
# by passing in an array e.g. fast_menu([:column1, :column2])
|
121
|
+
def fast_menu(columns = [])
|
122
|
+
# First, apply a filter to determine which pages to show.
|
123
|
+
pages = live.in_menu.order('lft ASC').includes(:translations)
|
124
|
+
|
125
|
+
# Now we only want to select particular columns to avoid any further queries.
|
126
|
+
# Title and menu_title are retrieved in the next block below so they are not here.
|
127
|
+
(menu_columns | columns).each do |column|
|
128
|
+
pages = pages.select(arel_table[column.to_sym])
|
129
|
+
end
|
130
|
+
|
131
|
+
# We have to get title and menu_title from the translations table.
|
132
|
+
# To avoid calling globalize3 an extra time, we get title as page_title
|
133
|
+
# and we get menu_title as page_menu_title.
|
134
|
+
# These is used in 'to_refinery_menu_item' in the Page model.
|
135
|
+
%w(title menu_title).each do |column|
|
136
|
+
pages = pages.joins(:translations).select(
|
137
|
+
"#{translation_class.table_name}.#{column} as page_#{column}"
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
pages
|
142
|
+
end
|
143
|
+
|
144
|
+
# Wrap up the logic of finding the pages based on the translations table.
|
145
|
+
def with_globalize(conditions = {})
|
146
|
+
conditions = {:locale => ::Globalize.locale}.merge(conditions)
|
147
|
+
globalized_conditions = {}
|
148
|
+
conditions.keys.each do |key|
|
149
|
+
if (translated_attribute_names.map(&:to_s) | %w(locale)).include?(key.to_s)
|
150
|
+
globalized_conditions["#{self.translation_class.table_name}.#{key}"] = conditions.delete(key)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
# A join implies readonly which we don't really want.
|
154
|
+
joins(:translations).where(globalized_conditions).where(conditions).readonly(false)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Wraps up all the checks that we need to do to figure out whether
|
158
|
+
# the current frontend locale is different to the current one set by ::I18n.locale.
|
159
|
+
# This terminates in a false if i18n extension is not defined or enabled.
|
160
|
+
def different_frontend_locale?
|
161
|
+
::Refinery.i18n_enabled? && ::Refinery::I18n.current_frontend_locale != ::I18n.locale
|
162
|
+
end
|
163
|
+
|
164
|
+
# Override this method to change which columns you want to select to render your menu.
|
165
|
+
# title and menu_title are always retrieved so omit these.
|
166
|
+
def menu_columns
|
167
|
+
%w(id depth parent_id lft rgt link_url menu_match slug)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns how many pages per page should there be when paginating pages
|
171
|
+
def per_page(dialog = false)
|
172
|
+
dialog ? Pages.pages_per_dialog : Pages.config.pages_per_admin_index
|
173
|
+
end
|
174
|
+
|
175
|
+
def expire_page_caching
|
176
|
+
begin
|
177
|
+
Rails.cache.delete_matched(/.*pages.*/)
|
178
|
+
rescue NotImplementedError
|
179
|
+
Rails.cache.clear
|
180
|
+
warn "**** [REFINERY] The cache store you are using is not compatible with Rails.cache#delete_matched - clearing entire cache instead ***"
|
181
|
+
ensure
|
182
|
+
return true # so that other callbacks process.
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Returns in cascading order: custom_slug or menu_title or title depending on
|
188
|
+
# which attribute is first found to be present for this page.
|
189
|
+
def custom_slug_or_title
|
190
|
+
if custom_slug.present?
|
191
|
+
custom_slug
|
192
|
+
elsif menu_title.present?
|
193
|
+
menu_title
|
194
|
+
else
|
195
|
+
title
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Am I allowed to delete this page?
|
200
|
+
# If a link_url is set we don't want to break the link so we don't allow them to delete
|
201
|
+
# If deletable is set to false then we don't allow this page to be deleted. These are often Refinery system pages
|
202
|
+
def deletable?
|
203
|
+
deletable && link_url.blank? and menu_match.blank?
|
204
|
+
end
|
205
|
+
|
206
|
+
# Repositions the child page_parts that belong to this page.
|
207
|
+
# This ensures that they are in the correct 0,1,2,3,4... etc order.
|
208
|
+
def reposition_parts!
|
209
|
+
reload.parts.each_with_index do |part, index|
|
210
|
+
part.update_attribute(:position, index)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Before destroying a page we check to see if it's a deletable page or not
|
215
|
+
# Refinery system pages are not deletable.
|
216
|
+
def destroy
|
217
|
+
return super if deletable?
|
218
|
+
|
219
|
+
unless Rails.env.test?
|
220
|
+
# give useful feedback when trying to delete from console
|
221
|
+
puts "This page is not deletable. Please use .destroy! if you really want it deleted "
|
222
|
+
puts "unset .link_url," if link_url.present?
|
223
|
+
puts "unset .menu_match," if menu_match.present?
|
224
|
+
puts "set .deletable to true" unless deletable
|
225
|
+
end
|
226
|
+
|
227
|
+
false
|
228
|
+
end
|
229
|
+
|
230
|
+
# If you want to destroy a page that is set to be not deletable this is the way to do it.
|
231
|
+
def destroy!
|
232
|
+
self.menu_match = nil
|
233
|
+
self.link_url = nil
|
234
|
+
self.deletable = true
|
235
|
+
|
236
|
+
destroy
|
237
|
+
end
|
238
|
+
|
239
|
+
# Used for the browser title to get the full path to this page
|
240
|
+
# It automatically prints out this page title and all of it's parent page titles joined by a PATH_SEPARATOR
|
241
|
+
def path(options = {})
|
242
|
+
# Override default options with any supplied.
|
243
|
+
options = {:reversed => true}.merge(options)
|
244
|
+
|
245
|
+
unless parent_id.nil?
|
246
|
+
parts = [title, parent.path(options)]
|
247
|
+
parts.reverse! if options[:reversed]
|
248
|
+
parts.join(PATH_SEPARATOR)
|
249
|
+
else
|
250
|
+
title
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# When this page is rendered in the navigation, where should it link?
|
255
|
+
# If a custom "link_url" is set, it uses that otherwise it defaults to a normal page URL.
|
256
|
+
# The "link_url" is often used to link to a plugin rather than a page.
|
257
|
+
#
|
258
|
+
# For example if I had a "Contact" page I don't want it to just render a contact us page
|
259
|
+
# I want it to show the Inquiries form so I can collect inquiries. So I would set the "link_url"
|
260
|
+
# to "/contact"
|
261
|
+
def url
|
262
|
+
if link_url.present?
|
263
|
+
link_url_localised?
|
264
|
+
elsif Refinery::Pages.marketable_urls
|
265
|
+
with_locale_param url_marketable
|
266
|
+
elsif to_param.present?
|
267
|
+
with_locale_param url_normal
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Adds the locale key into the URI for this page's link_url attribute, unless
|
272
|
+
# the current locale is set as the default locale.
|
273
|
+
def link_url_localised?
|
274
|
+
return link_url unless ::Refinery.i18n_enabled?
|
275
|
+
|
276
|
+
current_url = link_url
|
277
|
+
|
278
|
+
if current_url =~ %r{^/} && ::Refinery::I18n.current_frontend_locale != ::Refinery::I18n.default_frontend_locale
|
279
|
+
current_url = "/#{::Refinery::I18n.current_frontend_locale}#{current_url}"
|
280
|
+
end
|
281
|
+
|
282
|
+
current_url
|
283
|
+
end
|
284
|
+
|
285
|
+
# Add 'marketable url' attributes into this page's url.
|
286
|
+
# This sets 'path' as the nested_url value and sets 'id' to nil.
|
287
|
+
# For example, this might evaluate to /about for the "About" page.
|
288
|
+
def url_marketable
|
289
|
+
# :id => nil is important to prevent any other params[:id] from interfering with this route.
|
290
|
+
url_normal.merge(:path => nested_url, :id => nil)
|
291
|
+
end
|
292
|
+
|
293
|
+
# Returns a url suitable to be used in url_for in Rails (such as link_to).
|
294
|
+
# For example, this might evaluate to /pages/about for the "About" page.
|
295
|
+
def url_normal
|
296
|
+
{:controller => '/refinery/pages', :action => 'show', :path => nil, :id => to_param, :only_path => true}
|
297
|
+
end
|
298
|
+
|
299
|
+
# If the current locale is set to something other than the default locale
|
300
|
+
# then the :locale attribute will be set on the url hash, otherwise it won't be.
|
301
|
+
def with_locale_param(url_hash)
|
302
|
+
if self.class.different_frontend_locale?
|
303
|
+
url_hash.update(:locale => ::Refinery::I18n.current_frontend_locale)
|
304
|
+
end
|
305
|
+
url_hash
|
306
|
+
end
|
307
|
+
|
308
|
+
# Returns an array with all ancestors to_param, allow with its own
|
309
|
+
# Ex: with an About page and a Mission underneath,
|
310
|
+
# ::Refinery::Page.find('mission').nested_url would return:
|
311
|
+
#
|
312
|
+
# ['about', 'mission']
|
313
|
+
#
|
314
|
+
def nested_url
|
315
|
+
Rails.cache.fetch(url_cache_key) { uncached_nested_url }
|
316
|
+
end
|
317
|
+
|
318
|
+
def uncached_nested_url
|
319
|
+
[parent.try(:nested_url), to_param.to_s].compact.flatten
|
320
|
+
end
|
321
|
+
|
322
|
+
# Returns the string version of nested_url, i.e., the path that should be generated
|
323
|
+
# by the router
|
324
|
+
def nested_path
|
325
|
+
Rails.cache.fetch(path_cache_key) { ['', nested_url].join('/') }
|
326
|
+
end
|
327
|
+
|
328
|
+
def path_cache_key
|
329
|
+
[cache_key, 'nested_path'].join('#')
|
330
|
+
end
|
331
|
+
|
332
|
+
def url_cache_key
|
333
|
+
[cache_key, 'nested_url'].join('#')
|
334
|
+
end
|
335
|
+
|
336
|
+
def cache_key
|
337
|
+
[Refinery::Core.base_cache_key, 'page', ::I18n.locale, id].compact.join('/')
|
338
|
+
end
|
339
|
+
|
340
|
+
# Returns true if this page is "published"
|
341
|
+
def live?
|
342
|
+
not draft?
|
343
|
+
end
|
344
|
+
|
345
|
+
# Return true if this page can be shown in the navigation.
|
346
|
+
# If it's a draft or is set to not show in the menu it will return false.
|
347
|
+
def in_menu?
|
348
|
+
live? && show_in_menu?
|
349
|
+
end
|
350
|
+
|
351
|
+
def not_in_menu?
|
352
|
+
not in_menu?
|
353
|
+
end
|
354
|
+
|
355
|
+
# Returns true if this page is the home page or links to it.
|
356
|
+
def home?
|
357
|
+
link_url == '/'
|
358
|
+
end
|
359
|
+
|
360
|
+
# Returns all visible sibling pages that can be rendered for the menu
|
361
|
+
def shown_siblings
|
362
|
+
siblings.reject(&:not_in_menu?)
|
363
|
+
end
|
364
|
+
|
365
|
+
def refinery_menu_title
|
366
|
+
[page_menu_title, page_title, menu_title, title].detect(&:present?)
|
367
|
+
end
|
368
|
+
|
369
|
+
def to_refinery_menu_item
|
370
|
+
{
|
371
|
+
:id => id,
|
372
|
+
:lft => lft,
|
373
|
+
:menu_match => menu_match,
|
374
|
+
:parent_id => parent_id,
|
375
|
+
:rgt => rgt,
|
376
|
+
:title => refinery_menu_title,
|
377
|
+
:type => self.class.name,
|
378
|
+
:url => url
|
379
|
+
}
|
380
|
+
end
|
381
|
+
|
382
|
+
# Accessor method to get a page part from a page.
|
383
|
+
# Example:
|
384
|
+
#
|
385
|
+
# ::Refinery::Page.first.content_for(:body)
|
386
|
+
#
|
387
|
+
# Will return the body page part of the first page.
|
388
|
+
def content_for(part_title)
|
389
|
+
part_with_title(part_title).try(:body)
|
390
|
+
end
|
391
|
+
|
392
|
+
# Accessor method to get a page part object from a page.
|
393
|
+
# Example:
|
394
|
+
#
|
395
|
+
# ::Refinery::Page.first.part_with_title(:body)
|
396
|
+
#
|
397
|
+
# Will return the Refinery::PagePart object with that title using the first page.
|
398
|
+
def part_with_title(part_title)
|
399
|
+
# self.parts is usually already eager loaded so we can now just grab
|
400
|
+
# the first element matching the title we specified.
|
401
|
+
self.parts.detect do |part|
|
402
|
+
part.title.present? and # protecting against the problem that occurs when have nil title
|
403
|
+
part.title == part_title.to_s or
|
404
|
+
part.title.downcase.gsub(" ", "_") == part_title.to_s.downcase.gsub(" ", "_")
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
# In the admin area we use a slightly different title to inform the which pages are draft or hidden pages
|
409
|
+
# We show the title from the next available locale if there is no title for the current locale
|
410
|
+
def title_with_meta
|
411
|
+
if self.title.present?
|
412
|
+
title = [self.title]
|
413
|
+
else
|
414
|
+
title = [self.translations.detect {|t| t.title.present?}.title]
|
415
|
+
end
|
416
|
+
|
417
|
+
title << "<em>(#{::I18n.t('hidden', :scope => 'refinery.admin.pages.page')})</em>" unless show_in_menu?
|
418
|
+
title << "<em>(#{::I18n.t('draft', :scope => 'refinery.admin.pages.page')})</em>" if draft?
|
419
|
+
|
420
|
+
title.join(' ')
|
421
|
+
end
|
422
|
+
|
423
|
+
# Used to index all the content on this page so it can be easily searched.
|
424
|
+
def all_page_part_content
|
425
|
+
parts.map(&:body).join(" ")
|
426
|
+
end
|
427
|
+
|
428
|
+
##
|
429
|
+
# Protects generated slugs from title if they are in the list of reserved words
|
430
|
+
# This applies mostly to plugin-generated pages.
|
431
|
+
# This only kicks in when Refinery::Pages.marketable_urls is enabled.
|
432
|
+
#
|
433
|
+
# Returns the sluggified string
|
434
|
+
def normalize_friendly_id_with_marketable_urls(slug_string)
|
435
|
+
sluggified = slug_string.to_slug.normalize!
|
436
|
+
if Refinery::Pages.marketable_urls && self.class.friendly_id_config.reserved_words.include?(sluggified)
|
437
|
+
sluggified << "-page"
|
438
|
+
end
|
439
|
+
sluggified
|
440
|
+
end
|
441
|
+
alias_method_chain :normalize_friendly_id, :marketable_urls
|
442
|
+
|
443
|
+
private
|
444
|
+
|
445
|
+
def invalidate_cached_urls
|
446
|
+
return true unless Refinery::Pages.marketable_urls
|
447
|
+
|
448
|
+
[self, children].flatten.each do |page|
|
449
|
+
Rails.cache.delete(page.url_cache_key)
|
450
|
+
Rails.cache.delete(page.path_cache_key)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
alias_method :invalidate_child_cached_url, :invalidate_cached_urls
|
454
|
+
|
455
|
+
# Make sures that a translation exists for this page.
|
456
|
+
# The translation is set to the default frontend locale.
|
457
|
+
def ensure_locale
|
458
|
+
unless self.translations.present?
|
459
|
+
self.translations.build :locale => ::Refinery::I18n.default_frontend_locale
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
def expire_page_caching
|
464
|
+
self.class.expire_page_caching
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Refinery
|
2
|
+
class PagePart < Refinery::Core::BaseModel
|
3
|
+
|
4
|
+
attr_accessible :title, :content, :position, :body, :created_at,
|
5
|
+
:updated_at, :refinery_page_id
|
6
|
+
belongs_to :page, :foreign_key => :refinery_page_id
|
7
|
+
|
8
|
+
validates :title, :presence => true
|
9
|
+
alias_attribute :content, :body
|
10
|
+
|
11
|
+
translates :body if respond_to?(:translates)
|
12
|
+
|
13
|
+
def to_param
|
14
|
+
"page_part_#{title.downcase.gsub(/\W/, '_')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def body=(value)
|
18
|
+
super
|
19
|
+
|
20
|
+
normalise_text_fields
|
21
|
+
end
|
22
|
+
|
23
|
+
self.translation_class.send :attr_accessible, :locale if self.respond_to?(:translation_class)
|
24
|
+
|
25
|
+
protected
|
26
|
+
def normalise_text_fields
|
27
|
+
if body.present? && body !~ %r{^<}
|
28
|
+
self.body = "<p>#{body.gsub("\r\n\r\n", "</p><p>").gsub("\r\n", "<br/>")}</p>"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
|
-
<ul
|
2
|
-
<%= render :partial =>
|
1
|
+
<ul class='sortable_list'>
|
2
|
+
<%= render :partial => 'page',
|
3
|
+
:collection => @pages.select{|p| p.parent_id.nil?},
|
4
|
+
:locals => {
|
5
|
+
:collection => @pages
|
6
|
+
} %>
|
3
7
|
</ul>
|
4
|
-
<%= render
|
5
|
-
:locals => {:continue_reordering => !!local_assigns[:continue_reordering]} %>
|
8
|
+
<%= render '/refinery/admin/sortable_list', :continue_reordering => !!local_assigns[:continue_reordering] %>
|
@@ -1,17 +1,18 @@
|
|
1
1
|
<ul>
|
2
2
|
<li>
|
3
|
-
<%= render
|
3
|
+
<%= render '/refinery/admin/search', :url => refinery.admin_pages_path %>
|
4
4
|
</li>
|
5
5
|
<li>
|
6
|
-
<%= link_to t('.create_new_page'),
|
6
|
+
<%= link_to t('.create_new_page'), refinery.new_admin_page_path,
|
7
|
+
:class => "add_icon" %>
|
7
8
|
</li>
|
8
9
|
<% if @pages.many? and !searching? %>
|
9
10
|
<li>
|
10
|
-
<%= link_to t('.reorder_pages'),
|
11
|
+
<%= link_to t('.reorder_pages'), refinery.admin_pages_path,
|
11
12
|
:id => "reorder_action",
|
12
13
|
:class => "reorder_icon" %>
|
13
14
|
|
14
|
-
<%= link_to t('.reorder_pages_done'),
|
15
|
+
<%= link_to t('.reorder_pages_done'), refinery.admin_pages_path,
|
15
16
|
:id => "reorder_action_done",
|
16
17
|
:style => "display: none;",
|
17
18
|
:class => "reorder_icon" %>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<%= form_for [refinery, :admin, @page],
|
2
|
+
:url => (refinery.admin_page_path(@page.uncached_nested_url) if @page.persisted?) do |f| %>
|
3
|
+
|
4
|
+
<%= render '/refinery/admin/error_messages', :object => @page, :include_object_name => true %>
|
5
|
+
|
6
|
+
<%= render 'locale_picker', :current_locale => Globalize.locale if Refinery.i18n_enabled? %>
|
7
|
+
|
8
|
+
<div class="field">
|
9
|
+
<%= f.label :title %>
|
10
|
+
<%= f.text_field :title, :class => "larger widest" %>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<%= render 'form_fields_after_title', :f => f %>
|
14
|
+
|
15
|
+
<div class='field'>
|
16
|
+
<%= render 'form_page_parts', :f => f %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<%= render 'form_advanced_options', :f => f %>
|
20
|
+
|
21
|
+
<%= render '/refinery/admin/form_actions', :f => f,
|
22
|
+
:continue_editing => true,
|
23
|
+
:delete_title => t('delete', :scope => 'refinery.admin.pages'),
|
24
|
+
:delete_confirmation => t('message', :scope => 'refinery.admin.delete', :title => @page.title),
|
25
|
+
:before_cancel_button => submit_tag(
|
26
|
+
t('.preview'),
|
27
|
+
:id => 'preview-button',
|
28
|
+
:title => 'Preview page',
|
29
|
+
:name => nil,
|
30
|
+
:class => "wymupdate button",
|
31
|
+
:tooltip => t('.preview_changes')
|
32
|
+
) %>
|
33
|
+
|
34
|
+
<%= render 'form_new_page_parts', :f => f if Refinery::Pages.new_page_parts %>
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<% content_for :javascripts do %>
|
38
|
+
<script>
|
39
|
+
$(document).ready(function(){
|
40
|
+
page_options.init(
|
41
|
+
<%= Refinery::Pages.new_page_parts.to_s %>
|
42
|
+
, "<%= refinery.new_admin_page_part_path %>"
|
43
|
+
, "<%= refinery.admin_page_parts_path %>"
|
44
|
+
);
|
45
|
+
|
46
|
+
$("#preview-button").click(function(e) {
|
47
|
+
var form = $(this).parents('form');
|
48
|
+
var prev_url = form.attr('action');
|
49
|
+
var prev_target = form.attr('target');
|
50
|
+
form.attr({
|
51
|
+
'action': '<%= @page.persisted? ? refinery.preview_page_path(@page.uncached_nested_url) : refinery.preview_pages_path %>'
|
52
|
+
, 'target': '_blank'
|
53
|
+
});
|
54
|
+
form.submit();
|
55
|
+
form.attr({
|
56
|
+
'action': prev_url
|
57
|
+
, 'target': prev_target
|
58
|
+
});
|
59
|
+
e.preventDefault();
|
60
|
+
});
|
61
|
+
});
|
62
|
+
</script>
|
63
|
+
<% end %>
|
@@ -18,24 +18,44 @@
|
|
18
18
|
<%= f.label :parent_id, t('.parent_page') %>
|
19
19
|
<%= refinery_help_tag t('.parent_page_help') %>
|
20
20
|
</span>
|
21
|
-
<%= f.select :parent_id, nested_set_options(Page, @page) {|i| "#{'-' * i.level} #{i.title}" },
|
21
|
+
<%= f.select :parent_id, nested_set_options(::Refinery::Page, @page) {|i| "#{'-' * i.level} #{i.title}" },
|
22
22
|
:include_blank => true %>
|
23
23
|
</div>
|
24
|
+
<% if Refinery::Pages.use_layout_templates %>
|
24
25
|
<div class='field'>
|
25
26
|
<span class='label_with_help'>
|
26
|
-
<%= label_tag :
|
27
|
-
<%= refinery_help_tag t('.
|
27
|
+
<%= label_tag :layout_template, t('.layout_template') %>
|
28
|
+
<%= refinery_help_tag t('.layout_template_help') %>
|
28
29
|
</span>
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
<
|
35
|
-
|
36
|
-
<%=
|
37
|
-
</
|
30
|
+
<%= f.select(:layout_template, @valid_layout_templates) %>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
33
|
+
<% if Refinery::Pages.use_view_templates %>
|
34
|
+
<div class='field'>
|
35
|
+
<span class='label_with_help'>
|
36
|
+
<%= label_tag :view_template, t('.view_template') %>
|
37
|
+
<%= refinery_help_tag t('.view_template_help') %>
|
38
|
+
</span>
|
39
|
+
<%= f.select(:view_template, @valid_view_templates.map{|t| [t.titleize, t]}) %>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<div class='field'>
|
44
|
+
<span class='label_with_help'>
|
45
|
+
<%= label_tag :menu_title, t('.menu_title') %>
|
46
|
+
<%= refinery_help_tag t('.menu_title_help') %>
|
47
|
+
</span>
|
48
|
+
<%= f.text_field :menu_title, :style=> 'width:400px;' %>
|
49
|
+
</div>
|
50
|
+
<% if Refinery::Pages.use_custom_slugs %>
|
51
|
+
<div class='field'>
|
52
|
+
<span class='label_with_help'>
|
53
|
+
<%= f.label :custom_slug, t('.custom_slug') %>
|
54
|
+
<%= refinery_help_tag t('.custom_slug_help') %>
|
55
|
+
</span>
|
56
|
+
<%= f.text_field :custom_slug, :style=> 'width:400px;' %>
|
38
57
|
</div>
|
58
|
+
<% end %>
|
39
59
|
<div class='field'>
|
40
60
|
<span class='label_with_help'>
|
41
61
|
<%= f.label :skip_to_first_child?, t('.skip_to_first_child') %>
|
@@ -54,8 +74,8 @@
|
|
54
74
|
<% content_for :javascripts do %>
|
55
75
|
<script>
|
56
76
|
$(document).ready(function(){
|
57
|
-
link_tester.init('<%=
|
58
|
-
'<%=
|
77
|
+
link_tester.init('<%= refinery.test_url_admin_pages_dialogs_path %>',
|
78
|
+
'<%= refinery.test_email_admin_pages_dialogs_path %>');
|
59
79
|
|
60
80
|
link_tester.validate_url_textbox("#page_link_url")
|
61
81
|
});
|
@@ -74,6 +94,5 @@
|
|
74
94
|
</div>
|
75
95
|
</div>
|
76
96
|
|
77
|
-
<%= render :
|
78
|
-
:locals => {:f => f} %>
|
97
|
+
<%= render 'form_advanced_options_seo', :f => f %>
|
79
98
|
</div>
|