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.
Files changed (126) hide show
  1. data/app/controllers/refinery/admin/page_parts_controller.rb +26 -0
  2. data/app/controllers/refinery/admin/pages_controller.rb +77 -0
  3. data/app/controllers/refinery/admin/pages_dialogs_controller.rb +91 -0
  4. data/app/controllers/refinery/page_sweeper.rb +29 -0
  5. data/app/controllers/refinery/pages_controller.rb +103 -0
  6. data/app/helpers/refinery/pages/content_pages_helper.rb +26 -0
  7. data/app/helpers/refinery/pages_helper.rb +4 -0
  8. data/app/models/refinery/page.rb +467 -0
  9. data/app/models/refinery/page_part.rb +33 -0
  10. data/app/presenters/refinery/page_presenter.rb +7 -0
  11. data/app/views/admin/pages/_sortable_list.html.erb +7 -4
  12. data/app/views/{admin → refinery/admin}/pages/_actions.html.erb +5 -4
  13. data/app/views/refinery/admin/pages/_form.html.erb +63 -0
  14. data/app/views/{admin → refinery/admin}/pages/_form_advanced_options.html.erb +35 -16
  15. data/app/views/refinery/admin/pages/_form_advanced_options_seo.html.erb +3 -0
  16. data/app/views/{admin → refinery/admin}/pages/_form_fields_after_title.html.erb +0 -0
  17. data/app/views/{admin → refinery/admin}/pages/_form_new_page_parts.html.erb +5 -7
  18. data/app/views/{admin → refinery/admin}/pages/_form_page_parts.html.erb +19 -11
  19. data/app/views/{admin → refinery/admin}/pages/_locale_picker.html.erb +3 -3
  20. data/app/views/refinery/admin/pages/_page.html.erb +48 -0
  21. data/app/views/{admin → refinery/admin}/pages/_page_part_field.html.erb +1 -1
  22. data/app/views/refinery/admin/pages/_records.html.erb +14 -0
  23. data/app/views/refinery/admin/pages/_sortable_list.html.erb +4 -0
  24. data/app/views/refinery/admin/pages/children.html.erb +1 -0
  25. data/app/views/refinery/admin/pages/edit.html.erb +1 -0
  26. data/app/views/refinery/admin/pages/index.html.erb +9 -0
  27. data/app/views/refinery/admin/pages/new.html.erb +1 -0
  28. data/app/views/refinery/admin/pages_dialogs/_page_link.html.erb +20 -0
  29. data/app/views/{admin → refinery/admin}/pages_dialogs/link_to.html.erb +31 -36
  30. data/app/views/refinery/pages/home.html.erb +1 -0
  31. data/app/views/refinery/pages/show.html.erb +1 -0
  32. data/config/locales/bg.yml +81 -73
  33. data/config/locales/cs.yml +71 -72
  34. data/config/locales/da.yml +69 -72
  35. data/config/locales/de.yml +69 -72
  36. data/config/locales/el.yml +70 -72
  37. data/config/locales/en.yml +88 -73
  38. data/config/locales/es.yml +70 -73
  39. data/config/locales/fi.yml +70 -73
  40. data/config/locales/fr.yml +69 -72
  41. data/config/locales/it.yml +92 -89
  42. data/config/locales/ja.yml +72 -0
  43. data/config/locales/ko.yml +83 -0
  44. data/config/locales/lt.yml +71 -73
  45. data/config/locales/lv.yml +71 -74
  46. data/config/locales/nb.yml +69 -72
  47. data/config/locales/nl.yml +68 -71
  48. data/config/locales/pl.yml +70 -73
  49. data/config/locales/pt-BR.yml +70 -73
  50. data/config/locales/pt-PT.yml +75 -0
  51. data/config/locales/rs.yml +69 -72
  52. data/config/locales/ru.yml +77 -96
  53. data/config/locales/sk.yml +69 -72
  54. data/config/locales/sl.yml +68 -71
  55. data/config/locales/sv.yml +69 -72
  56. data/config/locales/vi.yml +69 -72
  57. data/config/locales/zh-CN.yml +75 -72
  58. data/config/locales/zh-TW.yml +69 -72
  59. data/config/routes.rb +10 -5
  60. data/db/migrate/20100913234708_create_refinerycms_pages_schema.rb +49 -43
  61. data/db/seeds.rb +41 -0
  62. data/lib/generators/refinery/pages/pages_generator.rb +21 -0
  63. data/lib/generators/refinery/pages/templates/config/initializers/refinery/pages.rb.erb +44 -0
  64. data/lib/refinery/pages/admin/instance_methods.rb +10 -8
  65. data/lib/refinery/pages/configuration.rb +44 -0
  66. data/lib/refinery/pages/content_page_presenter.rb +33 -0
  67. data/lib/refinery/pages/content_presenter.rb +56 -0
  68. data/lib/refinery/pages/engine.rb +73 -0
  69. data/lib/refinery/pages/instance_methods.rb +12 -26
  70. data/lib/refinery/pages/page_part_section_presenter.rb +19 -0
  71. data/lib/refinery/pages/section_presenter.rb +69 -0
  72. data/lib/{pages/tabs.rb → refinery/pages/tab.rb} +0 -0
  73. data/lib/refinery/pages/title_section_presenter.rb +14 -0
  74. data/lib/refinery/pages/type.rb +17 -0
  75. data/lib/refinery/pages/types.rb +32 -0
  76. data/lib/refinery/pages.rb +55 -0
  77. data/lib/refinerycms-pages.rb +1 -61
  78. data/refinerycms-pages.gemspec +17 -118
  79. data/spec/factories/pages.rb +5 -0
  80. data/spec/helpers/refinery/pages/content_pages_helper_spec.rb +44 -0
  81. data/spec/lib/generators/refinery/pages/pages_generator_spec.rb +29 -0
  82. data/spec/lib/pages/content_page_presenter_spec.rb +43 -0
  83. data/spec/lib/pages/content_presenter_spec.rb +97 -0
  84. data/spec/lib/pages/page_part_section_presenter_spec.rb +35 -0
  85. data/spec/lib/pages/section_presenter_spec.rb +86 -0
  86. data/spec/lib/pages/title_section_presenter_spec.rb +21 -0
  87. data/spec/lib/pages_spec.rb +26 -0
  88. data/spec/models/refinery/page_spec.rb +415 -0
  89. data/spec/requests/refinery/admin/pages_spec.rb +581 -0
  90. data/spec/requests/refinery/pages_spec.rb +302 -0
  91. metadata +162 -153
  92. data/app/controllers/admin/page_parts_controller.rb +0 -24
  93. data/app/controllers/admin/pages_controller.rb +0 -68
  94. data/app/controllers/admin/pages_dialogs_controller.rb +0 -85
  95. data/app/controllers/pages_controller.rb +0 -33
  96. data/app/helpers/pages_helper.rb +0 -2
  97. data/app/models/page.rb +0 -391
  98. data/app/models/page_part.rb +0 -29
  99. data/app/presenters/page_presenter.rb +0 -7
  100. data/app/views/admin/pages/_form.html.erb +0 -61
  101. data/app/views/admin/pages/_form_advanced_options_seo.html.erb +0 -4
  102. data/app/views/admin/pages/_page.html.erb +0 -33
  103. data/app/views/admin/pages/_records.html.erb +0 -14
  104. data/app/views/admin/pages/edit.html.erb +0 -1
  105. data/app/views/admin/pages/index.html.erb +0 -11
  106. data/app/views/admin/pages/new.html.erb +0 -1
  107. data/app/views/admin/pages_dialogs/_page_link.html.erb +0 -14
  108. data/app/views/pages/home.html.erb +0 -1
  109. data/app/views/pages/show.html.erb +0 -1
  110. data/config/locales/jp.yml +0 -75
  111. data/config/locales/lolcat.yml +0 -76
  112. data/db/migrate/20101214040815_translate_page_plugin.rb +0 -29
  113. data/db/migrate/20101216194133_remove_cached_slug_from_pages.rb +0 -11
  114. data/db/migrate/20110307025652_translate_custom_title_on_pages.rb +0 -26
  115. data/db/migrate/20110314213540_remove_translated_fields_from_pages.rb +0 -13
  116. data/db/migrate/20110329080451_create_seo_meta.rb +0 -89
  117. data/db/seeds/pages.rb +0 -42
  118. data/features/manage_pages.feature +0 -48
  119. data/features/step_definitions/page_steps.rb +0 -72
  120. data/features/support/paths.rb +0 -28
  121. data/features/translate_pages.feature +0 -40
  122. data/features/visit_pages.feature +0 -68
  123. data/lib/gemspec.rb +0 -40
  124. data/lib/generators/refinerycms_pages_generator.rb +0 -8
  125. data/lib/pages/marketable_routes.rb +0 -12
  126. 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
