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.
- checksums.yaml +4 -4
- data/README.md +81 -15
- data/Rakefile +1 -1
- data/app/assets/javascripts/pages/admin.es6.jsx +19 -0
- data/app/assets/javascripts/pages/admin/components.es6.jsx +1 -0
- data/app/assets/javascripts/pages/admin/components/page_tree.es6.jsx +330 -0
- data/app/assets/javascripts/pages/admin/components/page_tree_actions.es6.jsx +8 -0
- data/app/assets/javascripts/pages/admin/components/page_tree_node.es6.jsx +374 -0
- data/app/assets/javascripts/pages/admin/components/page_tree_store.es6.jsx +161 -0
- data/app/assets/javascripts/pages/admin/features/content_tabs.es6.jsx +63 -0
- data/app/assets/javascripts/pages/admin/features/edit_page.es6.jsx +141 -0
- data/app/assets/javascripts/pages/admin/features/editable_image.es6.jsx +145 -0
- data/app/assets/javascripts/pages/admin/features/modal.es6.jsx +90 -0
- data/app/assets/javascripts/pages/admin/features/page_images.es6.jsx +338 -0
- data/app/assets/javascripts/pages/admin/features/rich_text.es6.jsx +124 -0
- data/app/assets/javascripts/pages/admin/features/tag_editor.es6.jsx +160 -0
- data/app/assets/javascripts/pages/admin/lib/ajax_extensions.es6.jsx +21 -0
- data/app/assets/javascripts/pages/admin/lib/center_on_screen.es6.jsx +22 -0
- data/app/assets/javascripts/pages/admin/lib/tree.es6.jsx +294 -0
- data/app/assets/javascripts/pages/login_form.es6.jsx +21 -0
- data/app/assets/stylesheets/pages/admin.scss +148 -0
- data/app/assets/stylesheets/pages/admin/components/buttons.scss +5 -0
- data/app/assets/stylesheets/pages/admin/{editable_image.css.erb → components/editable_image.scss} +7 -8
- data/app/assets/stylesheets/pages/admin/components/forms.scss +71 -0
- data/app/assets/stylesheets/pages/admin/components/header.scss +169 -0
- data/app/assets/stylesheets/pages/admin/{images.css.scss.erb → components/images.scss} +6 -11
- data/app/assets/stylesheets/pages/admin/components/layout.scss +44 -0
- data/app/assets/stylesheets/pages/admin/components/links.scss +43 -0
- data/app/assets/stylesheets/pages/admin/components/list_table.scss +58 -0
- data/app/assets/stylesheets/pages/admin/{login.css.scss.erb → components/login.scss} +1 -1
- data/app/assets/stylesheets/pages/admin/{modal.css.erb → components/modal.scss} +3 -2
- data/app/assets/stylesheets/pages/admin/components/page_tree.scss +173 -0
- data/app/assets/stylesheets/pages/admin/{pagination.css.scss → components/pagination.scss} +13 -4
- data/app/assets/stylesheets/pages/admin/components/sidebar.scss +25 -0
- data/app/assets/stylesheets/pages/admin/{tag_editor.css.scss.erb → components/tag_editor.scss} +6 -0
- data/app/assets/stylesheets/pages/admin/components/textarea.scss +76 -0
- data/app/assets/stylesheets/pages/admin/controllers/pages.scss +196 -0
- data/app/assets/stylesheets/pages/admin/controllers/{users.css.erb → users.scss} +0 -0
- data/app/assets/stylesheets/pages/admin/mixins/breakpoints.scss +21 -0
- data/app/assets/stylesheets/pages/admin/mixins/clearfix.scss +7 -0
- data/app/assets/stylesheets/pages/admin/mixins/gradients.scss +7 -0
- data/app/assets/stylesheets/pages/admin/{print.css.erb → print.scss} +0 -0
- data/app/assets/stylesheets/pages/admin/vars.scss +8 -0
- data/app/controllers/admin/invites_controller.rb +10 -6
- data/app/controllers/admin/page_files_controller.rb +6 -8
- data/app/controllers/admin/page_images_controller.rb +14 -19
- data/app/controllers/admin/pages_controller.rb +44 -97
- data/app/controllers/admin/password_resets_controller.rb +7 -2
- data/app/controllers/concerns/pages_core/add_comments_controller.rb +67 -0
- data/app/controllers/concerns/pages_core/admin/news_page_controller.rb +58 -0
- data/app/controllers/concerns/pages_core/authentication.rb +1 -1
- data/app/controllers/concerns/pages_core/exception_handler.rb +44 -21
- data/app/controllers/concerns/pages_core/policies_helper.rb +10 -6
- data/app/controllers/concerns/pages_core/preview_pages_controller.rb +43 -0
- data/app/controllers/concerns/pages_core/process_titler.rb +2 -2
- data/app/controllers/concerns/pages_core/rss_controller.rb +25 -0
- data/app/controllers/concerns/pages_core/search_pages_controller.rb +40 -0
- data/app/controllers/errors_controller.rb +14 -2
- data/app/controllers/pages_core/admin_controller.rb +7 -5
- data/app/controllers/pages_core/frontend/page_files_controller.rb +5 -7
- data/app/controllers/pages_core/frontend/pages_controller.rb +41 -219
- data/app/controllers/pages_core/frontend_controller.rb +8 -2
- data/app/controllers/pages_core/sitemaps_controller.rb +5 -4
- data/app/formatters/pages_core/html_formatter.rb +33 -23
- data/app/helpers/admin/menu_helper.rb +12 -9
- data/app/helpers/admin/pages_helper.rb +40 -28
- data/app/helpers/pages_core/admin/admin_helper.rb +58 -56
- data/app/helpers/pages_core/admin/labelled_field_helper.rb +6 -7
- data/app/helpers/pages_core/admin/tag_editor_helper.rb +11 -9
- data/app/helpers/pages_core/application_helper.rb +13 -26
- data/app/helpers/pages_core/form_builder.rb +71 -134
- data/app/helpers/pages_core/head_tags_helper.rb +26 -168
- data/app/helpers/pages_core/images_helper.rb +3 -3
- data/app/helpers/pages_core/meta_tags_helper.rb +96 -0
- data/app/helpers/pages_core/open_graph_tags_helper.rb +51 -0
- data/app/helpers/pages_core/page_path_helper.rb +40 -0
- data/app/mailers/admin_mailer.rb +14 -14
- data/app/models/autopublisher.rb +2 -2
- data/app/models/category.rb +8 -8
- data/app/models/concerns/pages_core/has_roles.rb +2 -2
- data/app/models/concerns/pages_core/humanizable_param.rb +5 -5
- data/app/models/concerns/pages_core/page_model/autopublishable.rb +25 -0
- data/app/models/concerns/pages_core/page_model/commentable.rb +29 -0
- data/app/models/concerns/pages_core/page_model/images.rb +50 -0
- data/app/models/concerns/pages_core/page_model/localizable.rb +29 -0
- data/app/models/concerns/pages_core/page_model/pathable.rb +115 -0
- data/app/models/concerns/pages_core/page_model/redirectable.rb +36 -0
- data/app/models/concerns/pages_core/page_model/searchable.rb +41 -0
- data/app/models/concerns/pages_core/page_model/sortable.rb +54 -0
- data/app/models/concerns/pages_core/page_model/status.rb +50 -0
- data/app/models/concerns/pages_core/page_model/templateable.rb +82 -0
- data/app/models/concerns/pages_core/page_model/tree.rb +108 -0
- data/app/models/page.rb +30 -212
- data/app/models/page_builder.rb +4 -6
- data/app/models/page_category.rb +7 -0
- data/app/models/page_comment.rb +1 -1
- data/app/models/page_file.rb +4 -6
- data/app/models/page_image.rb +6 -7
- data/app/models/page_path.rb +46 -0
- data/app/models/password_reset_token.rb +5 -5
- data/app/models/role.rb +1 -1
- data/app/models/tag.rb +14 -16
- data/app/models/tagging.rb +2 -1
- data/app/models/user.rb +6 -7
- data/app/policies/page_policy.rb +8 -4
- data/app/policies/user_policy.rb +1 -1
- data/app/serializers/page_tree_serializer.rb +15 -0
- data/app/views/admin/invites/new.html.erb +2 -1
- data/app/views/admin/invites/show.html.erb +3 -4
- data/app/views/admin/pages/_edit_comments.html.erb +22 -6
- data/app/views/admin/pages/_edit_content.html.erb +4 -2
- data/app/views/admin/pages/_edit_images.html.erb +86 -75
- data/app/views/admin/pages/_edit_metadata.html.erb +22 -0
- data/app/views/admin/pages/_edit_options.html.erb +23 -15
- data/app/views/admin/pages/_pagelisting.html.erb +6 -6
- data/app/views/admin/pages/edit.html.erb +11 -6
- data/app/views/admin/pages/index.html.erb +12 -53
- data/app/views/admin/pages/new.html.erb +3 -3
- data/app/views/admin/pages/news.html.erb +1 -1
- data/app/views/admin_mailer/invite.text.erb +1 -1
- data/app/views/admin_mailer/password_reset.text.erb +1 -1
- data/app/views/errors/422.html.erb +7 -0
- data/app/views/errors/500_critical.html.erb +1 -1
- data/app/views/layouts/admin.html.erb +36 -32
- data/app/views/layouts/admin/_header.html.erb +2 -2
- data/config/locales/en.yml +38 -1
- data/config/routes.rb +40 -23
- data/db/migrate/20111219033112_create_pages_tables.rb +25 -29
- data/db/migrate/20121010055412_drop_removed_tables.rb +3 -3
- data/db/migrate/20130823133208_update_page_redirect_to.rb +0 -13
- data/db/migrate/20140203183900_create_roles.rb +5 -2
- data/db/migrate/20140920231700_convert_images_to_dis.rb +4 -2
- data/db/migrate/20150401131300_localize_images.rb +7 -8
- data/db/migrate/20151002174800_create_page_paths.rb +10 -0
- data/db/migrate/20151021103400_drop_binaries_table.rb +7 -0
- data/db/migrate/20151204151000_remove_page_content_order.rb +5 -0
- data/db/migrate/20160330220900_rename_pages_categories.rb +6 -0
- data/db/migrate/20160405202700_change_localization_limit.rb +9 -0
- data/lib/pages_core.rb +22 -27
- data/lib/pages_core/admin_menu_item.rb +16 -3
- data/lib/pages_core/archive_finder.rb +40 -13
- data/lib/pages_core/cache_sweeper.rb +72 -45
- data/lib/pages_core/configuration.rb +2 -2
- data/lib/pages_core/configuration/base.rb +4 -8
- data/lib/pages_core/configuration/pages.rb +6 -3
- data/lib/pages_core/engine.rb +23 -1
- data/lib/pages_core/extensions.rb +2 -2
- data/lib/pages_core/file_embedder.rb +40 -0
- data/lib/pages_core/page_path_constraint.rb +23 -0
- data/lib/pages_core/pages_plugin.rb +11 -0
- data/lib/pages_core/paginates.rb +3 -3
- data/lib/pages_core/plugin.rb +14 -8
- data/lib/pages_core/templates.rb +6 -6
- data/lib/pages_core/templates/block_configuration.rb +1 -1
- data/lib/pages_core/templates/configuration.rb +23 -24
- data/lib/pages_core/templates/configuration_handler.rb +1 -1
- data/lib/pages_core/templates/configuration_proxy.rb +7 -11
- data/lib/pages_core/templates/template_configuration.rb +55 -61
- data/lib/pages_core/version.rb +1 -1
- data/lib/rails/generators/pages_core/install/install_generator.rb +22 -48
- data/lib/rails/generators/pages_core/install/templates/page_templates_initializer.rb +1 -1
- data/lib/rails/generators/pages_core/install/templates/pages_initializer.rb +6 -3
- data/lib/rails/generators/pages_core/rspec/rspec_generator.rb +4 -1
- data/lib/rails/generators/pages_core/rspec/templates/factories.rb +1 -1
- data/lib/tasks/pages.rake +4 -4
- data/lib/tasks/pages/page_paths.rake +12 -0
- data/template.rb +2 -2
- data/vendor/assets/javascripts/reflux.min.js +1 -0
- metadata +173 -85
- data/app/assets/images/pages/admin/description-bg.gif +0 -0
- data/app/assets/images/pages/admin/drag-handle.gif +0 -0
- data/app/assets/images/pages/admin/flash-error-bg.gif +0 -0
- data/app/assets/images/pages/admin/formelement-bg.gif +0 -0
- data/app/assets/images/pages/admin/header-tab-current-bg.gif +0 -0
- data/app/assets/images/pages/admin/list-table-td-bg.gif +0 -0
- data/app/assets/images/pages/admin/sidebar-bg.gif +0 -0
- data/app/assets/images/pages/admin/textarea_controls.gif +0 -0
- data/app/assets/javascripts/pages/admin.js.coffee +0 -54
- data/app/assets/javascripts/pages/admin/controllers/base.js.coffee +0 -4
- data/app/assets/javascripts/pages/admin/controllers/pages_controller.js.coffee +0 -139
- data/app/assets/javascripts/pages/admin/controllers/users_controller.js.coffee +0 -9
- data/app/assets/javascripts/pages/admin/features/content_tabs.js.coffee +0 -47
- data/app/assets/javascripts/pages/admin/features/editable_image.js.coffee.erb +0 -122
- data/app/assets/javascripts/pages/admin/features/modal.js.coffee +0 -66
- data/app/assets/javascripts/pages/admin/features/page_images.js +0 -329
- data/app/assets/javascripts/pages/admin/features/rich_text.js.coffee +0 -40
- data/app/assets/javascripts/pages/admin/features/tag_editor.js +0 -159
- data/app/assets/javascripts/pages/admin/lib/ajax_extensions.js.coffee +0 -17
- data/app/assets/javascripts/pages/admin/lib/center_on_screen.js.coffee +0 -21
- data/app/assets/javascripts/pages/admin/lib/jrichtextarea.js +0 -57
- data/app/assets/javascripts/pages/login_form.js.coffee +0 -17
- data/app/assets/stylesheets/pages/admin.css.erb +0 -404
- data/app/assets/stylesheets/pages/admin/buttons.css.erb +0 -5
- data/app/assets/stylesheets/pages/admin/controllers/artists.css.erb +0 -94
- data/app/assets/stylesheets/pages/admin/controllers/files.css.erb +0 -58
- data/app/assets/stylesheets/pages/admin/controllers/pages.css.scss.erb +0 -178
- data/app/assets/stylesheets/pages/admin/forms.css.scss.erb +0 -73
- data/app/assets/stylesheets/pages/admin/header.css.erb +0 -129
- data/app/assets/stylesheets/pages/admin/links.css.erb +0 -34
- data/app/assets/stylesheets/pages/admin/list_table.css.erb +0 -56
- data/app/assets/stylesheets/pages/admin/sidebar.css.erb +0 -39
- data/app/assets/stylesheets/pages/admin/sortable_images.css.erb +0 -18
- data/app/assets/stylesheets/pages/admin/textarea.css.erb +0 -55
- data/app/models/concerns/pages_core/page_tree.rb +0 -85
- data/app/models/concerns/pages_core/searchable_page.rb +0 -33
- data/app/models/concerns/pages_core/templateable.rb +0 -85
- data/app/models/localization.rb +0 -27
- data/db/migrate/20140515130100_remove_sphinx_deltas.rb +0 -15
- data/lib/pages_core/localizable.rb +0 -49
- data/lib/pages_core/localizable/active_record_extension.rb +0 -41
- data/lib/pages_core/localizable/class_methods.rb +0 -51
- data/lib/pages_core/localizable/configuration.rb +0 -50
- data/lib/pages_core/localizable/instance_methods.rb +0 -130
- data/lib/pages_core/localizable/localizer.rb +0 -72
- 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
|