trusty-cms 7.0.26 → 7.0.28

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d45d76c458d982e12e398501691b9c80786772ae9a752b2476bcababf4f97ceb
4
- data.tar.gz: c5ff04b23662c3df08191e9780008c1f28b7eaffcb6f54a912dda3521f2bf22e
3
+ metadata.gz: 16753e005b09f59c333c5e9fd2af4bca3bd0e20f8d2da054500b3d262d1eecfa
4
+ data.tar.gz: c4159171a6a9f932b685cd3855bd0f931392053d4d797025e73aae1a5aa443fc
5
5
  SHA512:
6
- metadata.gz: 9b73ce6f51a809957d30ca3a51a67f2496db293b1160438608029d3a6e3ec40ea6aea40adad0d60374212a3475a508e900505b957890c486e505d47b15a3a69c
7
- data.tar.gz: 0b72e9b00f8dd0b2b5964f4d00f6d6cc085052a7c0e9635f48a6aee8325460d2890449b0a65200b490087c4b3d82c589d63987e987954c9e5278f92a4e315134
6
+ metadata.gz: 3f91892e8c3e8b0aa0e3899b7796833a4e2a0e5074eacf92f5e47b7e216559b5c4d32f487f03fb725775d960d20f0cd15cea678a0a14ef42aa65c9d07cb531c2
7
+ data.tar.gz: f5735dc96aa6cf0c3c80686f36d48cd7d49f5b8865ffd4c2d02ab708170764b5bff91a7fb525acbff932e67c76b9adcd104f35e145ee71ce61c4c897e42c597f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trusty-cms (7.0.26)
4
+ trusty-cms (7.0.28)
5
5
  RedCloth (= 4.3.3)
6
6
  activestorage-validator
7
7
  acts_as_list (>= 0.9.5, < 1.3.0)
data/README.md CHANGED
@@ -77,6 +77,23 @@ Steps:
77
77
 
78
78
  rspec
79
79
 
80
+ ### Preview Custom Page Types
81
+
82
+ TrustyCMS supports a preview feature for standard page types. However, this functionality may not work out of the box for custom page types. To enable the preview feature for your custom page types, follow these steps:
83
+
84
+ 1. In your application, create the following initializer file: `config/initializers/preview_page_types.rb`
85
+ 2. Inside this file, define a `PREVIEW_PAGE_TYPES` array constant with the names of the page types you’d like to enable the Preview button for, for example:
86
+
87
+ ```ruby
88
+ PREVIEW_PAGE_TYPES = %w[
89
+ BlogPage
90
+ FacilityPage
91
+ FileNotFoundPage
92
+ ].freeze
93
+ ```
94
+
95
+ 3. Test the Preview button with each custom page type. If a page type does not preview correctly, remove it from the list.
96
+
80
97
  ### Custom Page Type Routes Setup
81
98
  Additional configuration is required to ensure correct URL generation in the admin interface — specifically for the "Edit Page" dropdown and the "Save and View Draft" functionality.
82
99
 
@@ -106,11 +123,6 @@ DEFAULT_PAGE_TYPE_ROUTES = %w[
106
123
  ].freeze
