pages_core 3.4.3 → 3.5.1

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.
Files changed (215) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +81 -15
  3. data/Rakefile +1 -1
  4. data/app/assets/javascripts/pages/admin.es6.jsx +19 -0
  5. data/app/assets/javascripts/pages/admin/components.es6.jsx +1 -0
  6. data/app/assets/javascripts/pages/admin/components/page_tree.es6.jsx +330 -0
  7. data/app/assets/javascripts/pages/admin/components/page_tree_actions.es6.jsx +8 -0
  8. data/app/assets/javascripts/pages/admin/components/page_tree_node.es6.jsx +374 -0
  9. data/app/assets/javascripts/pages/admin/components/page_tree_store.es6.jsx +161 -0
  10. data/app/assets/javascripts/pages/admin/features/content_tabs.es6.jsx +63 -0
  11. data/app/assets/javascripts/pages/admin/features/edit_page.es6.jsx +141 -0
  12. data/app/assets/javascripts/pages/admin/features/editable_image.es6.jsx +145 -0
  13. data/app/assets/javascripts/pages/admin/features/modal.es6.jsx +90 -0
  14. data/app/assets/javascripts/pages/admin/features/page_images.es6.jsx +338 -0
  15. data/app/assets/javascripts/pages/admin/features/rich_text.es6.jsx +124 -0
  16. data/app/assets/javascripts/pages/admin/features/tag_editor.es6.jsx +160 -0
  17. data/app/assets/javascripts/pages/admin/lib/ajax_extensions.es6.jsx +21 -0
  18. data/app/assets/javascripts/pages/admin/lib/center_on_screen.es6.jsx +22 -0
  19. data/app/assets/javascripts/pages/admin/lib/tree.es6.jsx +294 -0
  20. data/app/assets/javascripts/pages/login_form.es6.jsx +21 -0
  21. data/app/assets/stylesheets/pages/admin.scss +148 -0
  22. data/app/assets/stylesheets/pages/admin/components/buttons.scss +5 -0
  23. data/app/assets/stylesheets/pages/admin/{editable_image.css.erb → components/editable_image.scss} +7 -8
  24. data/app/assets/stylesheets/pages/admin/components/forms.scss +71 -0
  25. data/app/assets/stylesheets/pages/admin/components/header.scss +169 -0
  26. data/app/assets/stylesheets/pages/admin/{images.css.scss.erb → components/images.scss} +6 -11
  27. data/app/assets/stylesheets/pages/admin/components/layout.scss +44 -0
  28. data/app/assets/stylesheets/pages/admin/components/links.scss +43 -0
  29. data/app/assets/stylesheets/pages/admin/components/list_table.scss +58 -0
  30. data/app/assets/stylesheets/pages/admin/{login.css.scss.erb → components/login.scss} +1 -1
  31. data/app/assets/stylesheets/pages/admin/{modal.css.erb → components/modal.scss} +3 -2
  32. data/app/assets/stylesheets/pages/admin/components/page_tree.scss +173 -0
  33. data/app/assets/stylesheets/pages/admin/{pagination.css.scss → components/pagination.scss} +13 -4
  34. data/app/assets/stylesheets/pages/admin/components/sidebar.scss +25 -0
  35. data/app/assets/stylesheets/pages/admin/{tag_editor.css.scss.erb → components/tag_editor.scss} +6 -0
  36. data/app/assets/stylesheets/pages/admin/components/textarea.scss +76 -0
  37. data/app/assets/stylesheets/pages/admin/controllers/pages.scss +196 -0
  38. data/app/assets/stylesheets/pages/admin/controllers/{users.css.erb → users.scss} +0 -0
  39. data/app/assets/stylesheets/pages/admin/mixins/breakpoints.scss +21 -0
  40. data/app/assets/stylesheets/pages/admin/mixins/clearfix.scss +7 -0
  41. data/app/assets/stylesheets/pages/admin/mixins/gradients.scss +7 -0
  42. data/app/assets/stylesheets/pages/admin/{print.css.erb → print.scss} +0 -0
  43. data/app/assets/stylesheets/pages/admin/vars.scss +8 -0
  44. data/app/controllers/admin/invites_controller.rb +10 -6
  45. data/app/controllers/admin/page_files_controller.rb +6 -8
  46. data/app/controllers/admin/page_images_controller.rb +14 -19
  47. data/app/controllers/admin/pages_controller.rb +44 -97
  48. data/app/controllers/admin/password_resets_controller.rb +7 -2
  49. data/app/controllers/concerns/pages_core/add_comments_controller.rb +67 -0
  50. data/app/controllers/concerns/pages_core/admin/news_page_controller.rb +58 -0
  51. data/app/controllers/concerns/pages_core/authentication.rb +1 -1
  52. data/app/controllers/concerns/pages_core/exception_handler.rb +44 -21
  53. data/app/controllers/concerns/pages_core/policies_helper.rb +10 -6
  54. data/app/controllers/concerns/pages_core/preview_pages_controller.rb +43 -0
  55. data/app/controllers/concerns/pages_core/process_titler.rb +2 -2
  56. data/app/controllers/concerns/pages_core/rss_controller.rb +25 -0
  57. data/app/controllers/concerns/pages_core/search_pages_controller.rb +40 -0
  58. data/app/controllers/errors_controller.rb +14 -2
  59. data/app/controllers/pages_core/admin_controller.rb +7 -5
  60. data/app/controllers/pages_core/frontend/page_files_controller.rb +5 -7
  61. data/app/controllers/pages_core/frontend/pages_controller.rb +41 -219
  62. data/app/controllers/pages_core/frontend_controller.rb +8 -2
  63. data/app/controllers/pages_core/sitemaps_controller.rb +5 -4
  64. data/app/formatters/pages_core/html_formatter.rb +33 -23
  65. data/app/helpers/admin/menu_helper.rb +12 -9
  66. data/app/helpers/admin/pages_helper.rb +40 -28
  67. data/app/helpers/pages_core/admin/admin_helper.rb +58 -56
  68. data/app/helpers/pages_core/admin/labelled_field_helper.rb +6 -7
  69. data/app/helpers/pages_core/admin/tag_editor_helper.rb +11 -9
  70. data/app/helpers/pages_core/application_helper.rb +13 -26
  71. data/app/helpers/pages_core/form_builder.rb +71 -134
  72. data/app/helpers/pages_core/head_tags_helper.rb +26 -168
  73. data/app/helpers/pages_core/images_helper.rb +3 -3
  74. data/app/helpers/pages_core/meta_tags_helper.rb +96 -0
  75. data/app/helpers/pages_core/open_graph_tags_helper.rb +51 -0
  76. data/app/helpers/pages_core/page_path_helper.rb +40 -0
  77. data/app/mailers/admin_mailer.rb +14 -14
  78. data/app/models/autopublisher.rb +2 -2
  79. data/app/models/category.rb +8 -8
  80. data/app/models/concerns/pages_core/has_roles.rb +2 -2
  81. data/app/models/concerns/pages_core/humanizable_param.rb +5 -5
  82. data/app/models/concerns/pages_core/page_model/autopublishable.rb +25 -0
  83. data/app/models/concerns/pages_core/page_model/commentable.rb +29 -0
  84. data/app/models/concerns/pages_core/page_model/images.rb +50 -0
  85. data/app/models/concerns/pages_core/page_model/localizable.rb +29 -0
  86. data/app/models/concerns/pages_core/page_model/pathable.rb +115 -0
  87. data/app/models/concerns/pages_core/page_model/redirectable.rb +36 -0
  88. data/app/models/concerns/pages_core/page_model/searchable.rb +41 -0
  89. data/app/models/concerns/pages_core/page_model/sortable.rb +54 -0
  90. data/app/models/concerns/pages_core/page_model/status.rb +50 -0
  91. data/app/models/concerns/pages_core/page_model/templateable.rb +82 -0
  92. data/app/models/concerns/pages_core/page_model/tree.rb +108 -0
  93. data/app/models/page.rb +30 -212
  94. data/app/models/page_builder.rb +4 -6
  95. data/app/models/page_category.rb +7 -0
  96. data/app/models/page_comment.rb +1 -1
  97. data/app/models/page_file.rb +4 -6
  98. data/app/models/page_image.rb +6 -7
  99. data/app/models/page_path.rb +46 -0
  100. data/app/models/password_reset_token.rb +5 -5
  101. data/app/models/role.rb +1 -1
  102. data/app/models/tag.rb +14 -16
  103. data/app/models/tagging.rb +2 -1
  104. data/app/models/user.rb +6 -7
  105. data/app/policies/page_policy.rb +8 -4
  106. data/app/policies/user_policy.rb +1 -1
  107. data/app/serializers/page_tree_serializer.rb +15 -0
  108. data/app/views/admin/invites/new.html.erb +2 -1
  109. data/app/views/admin/invites/show.html.erb +3 -4
  110. data/app/views/admin/pages/_edit_comments.html.erb +22 -6
  111. data/app/views/admin/pages/_edit_content.html.erb +4 -2
  112. data/app/views/admin/pages/_edit_images.html.erb +86 -75
  113. data/app/views/admin/pages/_edit_metadata.html.erb +22 -0
  114. data/app/views/admin/pages/_edit_options.html.erb +23 -15
  115. data/app/views/admin/pages/_pagelisting.html.erb +6 -6
  116. data/app/views/admin/pages/edit.html.erb +11 -6
  117. data/app/views/admin/pages/index.html.erb +12 -53
  118. data/app/views/admin/pages/new.html.erb +3 -3
  119. data/app/views/admin/pages/news.html.erb +1 -1
  120. data/app/views/admin_mailer/invite.text.erb +1 -1
  121. data/app/views/admin_mailer/password_reset.text.erb +1 -1
  122. data/app/views/errors/422.html.erb +7 -0
  123. data/app/views/errors/500_critical.html.erb +1 -1
  124. data/app/views/layouts/admin.html.erb +36 -32
  125. data/app/views/layouts/admin/_header.html.erb +2 -2
  126. data/config/locales/en.yml +38 -1
  127. data/config/routes.rb +40 -23
  128. data/db/migrate/20111219033112_create_pages_tables.rb +25 -29
  129. data/db/migrate/20121010055412_drop_removed_tables.rb +3 -3
  130. data/db/migrate/20130823133208_update_page_redirect_to.rb +0 -13
  131. data/db/migrate/20140203183900_create_roles.rb +5 -2
  132. data/db/migrate/20140920231700_convert_images_to_dis.rb +4 -2
  133. data/db/migrate/20150401131300_localize_images.rb +7 -8
  134. data/db/migrate/20151002174800_create_page_paths.rb +10 -0
  135. data/db/migrate/20151021103400_drop_binaries_table.rb +7 -0
  136. data/db/migrate/20151204151000_remove_page_content_order.rb +5 -0
  137. data/db/migrate/20160330220900_rename_pages_categories.rb +6 -0
  138. data/db/migrate/20160405202700_change_localization_limit.rb +9 -0
  139. data/lib/pages_core.rb +22 -27
  140. data/lib/pages_core/admin_menu_item.rb +16 -3
  141. data/lib/pages_core/archive_finder.rb +40 -13
  142. data/lib/pages_core/cache_sweeper.rb +72 -45
  143. data/lib/pages_core/configuration.rb +2 -2
  144. data/lib/pages_core/configuration/base.rb +4 -8
  145. data/lib/pages_core/configuration/pages.rb +6 -3
  146. data/lib/pages_core/engine.rb +23 -1
  147. data/lib/pages_core/extensions.rb +2 -2
  148. data/lib/pages_core/file_embedder.rb +40 -0
  149. data/lib/pages_core/page_path_constraint.rb +23 -0
  150. data/lib/pages_core/pages_plugin.rb +11 -0
  151. data/lib/pages_core/paginates.rb +3 -3
  152. data/lib/pages_core/plugin.rb +14 -8
  153. data/lib/pages_core/templates.rb +6 -6
  154. data/lib/pages_core/templates/block_configuration.rb +1 -1
  155. data/lib/pages_core/templates/configuration.rb +23 -24
  156. data/lib/pages_core/templates/configuration_handler.rb +1 -1
  157. data/lib/pages_core/templates/configuration_proxy.rb +7 -11
  158. data/lib/pages_core/templates/template_configuration.rb +55 -61
  159. data/lib/pages_core/version.rb +1 -1
  160. data/lib/rails/generators/pages_core/install/install_generator.rb +22 -48
  161. data/lib/rails/generators/pages_core/install/templates/page_templates_initializer.rb +1 -1
  162. data/lib/rails/generators/pages_core/install/templates/pages_initializer.rb +6 -3
  163. data/lib/rails/generators/pages_core/rspec/rspec_generator.rb +4 -1
  164. data/lib/rails/generators/pages_core/rspec/templates/factories.rb +1 -1
  165. data/lib/tasks/pages.rake +4 -4
  166. data/lib/tasks/pages/page_paths.rake +12 -0
  167. data/template.rb +2 -2
  168. data/vendor/assets/javascripts/reflux.min.js +1 -0
  169. metadata +173 -85
  170. data/app/assets/images/pages/admin/description-bg.gif +0 -0
  171. data/app/assets/images/pages/admin/drag-handle.gif +0 -0
  172. data/app/assets/images/pages/admin/flash-error-bg.gif +0 -0
  173. data/app/assets/images/pages/admin/formelement-bg.gif +0 -0
  174. data/app/assets/images/pages/admin/header-tab-current-bg.gif +0 -0
  175. data/app/assets/images/pages/admin/list-table-td-bg.gif +0 -0
  176. data/app/assets/images/pages/admin/sidebar-bg.gif +0 -0
  177. data/app/assets/images/pages/admin/textarea_controls.gif +0 -0
  178. data/app/assets/javascripts/pages/admin.js.coffee +0 -54
  179. data/app/assets/javascripts/pages/admin/controllers/base.js.coffee +0 -4
  180. data/app/assets/javascripts/pages/admin/controllers/pages_controller.js.coffee +0 -139
  181. data/app/assets/javascripts/pages/admin/controllers/users_controller.js.coffee +0 -9
  182. data/app/assets/javascripts/pages/admin/features/content_tabs.js.coffee +0 -47
  183. data/app/assets/javascripts/pages/admin/features/editable_image.js.coffee.erb +0 -122
  184. data/app/assets/javascripts/pages/admin/features/modal.js.coffee +0 -66
  185. data/app/assets/javascripts/pages/admin/features/page_images.js +0 -329
  186. data/app/assets/javascripts/pages/admin/features/rich_text.js.coffee +0 -40
  187. data/app/assets/javascripts/pages/admin/features/tag_editor.js +0 -159
  188. data/app/assets/javascripts/pages/admin/lib/ajax_extensions.js.coffee +0 -17
  189. data/app/assets/javascripts/pages/admin/lib/center_on_screen.js.coffee +0 -21
  190. data/app/assets/javascripts/pages/admin/lib/jrichtextarea.js +0 -57
  191. data/app/assets/javascripts/pages/login_form.js.coffee +0 -17
  192. data/app/assets/stylesheets/pages/admin.css.erb +0 -404
  193. data/app/assets/stylesheets/pages/admin/buttons.css.erb +0 -5
  194. data/app/assets/stylesheets/pages/admin/controllers/artists.css.erb +0 -94
  195. data/app/assets/stylesheets/pages/admin/controllers/files.css.erb +0 -58
  196. data/app/assets/stylesheets/pages/admin/controllers/pages.css.scss.erb +0 -178
  197. data/app/assets/stylesheets/pages/admin/forms.css.scss.erb +0 -73
  198. data/app/assets/stylesheets/pages/admin/header.css.erb +0 -129
  199. data/app/assets/stylesheets/pages/admin/links.css.erb +0 -34
  200. data/app/assets/stylesheets/pages/admin/list_table.css.erb +0 -56
  201. data/app/assets/stylesheets/pages/admin/sidebar.css.erb +0 -39
  202. data/app/assets/stylesheets/pages/admin/sortable_images.css.erb +0 -18
  203. data/app/assets/stylesheets/pages/admin/textarea.css.erb +0 -55
  204. data/app/models/concerns/pages_core/page_tree.rb +0 -85
  205. data/app/models/concerns/pages_core/searchable_page.rb +0 -33
  206. data/app/models/concerns/pages_core/templateable.rb +0 -85
  207. data/app/models/localization.rb +0 -27
  208. data/db/migrate/20140515130100_remove_sphinx_deltas.rb +0 -15
  209. data/lib/pages_core/localizable.rb +0 -49
  210. data/lib/pages_core/localizable/active_record_extension.rb +0 -41
  211. data/lib/pages_core/localizable/class_methods.rb +0 -51
  212. data/lib/pages_core/localizable/configuration.rb +0 -50
  213. data/lib/pages_core/localizable/instance_methods.rb +0 -130
  214. data/lib/pages_core/localizable/localizer.rb +0 -72
  215. data/lib/pages_core/localizable/scope_extension.rb +0 -22
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Localizable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ localizable do
10
+ attribute :name
11
+ attribute :body
12
+ attribute :excerpt
13
+ attribute :headline
14
+ attribute :boxout
15
+
16
+ attribute :path_segment
17
+ attribute :meta_title
18
+ attribute :meta_description
19
+ attribute :open_graph_title
20
+ attribute :open_graph_description
21
+
22
+ dictionary(lambda do
23
+ PagesCore::Templates::TemplateConfiguration.all_blocks
24
+ end)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Pathable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ has_many :page_paths, dependent: :destroy
10
+
11
+ validates :path_segment, format: { with: /\A[[[:alnum:]]\-_]*\z/ }
12
+ validate :path_segment_cannot_be_routable
13
+ before_validation :ensure_no_path_segment_on_deletion
14
+ after_save :ensure_path_segment
15
+ after_save :associate_page_path
16
+ end
17
+
18
+ def full_path(last_segment = nil)
19
+ last_segment ||= path_segment
20
+ return nil unless full_path?(last_segment)
21
+ if parent
22
+ [parent.full_path, last_segment].join("/")
23
+ else
24
+ last_segment
25
+ end
26
+ end
27
+
28
+ def full_path?(last_segment = nil)
29
+ last_segment ||= path_segment
30
+ if parent
31
+ parent.full_path? && !last_segment.blank?
32
+ else
33
+ !last_segment.blank?
34
+ end
35
+ end
36
+
37
+ def ensure_path_segment
38
+ return if deleted? || path_segment? || !name?
39
+ if path_collision?(generated_path_segment)
40
+ update path_segment: "#{generated_path_segment}-#{id}"
41
+ else
42
+ update path_segment: generated_path_segment
43
+ end
44
+ end
45
+
46
+ def pathable?
47
+ return true unless parent
48
+ parent.full_path?
49
+ end
50
+
51
+ private
52
+
53
+ def associate_page_path
54
+ return if deleted? || !full_path?
55
+ PagePath.build(self)
56
+ end
57
+
58
+ def ensure_no_path_segment_on_deletion
59
+ return unless deleted?
60
+ self.path_segment = nil
61
+ end
62
+
63
+ def generated_path_segment
64
+ name.gsub(/[^[[:alnum:]]\-_]+/, "-")
65
+ .gsub(/[\-]{2,}/, "-")
66
+ .gsub(/(^\-|\-$)/, "")
67
+ .mb_chars
68
+ .downcase
69
+ end
70
+
71
+ def page_path_matches_routes?(page_path)
72
+ [
73
+ "/#{page_path}",
74
+ "/#{I18n.default_locale}/#{page_path}"
75
+ ].map { |p| recognizable_route?(p) }.any?
76
+ end
77
+
78
+ def page_path_route?(route)
79
+ route[:controller] == "pages" &&
80
+ route[:action] == "show" &&
81
+ !route[:path].blank?
82
+ end
83
+
84
+ def path_collision?(path_segment)
85
+ sibling_path_segments.include?(path_segment) ||
86
+ page_path_matches_routes?(full_path(path_segment))
87
+ end
88
+
89
+ def path_segment_cannot_be_routable
90
+ return unless full_path?
91
+ return unless page_path_matches_routes?(full_path)
92
+ errors.add(:path_segment, "can't match an existing URL")
93
+ end
94
+
95
+ def recognizable_route?(path)
96
+ route = Rails.application.routes.recognize_path(path)
97
+ !page_path_route?(route)
98
+ rescue ActionController::RoutingError
99
+ false
100
+ end
101
+
102
+ def sibling_path_segments
103
+ siblings = if parent
104
+ parent.children
105
+ else
106
+ self.class.roots
107
+ end
108
+ siblings.reject { |p| p == self }
109
+ .map { |p| p.localize(locale) }
110
+ .map(&:path_segment)
111
+ .reject(&:blank?)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ class InvalidRedirectUrl < StandardError; end
6
+
7
+ module Redirectable
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ validates(:redirect_to,
12
+ format: { with: %r{\A(/|https?://).+\z},
13
+ allow_nil: true,
14
+ allow_blank: true })
15
+ end
16
+
17
+ # Returns boolean true if page has a valid redirect
18
+ def redirects?
19
+ redirect_to?
20
+ end
21
+
22
+ def redirect_path(params = {})
23
+ path = redirect_to.dup
24
+ if path.start_with? "/"
25
+ params.each do |key, value|
26
+ unless value.is_a?(String) || value.is_a?(Symbol)
27
+ raise InvalidRedirectUrl, "must be a string or a symbol"
28
+ end
29
+ path.gsub!("/:#{key}", "/#{value}")
30
+ end
31
+ end
32
+ path
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Searchable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ after_save ThinkingSphinx::RealTime.callback_for(:page)
10
+ end
11
+
12
+ def localization_values
13
+ localizations.map(&:value)
14
+ end
15
+
16
+ def category_names
17
+ categories.map(&:name)
18
+ end
19
+
20
+ def comment_names
21
+ comments.map(&:name)
22
+ end
23
+
24
+ def comment_bodies
25
+ comments.map(&:body)
26
+ end
27
+
28
+ def file_names
29
+ files.map(&:name)
30
+ end
31
+
32
+ def file_filenames
33
+ files.map(&:filename)
34
+ end
35
+
36
+ def published
37
+ published?
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Sortable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ acts_as_list scope: :parent_page
10
+ after_save :check_list_position
11
+ end
12
+
13
+ module ClassMethods
14
+ def order_by_tags(tags)
15
+ joins(
16
+ "LEFT JOIN taggings ON taggings.taggable_id = pages.id AND " \
17
+ "taggable_type = #{ActiveRecord::Base.connection.quote('Page')}",
18
+ "LEFT JOIN tags ON tags.id = taggings.tag_id AND tags.id IN (" +
19
+ tags.map(&:id).join(",") +
20
+ ")"
21
+ )
22
+ .group("pages.id, localizations.id")
23
+ .reorder("COUNT(tags.id) DESC, position ASC")
24
+ end
25
+ end
26
+
27
+ def reorderable_children?
28
+ !news_page?
29
+ end
30
+
31
+ def reorderable?
32
+ !parent || !parent.news_page?
33
+ end
34
+
35
+ def content_order
36
+ if news_page?
37
+ "pages.pinned DESC, published_at DESC"
38
+ else
39
+ "position ASC"
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def check_list_position
46
+ if deleted?
47
+ remove_from_list
48
+ elsif !position?
49
+ assume_bottom_position
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Status
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def status_labels
10
+ {
11
+ 0 => "Draft",
12
+ 1 => "Reviewed",
13
+ 2 => "Published",
14
+ 3 => "Hidden",
15
+ 4 => "Deleted"
16
+ }
17
+ end
18
+ end
19
+
20
+ # Return the status of the page as a string
21
+ def status_label
22
+ self.class.status_labels[status]
23
+ end
24
+
25
+ def flag_as_deleted!
26
+ update(status: 4)
27
+ end
28
+
29
+ def draft?
30
+ status == 0
31
+ end
32
+
33
+ def reviewed?
34
+ status == 1
35
+ end
36
+
37
+ def published?
38
+ status == 2 && !autopublish?
39
+ end
40
+
41
+ def hidden?
42
+ status == 3
43
+ end
44
+
45
+ def deleted?
46
+ status == 4
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Templateable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_validation :ensure_template
10
+ end
11
+
12
+ def template_config
13
+ PagesCore::Templates::TemplateConfiguration.new(template)
14
+ end
15
+
16
+ def template
17
+ return self[:template] unless self[:template].blank?
18
+ inherited_or_default_template
19
+ end
20
+
21
+ def default_subtemplate
22
+ template_config.value(:sub_template) ||
23
+ default_template ||
24
+ subtemplate_with_postfix ||
25
+ singularized_subtemplate ||
26
+ template
27
+ end
28
+
29
+ private
30
+
31
+ def singularized_subtemplate
32
+ singularized = ActiveSupport::Inflector.singularize(base_template)
33
+ return if base_template == singularized
34
+ find_template_by_expression(
35
+ Regexp.new("^" + Regexp.quote(singularized))
36
+ )
37
+ end
38
+
39
+ def subtemplate_with_postfix
40
+ find_template_by_expression(
41
+ Regexp.new(
42
+ "^" + Regexp.quote(base_template) + "_?(post|page|subpage|item)"
43
+ )
44
+ )
45
+ end
46
+
47
+ def base_template
48
+ template.split(/_/)
49
+ .reject { |w| %w(index list archive liste arkiv).include?(w) }
50
+ .join(" ")
51
+ end
52
+
53
+ def default_template
54
+ configured = PagesCore::Templates.configuration.get(
55
+ :default, :template, :value
56
+ )
57
+ configured if configured != :autodetect
58
+ end
59
+
60
+ def find_template_by_expression(expr)
61
+ PagesCore::Templates.names
62
+ .select { |t| t.match(expr) }
63
+ .try(&:first)
64
+ end
65
+
66
+ def default_template_options
67
+ PagesCore::Templates.configuration.get(
68
+ :default, :template, :options
69
+ ) || {}
70
+ end
71
+
72
+ def inherited_or_default_template
73
+ return parent.default_subtemplate.to_s if parent
74
+ (default_template_options[:root] || default_template || :index).to_s
75
+ end
76
+
77
+ def ensure_template
78
+ self[:template] ||= inherited_or_default_template
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,108 @@
1
+ # encoding: utf-8
2
+
3
+ module PagesCore
4
+ module PageModel
5
+ module Tree
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ belongs_to :parent,
10
+ class_name: "Page",
11
+ foreign_key: :parent_page_id,
12
+ inverse_of: :children
13
+
14
+ has_many :children,
15
+ class_name: "Page",
16
+ foreign_key: :parent_page_id,
17
+ inverse_of: :parent,
18
+ dependent: :destroy
19
+
20
+ # This must be included after the belongs_to call in order
21
+ # to override the .parent method.
22
+ include PagesCore::PageModel::Tree::InstanceMethods
23
+ end
24
+
25
+ module ClassMethods
26
+ # Returns all root pages
27
+ def roots
28
+ where(parent_page_id: nil).order("position ASC")
29
+ end
30
+
31
+ # Returns the first root page
32
+ def root
33
+ roots.first
34
+ end
35
+ end
36
+
37
+ module InstanceMethods
38
+ # Returns list of ancestors, starting from parent until root.
39
+ #
40
+ # subchild1.ancestors # => [child1, root]
41
+ def ancestors
42
+ node = self
43
+ nodes = []
44
+ nodes << node = node.parent while node.parent
45
+ nodes
46
+ end
47
+
48
+ # Returns all children, recursively
49
+ def all_subpages
50
+ return nil unless subpages.any?
51
+ localized_subpages.map { |p| [p, p.all_subpages] }.flatten.compact
52
+ end
53
+
54
+ def localized_subpages
55
+ return subpages unless locale?
56
+ subpages.localized(locale)
57
+ end
58
+
59
+ # Finds the page's next sibling. Returns nil if there isn't one.
60
+ def next_sibling
61
+ return unless siblings.any?
62
+ siblings[(siblings.index(self) + 1)...siblings.length].try(&:first)
63
+ end
64
+
65
+ # Returns the pages parent
66
+ def parent
67
+ super.try { |node| node.localize(locale) }
68
+ end
69
+
70
+ # Get subpages
71
+ def pages(_options = nil)
72
+ localized_subpages.published
73
+ end
74
+
75
+ # Finds the page's next sibling. Returns nil if there isn't one.
76
+ def previous_sibling
77
+ return unless siblings.any?
78
+ siblings[0...siblings.index(self)].try(&:last)
79
+ end
80
+
81
+ # Returns the root node of the tree.
82
+ def root
83
+ self_and_ancestors.last
84
+ end
85
+
86
+ # Returns ancestors and current node itself.
87
+ #
88
+ # subchild1.self_and_ancestors # => [subchild1, child1, root]
89
+ def self_and_ancestors
90
+ [self] + ancestors
91
+ end
92
+
93
+ # Returns all siblings, including self.
94
+ def siblings
95
+ if parent
96
+ parent.pages
97
+ else
98
+ self.class.roots.map { |node| node.localize(locale) }
99
+ end
100
+ end
101
+
102
+ def subpages
103
+ children.order(content_order)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end