@@ -0,0 +1,7 @@
1
+ class PagePresenter < ::Refinery::BasePresenter
2
+
3
+ def menu_title_type
4
+ @model.menu_title_type
5
+ end
6
+
7
+ end
@@ -1,5 +1,8 @@
1
- <ul id='sortable_list'>
2
- <%= render :partial => "page", :collection => @pages.select{|p| p.parent_id.nil?} %>
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 :partial => "/shared/admin/sortable_list",
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 :partial => "/shared/admin/search", :locals => {:url => admin_pages_url} %>
3
+ <%= render '/refinery/admin/search', :url => refinery.admin_pages_path %>
4
4
  </li>
5
5
  <li>
6
- <%= link_to t('.create_new_page'), new_admin_page_url, :class => "add_icon" %>
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'), admin_pages_url,
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'), admin_pages_url,
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 :custom_title, t('.custom_title') %>
27
- <%= refinery_help_tag t('.custom_title_help') %>
27
+ <%= label_tag :layout_template, t('.layout_template') %>
28
+ <%= refinery_help_tag t('.layout_template_help') %>
28
29
  </span>
29
- <% %w(none text).each do |type| %>
30
- <%= f.radio_button :custom_title_type, type %>
31
- <%= label_tag "page_custom_title_type_#{type}", t(type.downcase.gsub(" ", "_"), :scope => 'admin.pages.form_advanced_options.title_types'),
32
- :class => "stripped" %>
33
- <% end %>
34
- <div id='custom_title_none'></div>
35
- <div id='custom_title_text' style='display: <%= @page.custom_title_type == 'text' ? 'block' : 'none' %>'>
36
- <%= f.text_field :custom_title, :class => 'widest' %>
37
- </div>
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('<%= test_url_admin_pages_dialogs_url %>',
58
- '<%= test_email_admin_pages_dialogs_url %>');
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 :partial => "form_advanced_options_seo",
78
- :locals => {:f => f} %>
97
+ <%= render 'form_advanced_options_seo', :f => f %>
79
98
  </div>