107
124
  ```
108
125
 
109
- ### Save and View Draft Caching
110
- To ensure that pages and drafts under development are not cached by the browser or content delivery networks (such as CloudFront), the CMS appends a `trusty-no-cache` URL parameter containing the current date and time when a user selects **Save and View Draft** or **Save and View Page**.
111
-
112
- Because the `trusty-no-cache` parameter is always unique, it effectively bypasses caching mechanisms at both the CDN and browser levels, ensuring the user receives the most up-to-date version of the content with every request. Note that additional CDN configuration may be required to ensure query parameters are respected.
113
-
114
126
  ### Page Status Refresh Setup
115
127
 
116
128
  To ensure **Scheduled Pages** automatically update their status to **Published** after their designated **Publish Date & Time**, follow these steps to set up an automated refresh using **AWS Lambda** and **EventBridge**.
@@ -0,0 +1,40 @@
1
+ (function(Preview, $) {
2
+ Preview.showPreview = function(form){
3
+ var oldTarget = form.target;
4
+ var oldAction = form.action;
5
+
6
+ var $previewer = $('#preview_panel');
7
+ var $preview_tools = $previewer.find('.preview_tools');
8
+ var $frame = $('#page-preview');
9
+
10
+ $(window).scrollTop(0);
11
+ $previewer.show();
12
+ $preview_tools.css('opacity', 1);
13
+ $('body').addClass('clipped');
14
+ form.target = $frame.attr('id');
15
+ form.action = relative_url_root + '/admin/preview';
16
+ form.submit();
17
+
18
+ form.target = oldTarget;
19
+ form.action = oldAction;
20
+ }
21
+
22
+ }(window.Preview = window.Preview || {}, jQuery));
23
+
24
+ $(function () {
25
+ $('#show-preview').on('click', function(event){
26
+ event.preventDefault();
27
+ Preview.showPreview(this.form);
28
+ });
29
+
30
+ $('.preview_tools a.cancel').on('click', function(event){
31
+ event.preventDefault();
32
+ $('#preview_panel').hide();
33
+ $('body').removeClass('clipped');
34
+ $('#page-preview').attr('src', '');
35
+ });
36
+
37
+ $('iframe').on('load', function(event){
38
+ $('#preview_panel .preview_tools').css('opacity', null);
39
+ });
40
+ });
@@ -28,6 +28,7 @@
28
28
  //= require 'admin/page-edit'
29
29
  //= require 'admin/pagefield'
30
30
  //= require 'admin/popup'
31
+ //= require 'admin/preview'
31
32
  //= require 'admin/tabcontrol'
32
33
  //= require 'admin/utilities'
33
34
  //= require 'admin/tags'
@@ -3,7 +3,6 @@ class Admin::PagesController < Admin::ResourceController
3
3
  before_action :count_deleted_pages, only: [:destroy]
4
4
  before_action :set_page, only: %i[edit restore]
5
5
  rescue_from ActiveRecord::RecordInvalid, with: :validation_error
6
- include Admin::NodeHelper
7
6
  include Admin::PagesHelper
8
7
  include Admin::UrlHelper
9
8
 
@@ -43,6 +42,7 @@ class Admin::PagesController < Admin::ResourceController
43
42
  assets = Asset.order('created_at DESC')
44
43
  @term = assets.ransack(params[:search] || '')
45
44
  @page = self.model = model_class.new_with_defaults(trusty_config)
45
+ @render_preview_button = render_preview_button?
46
46
  assign_page_attributes
47
47
  response_for :new
48
48
  end
@@ -53,6 +53,7 @@ class Admin::PagesController < Admin::ResourceController
53
53
  @page_url = generate_page_url(request.url, @page)
54
54
  @page_path = format_path(@page.path)
55
55
  @versions = format_versions(@page.versions)
56
+ @render_preview_button = render_preview_button?
56
57
  response_for :edit
57
58
  end
58
59
 
@@ -62,6 +63,12 @@ class Admin::PagesController < Admin::ResourceController
62
63
  redirect_to edit_admin_page_path(@page)
63
64
  end
64
65
 
66
+ def preview
67
+ render_preview
68
+ rescue PreviewStop => e
69
+ render text: e.message unless @performed_render
70
+ end
71
+
65
72
  def save_table_position
66
73
  new_position = params[:new_position]
67
74
  Page.save_order(new_position)
@@ -152,6 +159,20 @@ class Admin::PagesController < Admin::ResourceController
152
159
  end
153
160
  end
154
161
 
162
+ def render_preview
163
+ params.permit!
164
+ Page.transaction do
165
+ page = Admin::PreviewPageBuilder.new(
166
+ model_class:,
167
+ page_params: params[:page],
168
+ referer: request.referer,
169
+ ).build
170
+
171
+ page.pagination_parameters = pagination_parameters
172
+ process_with_exception(page)
173
+ end
174
+ end
175
+
155
176
  def process_with_exception(page)
156
177
  page.process(request, response)
157
178
  @performed_render = true
@@ -177,4 +198,11 @@ class Admin::PagesController < Admin::ResourceController
177
198
  raise "I'm not allowed to constantize #{page_class}!"
178
199
  end
179
200
  end
201
+
202
+ def render_preview_button?
203
+ page_class = @page.class.name
204
+ previewable_classes = ['Page']
205
+ previewable_classes += PREVIEW_PAGE_TYPES if defined?(PREVIEW_PAGE_TYPES)
206
+ previewable_classes.include?(page_class)
207
+ end
180
208
  end
@@ -202,8 +202,6 @@ class Admin::ResourceController < ApplicationController
202
202
  end
203
203
 
204
204
  def redirect_url
205
- return "#{edit_admin_page_url(model)}?view_page=true" if params[:save_and_view]
206
-
207
205
  params[:continue] ? { action: 'edit', id: model.id } : { action: 'index' }
208
206
  end
209
207
 
@@ -1,4 +1,6 @@
1
1
  module Admin::NodeHelper
2
+ include Admin::UrlHelper
3
+
2
4
  def render_nodes(page, starting_index, parent_index = nil, simple = false)
3
5
  @rendered_html = ''
4
6
  render_node page, starting_index, parent_index, simple
@@ -25,17 +27,6 @@ module Admin::NodeHelper
25
27
  page
26
28
  end
27
29
 
28
- def format_path(path)
29
- return '' if path.nil? || path.empty?
30
-
31
- parts = path.split('/').reject(&:empty?)
32
- return 'Root' if parts.size == 1
33
- return '/' if parts.size == 2
34
-
35
- formatted_path = parts[1..-2].join('/')
36
- formatted_path.empty? ? '/' : "/#{formatted_path}"
37
- end
38
-
39
30
  def homepage
40
31
  @homepage ||= Page.find_by_parent_id(nil)
41
32
  end
@@ -1,6 +1,18 @@
1
1
  module Admin::UrlHelper
2
2
  require 'uri'
3
3
 
4
+ def format_path(path)
5
+ return '' if path.to_s.empty?
6
+
7
+ parts = path.split('/').reject(&:empty?)
8
+ parts_size = parts.size
9
+ return 'Root' if parts_size == 1
10
+ return '/' if parts_size == 2
11
+
12
+ formatted_path = parts[1..-2].join('/')
13
+ formatted_path.empty? ? '/' : "/#{formatted_path}"
14
+ end
15
+
4
16
  def generate_page_url(url, page)
5
17
  base_url = extract_base_url(url)
6
18
  build_url(base_url, page)
@@ -42,16 +42,6 @@ module ApplicationHelper
42
42
  submit_tag t('buttons.save_and_continue'), name: 'continue', class: 'button', accesskey: 's', id: 'save-and-continue-button'
43
43
  end
44
44
 
45
- def save_model_and_view_page_button(model, options = {})
46
- return nil unless generate_page_url(request.url, model)
47
-
48
- options[:label] ||= model.published? ? t('buttons.save_and_view_page') : t('buttons.save_and_view_draft')
49
- options[:class] ||= 'button'
50
- options[:name] ||= 'save_and_view'
51
- options[:id] ||= 'save-and-view-button'
52
- submit_tag options.delete(:label), options
53
- end
54
-
55
45
  def current_item?(item)
56
46
  if item.tab&.many? { |i| current_url?(i.relative_url) }
57
47
  # Accept only stricter URL matches if more than one matches
data/app/models/page.rb CHANGED
@@ -121,7 +121,7 @@ class Page < ActiveRecord::Base
121
121
  def path
122
122
  return '' if slug.blank?
123
123
 
124
- parent? ? parent.child_path(self) : clean_path(slug)
124
+ parent.present? ? clean_path("#{parent.path}/#{slug}") : clean_path(slug)
125
125
  end
126
126
 
127
127
  alias_method :url, :path
@@ -0,0 +1,54 @@
1
+ module Admin
2
+ class PreviewPageBuilder
3
+ def initialize(model_class:, page_params:, referer:)
4
+ @model_class = model_class
5
+ @page_params = page_params
6
+ @referer = referer
7
+ end
8
+
9
+ def build
10
+ editing_existing_page? ? build_existing_page : build_new_page
11
+ end
12
+
13
+ private
14
+
15
+ def build_existing_page
16
+ page = find_page_from_referer.becomes(valid_model_class)
17
+ page.update(@page_params)
18
+ page
19
+ end
20
+
21
+ def build_new_page
22
+ page = valid_model_class.new(@page_params)
23
+
24
+ if creating_child_page?
25
+ parent = find_page_from_referer
26
+ page.parent = parent
27
+ page.layout_id ||= parent.layout_id
28
+ end
29
+
30
+ page.save!
31
+ page
32
+ end
33
+
34
+ def valid_model_class
35
+ Page.descendants.include?(@model_class) ? @model_class : Page
36
+ end
37
+
38
+ def find_page_from_referer
39
+ Page.find(extract_page_id_from_referer)
40
+ end
41
+
42
+ def extract_page_id_from_referer
43
+ @referer[%r{/admin/pages/(\d+)}, 1]
44
+ end
45
+
46
+ def editing_existing_page?
47
+ @referer =~ %r{/admin/pages/\d+/edit}
48
+ end
49
+
50
+ def creating_child_page?
51
+ @referer =~ %r{/admin/pages/\d+/children/new}
52
+ end
53
+ end
54
+ end
@@ -20,7 +20,8 @@
20
20
  = render :partial => 'admin/page_fields/page_field', :collection => @page.fields
21
21
  = render_region :extended_metadata, :locals => {:f => fields}
22
22
  .drawer_handle
23
- %a.toggle{:href=>'#attributes', :rel=>'toggle[attributes]', :class=>"#{(meta_errors? ? 'less' : 'more')}"}
23
+ - toggle_class = meta_errors? ? 'less' : 'more'
24
+ %a.toggle{ href: '#attributes', rel: 'toggle[attributes]', class: toggle_class }
24
25
  = meta_label
25
26
  %i.fas.fa-angle-down
26
27
  - form.edit_page_parts do
@@ -66,32 +67,27 @@
66
67
  .error.hidden
67
68
  %span#published-at-error
68
69
 
69
- - render_region :form_bottom, :locals => {:f => fields} do |form_bottom|
70
+ - render_region :form_bottom, locals: { f: fields } do |form_bottom|
70
71
  - form_bottom.edit_buttons do
71
72
  - @buttons_partials.each do |partial|
72
- = render :partial => partial, :locals => {:f => fields}
73
+ = render partial: partial, locals: { f: fields }
74
+
73
75
  .page-actions
74
76
  = save_model_button(@page)
75
77
  = save_model_and_continue_editing_button(@page)
76
- = save_model_and_view_page_button(@page)
78
+ = submit_tag(t('preview'), class: 'button', id: 'show-preview') if @render_preview_button
77
79
  = t('or')
78
80
  = link_to t('cancel'), admin_pages_url(site_id: @site_id), class: 'alt'
79
- #view-page-url-data{ data: { url: @page_url } }
80
- - form_bottom.edit_timestamp do
81
- = updated_stamp @page
82
81
 
83
- -# Opens a new tab with the page URL when "Save and View Page" is selected
84
- :javascript
85
- document.addEventListener("DOMContentLoaded", function() {
86
- const params = new URLSearchParams(window.location.search);
87
- const dataDiv = document.getElementById("view-page-url-data");
88
- const baseUrl = dataDiv?.dataset?.url;
89
-
90
- if (params.get("view_page") === "true" && baseUrl) {
91
- const now = new Date().toISOString();
92
- const separator = baseUrl.includes("?") ? "&" : "?";
93
- const newTabUrl = `${baseUrl}${separator}trusty-no-cache=${encodeURIComponent(now)}`;
94
- window.open(newTabUrl, '_blank');
95
- }
96
- });
82
+ .fullcover.grey_out#preview_panel{ style: 'display: none;' }
83
+ %iframe.fullcover#page-preview{
84
+ name: 'page-preview',
85
+ src: "#{ActionController::Base.relative_url_root}/loading-iframe.html",
86
+ frameborder: 0,
87
+ scrolling: 'auto'
88
+ }
89
+ .preview_tools
90
+ = link_to t('edit_page'), {}, class: 'button cancel'
97
91
 
92
+ - form_bottom.edit_timestamp do
93
+ = updated_stamp(@page)
@@ -52,8 +52,6 @@ en:
52
52
  buttons:
53
53
  create: 'Create %{name}'
54
54
  save_and_continue: 'Save and Continue Editing'
55
- save_and_view_draft: 'Save and View Draft'
56
- save_and_view_page: 'Save and View Page'
57
55
  save_changes: 'Save Changes'
58
56
  cancel: 'Cancel'
59
57
  change: 'Change'
data/config/routes.rb CHANGED
@@ -41,6 +41,7 @@ TrustyCms::Application.routes.draw do
41
41
  end
42
42
  end
43
43
 
44
+ match 'admin/preview' => 'admin/pages#preview', :as => :preview, :via => %i[post put]
44
45
  get 'admin' => 'admin/pages#index'
45
46
 
46
47
  namespace :admin do
@@ -1,3 +1,3 @@
1
1
  module TrustyCms
2
- VERSION = '7.0.26'.freeze
2
+ VERSION = '7.0.28'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trusty-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.26
4
+ version: 7.0.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - TrustyCms CMS dev team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-02 00:00:00.000000000 Z
11
+ date: 2025-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activestorage-validator
@@ -702,6 +702,7 @@ files:
702
702
  - app/assets/javascripts/admin/pagefield.js
703
703
  - app/assets/javascripts/admin/persist.min.js
704
704
  - app/assets/javascripts/admin/popup.js
705
+ - app/assets/javascripts/admin/preview.js
705
706
  - app/assets/javascripts/admin/sortable.js
706
707
  - app/assets/javascripts/admin/tabcontrol.js.erb
707
708
  - app/assets/javascripts/admin/tags.js
@@ -814,6 +815,7 @@ files:
814
815
  - app/models/trusty_cms/page_response_cache_director.rb
815
816
  - app/models/user.rb
816
817
  - app/models/user_action_observer.rb
818
+ - app/services/admin/preview_page_builder.rb
817
819
  - app/views/admin/assets/_asset.html.haml
818
820
  - app/views/admin/assets/_asset_table.html.haml
819
821
  - app/views/admin/assets/_errors.html.haml