<% end %>
diff --git a/core/config/locales/en.yml b/core/config/locales/en.yml
index 3ba67fa2607..9fc630ec862 100644
--- a/core/config/locales/en.yml
+++ b/core/config/locales/en.yml
@@ -43,7 +43,9 @@ en:
change: Click here to pick an image
show: Show
locale_picker:
- language: Language
+ language: Language,
+ edit_in_locale: Edit in '%{locale_code}'
+ edit_in_language: Edit in %{language}
resource_picker:
download_current: Download current file
opens_in_new_window: Opens in a new window
diff --git a/core/lib/generators/refinery/cms/cms_generator.rb b/core/lib/generators/refinery/cms/cms_generator.rb
index b4a86e645d1..9c110cee27a 100644
--- a/core/lib/generators/refinery/cms/cms_generator.rb
+++ b/core/lib/generators/refinery/cms/cms_generator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'pathname'
require 'mkmf'
@@ -5,18 +7,18 @@ module Refinery
class CmsGenerator < Rails::Generators::Base
source_root Pathname.new(File.expand_path('../templates', __FILE__))
- class_option :update, :type => :boolean, :aliases => nil, :group => :runtime,
- :desc => "Update an existing Refinery CMS based application"
- class_option :fresh_installation, :type => :boolean, :aliases => nil, :group => :runtime, :default => false,
- :desc => "Allow Refinery to remove default Rails files in a fresh installation"
- class_option :heroku, :type => :string, :default => nil, :group => :runtime, :banner => 'APP_NAME',
- :desc => "Deploy to Heroku after the generator has run."
- class_option :stack, :type => :string, :default => 'cedar-14', :group => :runtime,
- :desc => "Specify which Heroku stack you want to use. Requires --heroku option to function."
- class_option :skip_db, :type => :boolean, :default => false, :aliases => nil, :group => :runtime,
- :desc => "Skip over any database creation, migration or seeding."
- class_option :skip_migrations, :type => :boolean, :default => false, :aliases => nil, :group => :runtime,
- :desc => "Skip over installing or running migrations."
+ class_option :update, type: :boolean, aliases: nil, group: :runtime,
+ desc: "Update an existing Refinery CMS based application"
+ class_option :fresh_installation, type: :boolean, aliases: nil, group: :runtime, default: false,
+ desc: "Allow Refinery to remove default Rails files in a fresh installation"
+ class_option :heroku, type: :string, default: nil, group: :runtime, banner: 'APP_NAME',
+ desc: "Deploy to Heroku after the generator has run."
+ class_option :stack, type: :string, default: 'cedar-14', group: :runtime,
+ desc: "Specify which Heroku stack you want to use. Requires --heroku option to function."
+ class_option :skip_db, type: :boolean, default: false, aliases: nil, group: :runtime,
+ desc: "Skip over any database creation, migration or seeding."
+ class_option :skip_migrations, type: :boolean, default: false, aliases: nil, group: :runtime,
+ desc: "Skip over installing or running migrations."
def generate
start_pretending?
@@ -55,7 +57,7 @@ def append_asset_pipeline!
if destination_path.join(application_css).file?
insert_into_file application_css, %q{*= require refinery/formatting
*= require refinery/theme
- }, :before => "*= require_self"
+ }, before: "*= require_self"
end
end
@@ -215,10 +217,10 @@ def ensure_environments_are_sane!
" end"
].join("\n")
- gsub_file env, current_mailer_config, new_mailer_config, :verbose => false
+ gsub_file env, current_mailer_config, new_mailer_config, verbose: false
end
- gsub_file env, "config.assets.compile = false", "config.assets.compile = true", :verbose => false
+ gsub_file env, "config.assets.compile = false", "config.assets.compile = true", verbose: false
end
end
@@ -253,7 +255,7 @@ def manage_roadblocks!
%w(public/index.html app/views/layouts/application.html.erb).each do |roadblock|
if (roadblock_path = destination_path.join(roadblock)).file?
if self.options[:fresh_installation]
- remove_file roadblock_path, :verbose => true
+ remove_file roadblock_path, verbose: true
else
say_status :"-- You may need to remove '#{roadblock}' for Refinery to function properly --", nil, :yellow
end
@@ -329,7 +331,7 @@ def start_pretending?
# Only pretend to do the next actions if this is Refinery to stay DRY
if destination_path == Refinery.root
say_status :'-- pretending to make changes that happen in an actual installation --', nil, :yellow
- old_pretend = self.options[:pretend]
+ self.old_pretend = self.options[:pretend]
new_options = self.options.dup
new_options[:pretend] = true
self.options = new_options
@@ -340,10 +342,12 @@ def stop_pretending?
# Stop pretending
if destination_path == Refinery.root
say_status :'-- finished pretending --', nil, :yellow
- new_options = self.options.dup
+ new_options = options.dup.merge(pretend: old_pretend)
new_options[:pretend] = old_pretend
self.options = new_options
end
end
+
+ private attr_accessor :old_pretend
end
end
diff --git a/core/lib/generators/refinery/dummy/dummy_generator.rb b/core/lib/generators/refinery/dummy/dummy_generator.rb
index 80a9556f69b..805ba3ba11b 100644
--- a/core/lib/generators/refinery/dummy/dummy_generator.rb
+++ b/core/lib/generators/refinery/dummy/dummy_generator.rb
@@ -13,9 +13,22 @@ def self.source_paths
paths.flatten
end
+
PASSTHROUGH_OPTIONS = [
- :skip_active_record, :skip_javascript, :skip_action_cable, :skip_action_mailer, :skip_active_storage, :database,
- :javascript, :quiet, :pretend, :force, :skip
+ :database,
+ :force,
+ :pretend,
+ :quiet,
+ :skip,
+ :skip_action_cable,
+ :skip_action_mailbox,
+ :skip_action_mailer,
+ :skip_action_text,
+ :skip_active_job,
+ :skip_active_record,
+ :skip_active_storage,
+ :skip_hotwire,
+ :skip_javascript
]
def generate_test_dummy
@@ -24,8 +37,12 @@ def generate_test_dummy
opts[:force] = true
opts[:skip_bundle] = true
opts[:skip_action_cable] = true
+ opts[:skip_action_mailbox] = true
opts[:skip_action_mailer] = true
+ opts[:skip_action_text] = true
+ opts[:skip_active_job] = true
opts[:skip_active_storage] = true
+ opts[:skip_hotwire] = true
opts[:skip_javascript] = true
invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], opts
@@ -34,14 +51,16 @@ def generate_test_dummy
def test_dummy_config
@database = options[:database]
- template "rails/database.yml", "#{dummy_path}/config/database.yml", :force => true
- template "rails/boot.rb.erb", "#{dummy_path}/config/boot.rb", :force => true
- template "rails/application.rb.erb", "#{dummy_path}/config/application.rb", :force => true
- template "rails/routes.rb", "#{dummy_path}/config/routes.rb", :force => true
- template "rails/Rakefile", "#{dummy_path}/Rakefile", :force => true
- template "rails/application.js", "#{dummy_path}/app/assets/javascripts/application.js", :force => true
- template 'rails/blank.png', "#{dummy_path}/public/apple-touch-icon.png", :force => true
- template 'rails/blank.png', "#{dummy_path}/public/apple-touch-icon-precomposed.png", :force => true
+ template "rails/database.yml", "#{dummy_path}/config/database.yml", force: true
+ template "rails/boot.rb.erb", "#{dummy_path}/config/boot.rb", force: true
+ template "rails/application.rb.erb", "#{dummy_path}/config/application.rb", force: true
+ template "rails/routes.rb", "#{dummy_path}/config/routes.rb", force: true
+ template "rails/storage.yml", "#{dummy_path}/config/storage.yml", force: true
+ template "rails/Rakefile", "#{dummy_path}/Rakefile", force: true
+ template "rails/application.js", "#{dummy_path}/app/assets/javascripts/application.js", force: true
+ template "rails/manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true
+ template 'rails/blank.png', "#{dummy_path}/public/apple-touch-icon.png", force: true
+ template 'rails/blank.png', "#{dummy_path}/public/apple-touch-icon-precomposed.png", force: true
end
def test_dummy_clean
diff --git a/core/lib/generators/refinery/dummy/templates/rails/application.rb.erb b/core/lib/generators/refinery/dummy/templates/rails/application.rb.erb
index d65a67e71a4..85980852c18 100644
--- a/core/lib/generators/refinery/dummy/templates/rails/application.rb.erb
+++ b/core/lib/generators/refinery/dummy/templates/rails/application.rb.erb
@@ -1,6 +1,13 @@
require File.expand_path('../boot', __FILE__)
-require 'rails/all'
+begin
+ require 'rails/all'
+rescue NameError => e
+ raise unless e.message.include?("ActiveSupport::LoggerThreadSafeLevel::Logger")
+
+ require "logger"
+ retry
+end
require 'refinerycms/core'
# Require the gems listed in Gemfile, including any gems
@@ -10,7 +17,7 @@ Bundler.require(*Rails.groups(assets: %w(development test)))
module Dummy
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
- config.load_defaults 6.0
+ config.load_defaults 6.1
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
diff --git a/core/lib/generators/refinery/dummy/templates/rails/database.yml b/core/lib/generators/refinery/dummy/templates/rails/database.yml
index 224fb9d7de6..5323f9b56e7 100644
--- a/core/lib/generators/refinery/dummy/templates/rails/database.yml
+++ b/core/lib/generators/refinery/dummy/templates/rails/database.yml
@@ -1,34 +1,75 @@
-login: &login
<% if /mysql$/ === @database %>
+development:
adapter: mysql<%= '2' unless /jdbc/ === @database %>
- encoding: utf8
+ encoding: utf8mb4
reconnect: false
pool: 5
username: root
password: <%%= ENV['MYSQL_PASSWORD'] %>
- #socket: /tmp/mysql.sock
+ database: dummy_dev
+
+test:
+ adapter: mysql<%= '2' unless /jdbc/ === @database %>
+ encoding: utf8mb4
+ reconnect: false
+ pool: 5
+ username: root
+ password: <%%= ENV['MYSQL_PASSWORD'] %>
+ database: dummy_test
+
+production:
+ adapter: mysql<%= '2' unless /jdbc/ === @database %>
+ encoding: utf8mb4
+ reconnect: false
+ pool: 5
+ username: root
+ password: <%%= ENV['MYSQL_PASSWORD'] %>
+ database: dummy_prod
+
<% elsif /postgresql/ === @database %>
+development:
adapter: postgresql
encoding: unicode
- database: refinery_database_development
pool: 5
username: <%%= ENV.fetch('PGUSER', 'postgres') %>
password: <%%= ENV.fetch('PGPASSWORD', 'postgres') %>
min_messages: warning
+ database: dummy_dev
+
+test:
+ adapter: postgresql
+ encoding: unicode
+ pool: 5
+ username: <%%= ENV.fetch('PGUSER', 'postgres') %>
+ password: <%%= ENV.fetch('PGPASSWORD', 'postgres') %>
+ min_messages: warning
+ database: dummy_test
+
+production:
+ adapter: postgresql
+ encoding: unicode
+ pool: 5
+ username: <%%= ENV.fetch('PGUSER', 'postgres') %>
+ password: <%%= ENV.fetch('PGPASSWORD', 'postgres') %>
+ min_messages: warning
+ database: dummy_prod
+
<% else %>
+development:
adapter: sqlite3
pool: 5
timeout: 5000
-<% end %>
-
-development:
- <<: *login
database: dummy_dev
test:
- <<: *login
+ adapter: sqlite3
+ pool: 5
+ timeout: 5000
database: dummy_test
production:
- <<: *login
+ adapter: sqlite3
+ pool: 5
+ timeout: 5000
database: dummy_prod
+<% end %>
\ No newline at end of file
diff --git a/core/lib/generators/refinery/dummy/templates/rails/manifest.js b/core/lib/generators/refinery/dummy/templates/rails/manifest.js
new file mode 100644
index 00000000000..5cc2c089409
--- /dev/null
+++ b/core/lib/generators/refinery/dummy/templates/rails/manifest.js
@@ -0,0 +1,3 @@
+//= link_tree ../images
+//= link_directory ../javascripts .js
+//= link_directory ../stylesheets .css
\ No newline at end of file
diff --git a/core/lib/generators/refinery/dummy/templates/rails/storage.yml b/core/lib/generators/refinery/dummy/templates/rails/storage.yml
new file mode 100644
index 00000000000..8fdb99ce16b
--- /dev/null
+++ b/core/lib/generators/refinery/dummy/templates/rails/storage.yml
@@ -0,0 +1,7 @@
+test:
+ service: Disk
+ root: <%%= Rails.root.join("tmp/storage") %>
+
+local:
+ service: Disk
+ root: <%%= Rails.root.join("storage") %>
\ No newline at end of file
diff --git a/core/lib/generators/refinery/engine/templates/Gemfile b/core/lib/generators/refinery/engine/templates/Gemfile
index cf6921bd72b..c2fc050947c 100644
--- a/core/lib/generators/refinery/engine/templates/Gemfile
+++ b/core/lib/generators/refinery/engine/templates/Gemfile
@@ -38,6 +38,5 @@ end
# in production environments by default.
group :assets do
gem 'sass-rails'
- gem 'coffee-rails'
gem 'uglifier'
end
diff --git a/core/lib/refinery.rb b/core/lib/refinery.rb
index 921851faa03..a12e806bb6f 100644
--- a/core/lib/refinery.rb
+++ b/core/lib/refinery.rb
@@ -1,4 +1,11 @@
-require 'rails' # from railties
+begin
+ require 'rails' # from railties
+rescue NameError => e
+ raise unless e.message.include?("ActiveSupport::LoggerThreadSafeLevel::Logger")
+
+ require "logger"
+ retry
+end
require 'active_record'
require 'action_controller'
require 'rbconfig'
diff --git a/core/lib/refinery/core/engine.rb b/core/lib/refinery/core/engine.rb
index ae0b04c84bb..efe00dce909 100644
--- a/core/lib/refinery/core/engine.rb
+++ b/core/lib/refinery/core/engine.rb
@@ -45,11 +45,22 @@ def refinery_inclusion!
end
initializer "refinery.mobility" do
- Mobility.configure do |config|
- config.default_backend = :table
- config.accessor_method = :translates
- config.query_method = :i18n
- config.default_options[:dirty] = true
+ Mobility.configure do
+ plugins do
+ backend :table
+ reader # Explicitly declare readers,
+ writer # writers, and
+ backend_reader # backend reader (post.title_backend, etc).
+ active_record # You must now also explicitly ask for ActiveRecord (or Sequel)
+ query # i18n is the default scope
+ cache # previously implicit
+ fallbacks
+ presence # previously implicit
+ default
+ attribute_methods # uncomment this to get methods like `translated_attributes`
+ dirty
+ end
+ # accessor_method not available in v1.0
end
end
diff --git a/core/lib/refinery/crud.rb b/core/lib/refinery/crud.rb
index a94b86ecda5..38bf00a2563 100644
--- a/core/lib/refinery/crud.rb
+++ b/core/lib/refinery/crud.rb
@@ -24,19 +24,21 @@ def self.default_options(model_name)
plural_name = singular_name.pluralize
{
- :conditions => '',
- :include => [],
- :order => ('position ASC' if this_class.connected? && this_class.table_exists? && this_class.column_names.include?('position')),
- :paging => true,
- :per_page => false,
- :redirect_to_url => "refinery.#{Refinery.route_for_model(class_name.constantize, :plural => true)}",
- :searchable => true,
- :search_conditions => '',
- :sortable => true,
- :title_attribute => "title",
- :class_name => class_name,
- :singular_name => singular_name,
- :plural_name => plural_name
+ conditions: '',
+ include: [],
+ order: ('position ASC' if this_class.connected? && this_class.table_exists? && this_class.column_names.include?('position')),
+ paging: true,
+ per_page: false,
+ redirect_to_url: "refinery.#{Refinery.route_for_model(class_name.constantize, :plural => true)}",
+ searchable: true,
+ search_conditions: '',
+ sortable: true,
+ title_attribute: "title",
+ class_name: class_name,
+ singular_name: singular_name,
+ plural_name: plural_name,
+ find_actions: [:update, :destroy, :edit, :show],
+ exclude_from_find: []
}
end
@@ -52,14 +54,14 @@ def crudify(model_name, options = {})
class_name = options[:class_name]
singular_name = options[:singular_name]
plural_name = options[:plural_name]
+ actions = [*options[:find_actions]] - [*options[:exclude_from_find]]
module_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.crudify_options
#{options.inspect}
end
- prepend_before_action :find_#{singular_name},
- :only => [:update, :destroy, :edit, :show]
+ prepend_before_action :find_#{singular_name}, only: #{actions}
prepend_before_action :merge_position_into_params!, :only => :create
def new
diff --git a/core/lib/refinery/generators/generated_attribute.rb b/core/lib/refinery/generators/generated_attribute.rb
index 7595fb3051b..44f938b01ed 100644
--- a/core/lib/refinery/generators/generated_attribute.rb
+++ b/core/lib/refinery/generators/generated_attribute.rb
@@ -3,9 +3,22 @@
module Refinery
module Generators
class GeneratedAttribute < Rails::Generators::GeneratedAttribute
+ REFINERY_TYPES = %w(image resource radio select checkbox)
+
attr_accessor :refinery_type
class << self
+ def parse(column_definition)
+ name, type, index_type = column_definition.split(":")
+
+ # Handle Refinery's custom types before Rails validates them
+ if type && REFINERY_TYPES.include?(type)
+ new(name, type.to_sym, index_type)
+ else
+ super
+ end
+ end
+
def reference?(type)
[:references, :belongs_to, :image, :resource].include? type
end
diff --git a/core/lib/refinery/version.rb b/core/lib/refinery/version.rb
index 3a6f11e49f8..990c0c0e0cd 100644
--- a/core/lib/refinery/version.rb
+++ b/core/lib/refinery/version.rb
@@ -13,7 +13,7 @@ def to_s
end
def required_ruby_version
- '>= 2.5.5'
+ '>= 3.1'
end
end
end
diff --git a/core/refinerycms-core.gemspec b/core/refinerycms-core.gemspec
index fa50e66c16b..28bba0c4fab 100644
--- a/core/refinerycms-core.gemspec
+++ b/core/refinerycms-core.gemspec
@@ -3,7 +3,7 @@
require File.expand_path('../core/lib/refinery/version', __dir__)
version = Refinery::Version.to_s
-rails_version = ['>= 5.2.0', '< 7']
+rails_version = ['>= 6.1.0', '< 9']
Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
s.summary = 'Core extension for Refinery CMS'
s.description = 'The core of Refinery CMS. This handles the common functionality and is required by most extensions'
s.email = 'gems@p.arndt.io'
- s.homepage = 'https://www.refinerycms.com'
+ s.homepage = 'https://github.com/refinery/refinerycms'
s.authors = ['Philip Arndt', 'David Jones', 'Uģis Ozols', 'Brice Sanchez']
s.license = 'MIT'
s.require_paths = %w[lib]
@@ -24,11 +24,11 @@ Gem::Specification.new do |s|
s.add_dependency 'actionpack', rails_version
s.add_dependency 'activerecord', rails_version
- s.add_dependency 'coffee-rails', ['~> 5.0', '>= 5.0.0']
+
s.add_dependency 'decorators', '~> 2.0', '>= 2.0.0'
s.add_dependency 'font-awesome-sass', '>= 4.3.0', '< 5.0'
s.add_dependency 'jquery-rails', '~> 4.3', '>= 4.3.1'
- s.add_dependency 'jquery-ui-rails', '~> 6.0', '>= 6.0.0'
+ s.add_dependency 'jquery-ui-rails', '~> 7.0.0'
s.add_dependency 'railties', rails_version
s.add_dependency 'refinerycms-i18n', ['~> 5.0', '>= 5.0.1']
s.add_dependency 'sass-rails', '>= 4.0', '< 7'
diff --git a/core/spec/helpers/refinery/translation_helper_spec.rb b/core/spec/helpers/refinery/translation_helper_spec.rb
index 10bbde9634b..12a6cd85779 100644
--- a/core/spec/helpers/refinery/translation_helper_spec.rb
+++ b/core/spec/helpers/refinery/translation_helper_spec.rb
@@ -1,7 +1,7 @@
require "spec_helper"
module Refinery
- describe TranslationHelper, :type => :helper do
+ describe TranslationHelper, type: :helper do
describe "#t" do
it "overrides Rails' translation method" do
@@ -15,8 +15,7 @@ module Refinery
before do
Mobility.with_locale(:en) do
- page.title = "draft"
- page.save!
+ page.update!({title: 'draft'})
end
Mobility.with_locale(:lv) do
@@ -25,19 +24,56 @@ module Refinery
end
end
- context "when title is present" do
- it "returns it" do
+ context "when field for current locale is present" do
+ it "it's value is returned" do
expect(helper.translated_field(page, :title)).to eq("draft")
end
end
- context "when title for current locale isn't available" do
- it "returns existing title from translations" do
+ context "when field for current locale isn't present" do
+
+ it "returns existing field value from other translations" do
Page::Translation.where(locale: :en).first.destroy
expect(helper.translated_field(page, :title)).to eq("melnraksts")
end
end
end
+ describe '#locales_with_translated_field' do
+ let(:page) { FactoryBot.build(:page) }
+
+ before do
+ allow(Refinery::I18n).to receive(:frontend_locales).and_return([:en, :lv, :it])
+ Mobility.with_locale(:en) do
+ page.update!({title: 'draft'})
+ end
+
+ Mobility.with_locale(:lv) do
+ page.title = "melnraksts"
+ page.save!
+ end
+ end
+
+ it 'returns an array of locales which have the named field translated' do
+ expect(helper.locales_with_translated_field(page, :title)).to eq([:en, :lv])
+ end
+
+ context 'The field has no translations' do
+ before do
+ Refinery::I18n.frontend_locales.each do |locale|
+ Mobility.with_locale(locale) do
+ page.title = "A title"
+ page.menu_title = ""
+ page.save!
+ end
+ end
+ end
+
+ it 'returns an empty array' do
+ expect(helper.locales_with_translated_field(page, :menu_title)).to eq([])
+ end
+ end
+ end
+
end
end
diff --git a/core/spec/lib/refinery/crud_spec.rb b/core/spec/lib/refinery/crud_spec.rb
index 8b7df004008..a6503e3af94 100644
--- a/core/spec/lib/refinery/crud_spec.rb
+++ b/core/spec/lib/refinery/crud_spec.rb
@@ -15,7 +15,8 @@ class CrudDummy < ActiveRecord::Base
end
class CrudDummyController < ::ApplicationController
- crudify :'refinery/crud_dummy'
+ skip_before_action :find_or_set_locale, raise: false
+ crudify :'refinery/crud_dummy', find_actions: [:update, :destroy, :edit]
end
end
diff --git a/core/spec/presenters/refinery/translated_field_presenter_spec.rb b/core/spec/presenters/refinery/translated_field_presenter_spec.rb
index bad639bee28..da9136b8c20 100644
--- a/core/spec/presenters/refinery/translated_field_presenter_spec.rb
+++ b/core/spec/presenters/refinery/translated_field_presenter_spec.rb
@@ -6,13 +6,11 @@ module Refinery
before do
Mobility.with_locale(:en) do
- page.title = "draft"
- page.save!
+ page.update!({ title: "draft" })
end
Mobility.with_locale(:lv) do
- page.title = "melnraksts"
- page.save!
+ page.update!(title: "melnraksts")
end
end
diff --git a/core/spec/system/refinery/admin/xhr_paging_spec.rb b/core/spec/system/refinery/admin/xhr_paging_spec.rb
index c1272f48f11..9a8aa9da8fb 100644
--- a/core/spec/system/refinery/admin/xhr_paging_spec.rb
+++ b/core/spec/system/refinery/admin/xhr_paging_spec.rb
@@ -2,17 +2,21 @@
module Refinery
describe "Crudify", type: :system do
+ before do
+ driven_by(:selenium_chrome_headless)
+ end
refinery_login
describe "xhr_paging", :js do
# Refinery::Admin::ImagesController specifies :order => 'created_at DESC' in crudify
let(:first_image) { Image.order('created_at DESC').first }
let(:last_image) { Image.order('created_at DESC').last }
- let!(:image_1) { FactoryBot.create :image }
- let!(:image_2) { FactoryBot.create :image }
+ let!(:image_1) { FactoryBot.create(:image) }
+ let!(:image_2) { FactoryBot.create(:image) }
before do
allow(Image).to receive(:per_page).and_return(1)
+ allow(Refinery::Images).to receive(:preferred_image_view).and_return(:grid)
end
it 'performs ajax paging of index' do
@@ -37,5 +41,4 @@ module Refinery
end
end
end
-
end
diff --git a/core/spec/system/refinery/site_bar_spec.rb b/core/spec/system/refinery/site_bar_spec.rb
index 7c5add0ecc9..a18a7a7cc11 100644
--- a/core/spec/system/refinery/site_bar_spec.rb
+++ b/core/spec/system/refinery/site_bar_spec.rb
@@ -1,7 +1,9 @@
+# frozen_string_literal: true
+
require "spec_helper"
module Refinery
- describe "site bar", :type => :system do
+ describe "site bar", type: :system do
refinery_login
describe "logout link" do
@@ -10,10 +12,10 @@ module Refinery
context "when set" do
before do
allow(Refinery::Core).to receive(:refinery_logout_path).and_return(logout_path)
- visit Refinery::Core.backend_path
end
it "is present" do
+ visit Refinery::Core.backend_path
expect(page).to have_selector("a[href='#{logout_path}']")
expect(page).to have_content("Log out")
end
@@ -62,7 +64,7 @@ module Refinery
end
it "has an 'edit this page' button" do
- expect(page).to have_link("Edit this page", :href => refinery.edit_admin_page_path(root_page))
+ expect(page).to have_link("Edit this page", href: refinery.edit_admin_page_path(root_page))
end
end
diff --git a/doc/guides/1 - Getting Started/1 - Installation Prerequisites.md b/doc/guides/1 - Getting Started/1 - Installation Prerequisites.md
index 2459b6f8024..a16e26d2858 100644
--- a/doc/guides/1 - Getting Started/1 - Installation Prerequisites.md
+++ b/doc/guides/1 - Getting Started/1 - Installation Prerequisites.md
@@ -4,15 +4,15 @@ This guide covers getting your system ready for Refinery. Afterwards you will ha
* A working version of Ruby
* ImageMagick installed
-* Either the SQLite, MySQL, or PostgreSQL database configured
+* Either the SQLite, MySQL, or Postgres database configured
## Checklist
If you are already a Rails developer, you will most likely not have to install anything else. Here's the requirements for Refinery:
-* __Ruby__ - 2.2.2+, Rubinius, and JRuby are all acceptable
+* __Ruby__ - 3.2+ and JRuby are all acceptable
* __RubyGems__ - Recommended that you have the latest version installed
-* __Database__ - SQLite3 (default), MySQL, or PostgreSQL
+* __Database__ - SQLite3 (default), MySQL, or Postgres
* __ImageMagick__ - Recommended that you have the latest version installed
If you have all of these things, great! Proceed on to the [Getting Started with Refinery](/guides/getting-started/) guide.
@@ -57,35 +57,15 @@ $ sudo apt-get install mysql-client mysql-server libmysqlclient-dev
$ sudo apt-get install imagemagick
```
-## Mac OS X
+## macOS
### Ruby
-__TIP__: The best way to install Ruby is using [rbenv](https://github.com/rbenv/rbenv)
-
-### Rubygems
-
-__TIP__: If you used `rbenv` above then this step will not be necessary.
-
-Rubygems also comes installed by default, however, it could be an old version which will cause problems. Update using:
-
-```shell
-$ gem update --system
-```
-
-Also, in the past, we face to a RDoc bug, you should update it as well:
-
-```shell
-$ gem install rdoc
-```
-
-### Database
-
-SQLite is most likely already installed.
+__TIP__: The best way to install Ruby is using [mise-en-place](https://mise.jdx.dev/)
### ImageMagick
-Use this shell script: . Or, if you have [Homebrew](http://mxcl.github.io/homebrew/) installed, you can use:
+If you have [Homebrew](https://brew.sh/) installed, you can use:
```shell
$ brew install imagemagick
@@ -95,17 +75,15 @@ $ brew install imagemagick
### Ruby and Rubygems
- provides a great installer to get you up and running in no time. Just download the kit and follow through the installer.
-
### Database
-If you used Rails Installer, then SQLite will have been installed by default. For MySQL, follow the instructions at the MySQL website:
+For MySQL, follow the instructions at the MySQL website: . For Postgres, follow the instructions at the Postgres website: .
### ImageMagick
__WARNING__: ImageMagick is tricky to install on Windows. Make sure to read the instructions carefully, and if one version does not work for you try an older version as well.
-Follow the instructions at
+Follow the instructions at
## Ready to Install!
diff --git a/doc/guides/1 - Getting Started/2 - Getting Started.md b/doc/guides/1 - Getting Started/2 - Getting Started.md
index 04a2845c940..c751b364416 100644
--- a/doc/guides/1 - Getting Started/2 - Getting Started.md
+++ b/doc/guides/1 - Getting Started/2 - Getting Started.md
@@ -38,7 +38,7 @@ The Refinery philosophy includes several guiding principles:
* __"The Rails Way" where possible__ - Refinery embraces conventions used in Rails, allowing any Rails programmer to leverage existing knowledge to get up and running quickly.
* __End user focused interface__ - Refinery's user interface is simple, bright and attractive so end users feel invited and not overwhelmed.
* __Awesome developer tools__ - Refinery makes it easy for developers to add functionality and change the front-end look and feel.
-* __Encourage and Help Others__ - Refinery has an active community on Github, Gitter and Google Groups. If you ever have a question there is someone able and willing to assist.
+* __Encourage and Help Others__ - Refinery has an active community on GitHub, and Google Groups. If you ever have a question there is someone able and willing to assist.
### Refinery's architecture
diff --git a/doc/guides/1 - Getting Started/4 - How to get help.md b/doc/guides/1 - Getting Started/4 - How to get help.md
index e0ff8a0b20a..73d320e65b7 100644
--- a/doc/guides/1 - Getting Started/4 - How to get help.md
+++ b/doc/guides/1 - Getting Started/4 - How to get help.md
@@ -6,14 +6,6 @@ We all sometimes hit a brick wall. This guide will show you how to:
One of Refinery's key principles is "Encourage and Help Others" so if you have any problems just let us know and we'll do our best to help you. And one day you might help someone else out too!
-## Gitter Channel
-
-Connect to our [Refinery Gitter channel](https://gitter.im/refinery/refinerycms).
-
-If you ask a question and don't get an immediate response, don't take offence; either wait a half-hour and ask again, or just post your question on the [Google Group](https://groups.google.com/forum/#!forum/refinery-cms) instead. This gives developers who are in other timezones or who are temporarily unavailable a chance to help you out.
-
-Please remember that Refinery is a fully open-source application. None of us are paid to fix it or improve it; we do so because we like Refinery and we greatly appreciate its value. Unfortunately, we cannot immediately drop everything to solve a problem for you (as much as we'd like to). Be patient, and try to figure out the problem on your own while you wait. The more information you can dig up yourself, the easier it is for us to help you resolve your issues expediently.
-
## Google Group
The [Refinery CMS Google Group](https://groups.google.com/forum/#!forum/refinery-cms) is a great place to ask for help if you don't get a response on Gitter. Your first message may take a short while to appear, as all first-time posters are required by Google Groups to pass moderation.
@@ -22,4 +14,4 @@ The [Refinery CMS Google Group](https://groups.google.com/forum/#!forum/refinery
* API (click 'File List' in top right) - http://api.refinerycms.org
* [GitHub Wiki](https://github.com/refinery/refinerycms/wiki)
-* [Guides](https://www.refinerycms.com/guides)
\ No newline at end of file
+* [Guides](https://www.refinerycms.com/guides)
diff --git a/images/app/controllers/refinery/admin/images_controller.rb b/images/app/controllers/refinery/admin/images_controller.rb
index 3caf6a93a8e..5d5596da7b3 100644
--- a/images/app/controllers/refinery/admin/images_controller.rb
+++ b/images/app/controllers/refinery/admin/images_controller.rb
@@ -1,3 +1,7 @@
+# frozen_string_literal: true
+
+require 'will_paginate/array'
+
module Refinery
module Admin
class ImagesController < ::Refinery::AdminController
@@ -6,7 +10,8 @@ class ImagesController < ::Refinery::AdminController
include: [:translations, :crops],
order: "updated_at DESC",
sortable: false,
- conditions: 'parent_id IS NULL'
+ conditions: 'parent_id IS NULL',
+ find_actions: [:update, :destroy, :edit]
before_action :change_list_mode_if_specified, :init_dialog
@@ -184,7 +189,7 @@ def image_params
def permitted_image_params
[
- :image, :image_size, :image_title, :image_alt
+ { image: [] }, :image_size, :image_title, :image_alt
]
end
end
diff --git a/images/app/helpers/refinery/admin/images_helper.rb b/images/app/helpers/refinery/admin/images_helper.rb
index 8f7dd1a1d1f..c62a0bb5301 100644
--- a/images/app/helpers/refinery/admin/images_helper.rb
+++ b/images/app/helpers/refinery/admin/images_helper.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Refinery
module Admin
module ImagesHelper
@@ -7,17 +9,21 @@ def other_image_views
end
end
+ def locale_text_icon(text)
+ text
+ end
+
def thumbnail_urls(image)
- thumbnail_urls = {
- :"data-original" => image_path(image.url),
- :"data-grid" => image_path(image.thumbnail(:geometry => '135x135#c').url)
+ thumbnails = {
+ original: image_path(image.url),
+ grid: image_path(image.thumbnail(geometry: '135x135#c').url)
}
- Refinery::Images.user_image_sizes.sort_by{ |key, geometry| geometry}.each do |size, pixels|
- thumbnail_urls[:"data-#{size.to_s.parameterize}"] = image_path(image.thumbnail(:geometry => pixels).url)
+ Refinery::Images.user_image_sizes.sort_by { |key, geometry| geometry }.each do |size, pixels|
+ thumbnails[size.to_s.parameterize] = image_path(image.thumbnail(geometry: pixels).url)
end
- thumbnail_urls
+ { data: thumbnails }
end
end
end
diff --git a/images/app/presenters/refinery/admin/grid_presenter.rb b/images/app/presenters/refinery/admin/grid_presenter.rb
new file mode 100644
index 00000000000..c81f5b1b089
--- /dev/null
+++ b/images/app/presenters/refinery/admin/grid_presenter.rb
@@ -0,0 +1,42 @@
+module Refinery
+ module Admin
+
+ # Refinery::Admin::GridPresenter is a class intended for presenting
+ # grouped records in a grid format within the Refinery CMS admin interface.
+ #
+ # It inherits from Refinery::Admin::GroupPresenter and overrides specific
+ # properties to provide custom behavior suitable for grid presentations.
+ #
+ # The primary features provided by this class include:
+ # - Custom grouping of records based on predefined logic.
+ # - Control over headers, identity keys, and displayed content organization.
+ #
+ # == Inclusions
+ # This class includes the following modules to extend functionality:
+ # - Refinery::Admin::ImagesHelper: Provides helper methods for working with images.
+ # - ActionView::Helpers::TagHelper: Supplies methods for creating HTML tags.
+ #
+ # == Attributes
+ # - @group_headers: Controls whether headers for each record group are displayed. Defaults to `false`.
+ # - @identity_keys: Represents the keys used to identify and present record attributes, including thumbnail, title, and alt text attributes.
+ # - @header: Stores header configurations, initialized as `nil`.
+ # - @groups: A lambda function designed to group records by associating them with the current date.
+ #
+ # == Initialization
+ # When initialized, `GridPresenter` accepts an execution `context` (e.g., a controller, view, etc.)
+ # and propagates this context to the superclass.
+ class GridPresenter < GroupPresenter
+ include Refinery::Admin::ImagesHelper
+ include ActionView::Helpers::TagHelper
+
+ def initialize(context)
+ super(context)
+ @group_headers = false
+ @identity_keys = [:thumbnail, :title, :alt]
+ @header = nil
+ @groups = ->(records) { [[Date.today, records]] }
+ end
+
+ end
+ end
+end
diff --git a/images/app/presenters/refinery/admin/group_presenter.rb b/images/app/presenters/refinery/admin/group_presenter.rb
new file mode 100644
index 00000000000..74f86696117
--- /dev/null
+++ b/images/app/presenters/refinery/admin/group_presenter.rb
@@ -0,0 +1,68 @@
+module Refinery
+ module Admin
+
+ # Refinery::Admin::GroupPresenter
+ #
+ # This class represents a presenter for organizing and displaying
+ # groups with associated metadata in a structured format.
+ #
+ # The presenter utilizes several helper modules for enhanced
+ # functionality and template rendering support.
+ #
+ # == Includes:
+ # * `Refinery::Admin::ImagesHelper` - Provides image-related functionality.
+ # * `ActionView::Helpers::TagHelper` - Used to create HTML-like tags dynamically.
+ #
+ # == Attributes:
+ # * `context` [Object] - Represents the context within which the presenter operates.
+ # * `groups` [Object] - Holds a collection of groups to be managed.
+ # * `group_classes` [Array] - Provides a list of CSS class names applied to the group tag.
+ # * `group_header` [Proc] - Callable object (e.g., lambda) to determine the header for each group.
+ # * `group_headers` [Boolean] - Controls whether group headers are displayed.
+ # * `group_tag` [Symbol] - Defines the tag used to wrap groups, e.g., `:ul`.
+ # * `group_wrapper` [Proc] - Customizable wrapper for rendering group collections.
+ # * `header` [Proc] - Callable object to format the header for individual groups.
+ # * `header_tag` [Symbol] - Specifies the tag for rendering headers, e.g., `:h3`.
+ # * `identity_keys` [Object] - Additional attribute for handling unique identity keys.
+ #
+ # == Public Instance Methods:
+ # - `initialize(context)`
+ # Initializes a new instance of the presenter within a given context,
+ # setting default values for various attributes like headers and tags.
+ #
+ # - `group_wrapper(&block)`
+ # Wraps the rendering of groups using a specified tag.
+ # This is customizable via the `group_tag` and `group_classes` attributes.
+ # A block must be passed to render the inner contents.
+ #
+ # - `group_header(date)`
+ # Constructs a header for individual groups based on a provided date.
+ # The format of the header is defined by the `header` callable and
+ # displayed using the specified `header_tag`.
+ class GroupPresenter
+ include Refinery::Admin::ImagesHelper
+ include ActionView::Helpers::TagHelper
+
+ attr_accessor :context, :groups, :group_classes, :group_header, :group_headers, :group_tag, :group_wrapper,
+ :header, :header_tag, :identity_keys
+
+ def initialize(context)
+ @context = context
+ @group_headers = true
+ @group_tag = :ul
+ @group_classes = [:image_group]
+ @header_tag = :h3
+ end
+
+ def group_wrapper(&block)
+ context.tag group_tag, class: group_classes do
+ yield block
+ end
+ end
+
+ def group_header(date)
+ tag.send(header_tag, header.call(date), class: :group_header)
+ end
+ end
+ end
+end
diff --git a/images/app/presenters/refinery/admin/image_presenter.rb b/images/app/presenters/refinery/admin/image_presenter.rb
new file mode 100644
index 00000000000..06856f15d2c
--- /dev/null
+++ b/images/app/presenters/refinery/admin/image_presenter.rb
@@ -0,0 +1,145 @@
+module Refinery
+ module Admin
+
+ # Refinery::Admin::ImagePresenter
+ #
+ # This class represents a presenter for managing and displaying image data
+ # in the Refinery admin interface. It provides methods to format image-related
+ # data for display and to generate necessary HTML components for interacting
+ # with images in the admin UI.
+ #
+ # === Includes
+ # - ActionView::RecordIdentifier: Provides methods for DOM ID generation for records.
+ # - ActionView::Helpers::UrlHelper: Allows generation of URLs and links.
+ # - ActionView::Helpers::TagHelper: Provides methods for generating HTML tags.
+ # - ActionView::Context: Allows rendering within the correct context.
+ # - Refinery::TranslationHelper: Adds support for translation-related helper methods.
+ # - Refinery::Admin::ImagesHelper: Includes specific helper methods for working with images.
+ # - Refinery::ActionHelper: Provides additional action-based helper methods.
+ #
+ # === Attributes
+ # - `image` [Reader]: The image object being presented.
+ # - `context` [Reader]: Context of the current view, often required for generating paths and URLs.
+ # - `index_keys` [Reader]: Used to specify the attributes displayed in the index table for images.
+ # - `i18n_scope` [Reader]: Specifies the internationalization scope for localization of text.
+ # - `title` [Writer]: Sets the title for the image.
+ # - `alt` [Writer]: Sets the alt text for the image.
+ # - `filename` [Writer]: Sets the filename for the image.
+ # - `translations` [Writer]: Stores translations for the image fields.
+ # - `edit_attributes` [Writer]: Stores attributes to be used for editing the image.
+ # - `delete_attributes` [Writer]: Stores attributes to be used for deleting the image.
+ # - `preview_attributes` [Writer]: Stores attributes for image preview options.
+ #
+ # === Constants
+ # - `IndexEntry`: Defines a structure to hold index entry data, including the image ID,
+ # edit link, text elements, locales, and actionable items.
+ #
+ # === Instance Methods
+ #
+ # - `initialize(image, context, scope = nil)`:
+ # Constructor that initializes the ImagePresenter with the given image object, view context,
+ # and optional internationalization scope.
+ #
+ # - `index_entry(index_keys)`:
+ # Generates an index entry for the image, including its ID, edit link, text elements,
+ # and actions. Accepts an array of keys for specifying index fields.
+ # These keys differ between the grid_view and list_view, and other views could be added
+ #
+ # - `link_to_edit(edit_key)`:
+ # Creates a link to edit the image, using the given key for determining the "text" of the link.
+ #
+ # - `text_elements(keys)`:
+ # Generates text elements for display based on the provided keys, wrapping them in HTML spans.
+ #
+ # - `thumbnail`:
+ # Returns the thumbnail for the image, including specific attributes such as its
+ # URL, description (alt) and title
+ class ImagePresenter < Refinery::BasePresenter
+ include ActionView::RecordIdentifier
+ include ActionView::Helpers::UrlHelper
+ include ActionView::Helpers::TagHelper
+ include ActionView::Context
+
+ include Refinery::TranslationHelper
+ include Refinery::Admin::ImagesHelper
+ include Refinery::ActionHelper
+
+ attr_reader :image, :context, :index_keys, :i18n_scope
+ attr_writer :title, :alt, :filename, :translations, :edit_attributes, :delete_attributes, :preview_attributes
+ delegate_missing_to :image
+ delegate :t, to: :context
+
+ IndexEntry = Struct.new('ImageEntry', :id, :edit_link, :text_elements, :locales, :actions)
+
+ def initialize(image, context, scope = nil)
+ super(image)
+ @image = image
+ @context = context
+ @i18n_scope = scope || 'refinery.admin.images'
+ end
+
+ def index_entry(index_keys)
+ edit_key, *text_keys = index_keys
+ IndexEntry.new(
+ id: image.id,
+ edit_link: link_to_edit(index_keys[0]),
+ text_elements: text_elements(index_keys[1..]),
+ actions: tag.span( image_actions, class: :actions)
+ )
+ end
+
+ def link_to_edit(edit_key)
+ link_to(self.send(edit_key),
+ context.edit_admin_image_path(image),
+ { title: ::I18n.t('.edit', title: image.title, scope: i18n_scope), class: :edit_link})
+ end
+
+ def text_elements(keys)
+ keys.reduce(ActiveSupport::SafeBuffer.new) do |buffer, key|
+ buffer << tag.span(self.send(key), title: ::I18n.t(key, scope: i18n_scope), class: key)
+ end
+ end
+
+ def thumbnail
+ tag.img src: image.thumbnail(geometry: Refinery::Images.admin_image_sizes[:grid], strip: true).url(only_path: true),
+ alt: image.alt, title: image.title, class: :thumbnail
+ end
+
+ def title
+ translated_field(image, :title)
+ end
+
+ def alt
+ alt_text = translated_field(@image, :alt)
+ alt_text unless alt_text === translated_field(image, :title)
+ end
+
+ def filename
+ image.image_name
+ end
+
+ def image_actions
+ [*edit_actions, delete_action, preview_action].reduce(ActiveSupport::SafeBuffer.new) do |buffer, action|
+ buffer << action
+ end
+ end
+
+ def edit_actions
+ translated_locales = locales_with_translated_field(image, :image_title)
+ edit_in_locales(context.edit_admin_image_path(image), translated_locales)
+ end
+
+ def preview_action(options = {})
+ action_icon(:preview, image.url, ::I18n.t('.view_live_html', scope: i18n_scope),
+ options: options)
+ end
+
+ def delete_action(options = {})
+ action_icon(:delete, context.admin_image_path(image),
+ ::I18n.t('.delete', scope: i18n_scope),
+ data: { confirm: ::I18n.t('message', scope: 'refinery.admin.delete', title: image.title) },
+ **options )
+ end
+ end
+ end
+end
diff --git a/images/app/presenters/refinery/admin/list_presenter.rb b/images/app/presenters/refinery/admin/list_presenter.rb
new file mode 100644
index 00000000000..56edd2b2d5e
--- /dev/null
+++ b/images/app/presenters/refinery/admin/list_presenter.rb
@@ -0,0 +1,23 @@
+module Refinery
+ module Admin
+ class ListPresenter < GroupPresenter
+ include Refinery::Admin::ImagesHelper
+ include ActionView::Helpers::TagHelper
+
+ # Initialize the presenter with a context, a lambda for headers, and a lambda for groups.
+ #
+ # @param context [Object] An object that provides the necessary methods for grouping and rendering.
+ # @param header [Proc] Callable for formatting group headers.
+ # @param groups [Proc] Callable for grouping records.
+ def initialize(context,
+ header: ->(date) { localized(date) },
+ groups: ->(records) { context.group_by_date(records, :updated_at) })
+ super(context)
+ @identity_keys = [:title, :filename, :alt]
+ @group_headers = true
+ @header = header
+ @groups = groups
+ end
+ end
+ end
+end
diff --git a/images/app/views/refinery/admin/images/_existing_image.html.erb b/images/app/views/refinery/admin/images/_existing_image.html.erb
index 9d108d76769..0682ea6496d 100644
--- a/images/app/views/refinery/admin/images/_existing_image.html.erb
+++ b/images/app/views/refinery/admin/images/_existing_image.html.erb
@@ -6,24 +6,28 @@
diff --git a/images/app/views/refinery/admin/images/_form.html.erb b/images/app/views/refinery/admin/images/_form.html.erb
index bdcdf4dca55..7e76ce47c95 100644
--- a/images/app/views/refinery/admin/images/_form.html.erb
+++ b/images/app/views/refinery/admin/images/_form.html.erb
@@ -17,7 +17,7 @@
<%= f.file_field :image %>
<% else %>
- <% # we must only hint at multiple when it's a new record otherwise update fails. %>
+ <%# we must only hint at multiple when it's a new record otherwise update fails. %>
<%= f.file_field :image, multiple: true %>
<% end %>
@@ -113,4 +113,4 @@
<% end %>
<% content_for :stylesheets, stylesheet_link_tag('cropper') -%>
-<% end %>
\ No newline at end of file
+<% end %>
diff --git a/images/app/views/refinery/admin/images/_image.html.erb b/images/app/views/refinery/admin/images/_image.html.erb
new file mode 100644
index 00000000000..d1ccdb6cfc7
--- /dev/null
+++ b/images/app/views/refinery/admin/images/_image.html.erb
@@ -0,0 +1,5 @@
+
diff --git a/pages/config/locales/en.yml b/pages/config/locales/en.yml
index 709be9a48fa..47b01f635e6 100644
--- a/pages/config/locales/en.yml
+++ b/pages/config/locales/en.yml
@@ -32,15 +32,15 @@ en:
tab_name: Your file
link_to_this_resource: Link to this file
pages:
- delete: Remove this page forever
- edit: Edit this page
- new: Add a new child page
expand_collapse: Expand or collapse sub pages
page:
draft: draft
hidden: hidden
redirected: Redirected
skip_to_first_child: Skip to first child
+ delete: Remove this page forever
+ edit: Edit this page
+ new: Add a new child page
view_live_html: View this page live (opens in a new window)
form:
preview: Preview
diff --git a/pages/lib/refinery/pages/finder.rb b/pages/lib/refinery/pages/finder.rb
index f32af40a977..e58dbbea164 100644
--- a/pages/lib/refinery/pages/finder.rb
+++ b/pages/lib/refinery/pages/finder.rb
@@ -44,7 +44,7 @@ def with_mobility
attr_accessor :conditions
def translated_attributes
- Page.translated_attribute_names.map(&:to_s) | %w(locale)
+ [*Page.mobility_attributes, 'locale']
end
def translations_conditions(original_conditions)
diff --git a/pages/lib/refinery/pages/instance_methods.rb b/pages/lib/refinery/pages/instance_methods.rb
index 1ff334ad961..8b2263e611c 100644
--- a/pages/lib/refinery/pages/instance_methods.rb
+++ b/pages/lib/refinery/pages/instance_methods.rb
@@ -18,7 +18,7 @@ def error_404(exception = nil)
end
end
- def render(*args)
+ def render(*args, &block)
present @page unless admin? || @meta
super
end
diff --git a/pages/refinerycms-pages.gemspec b/pages/refinerycms-pages.gemspec
index c67ff1b60e0..5f7980ff801 100644
--- a/pages/refinerycms-pages.gemspec
+++ b/pages/refinerycms-pages.gemspec
@@ -22,8 +22,8 @@ Gem::Specification.new do |s|
s.add_dependency 'awesome_nested_set', '~> 3.1', '>= 3.1.0'
s.add_dependency 'babosa', '~> 1.0'
s.add_dependency 'diffy', '~> 3.1', '>= 3.1.0'
- s.add_dependency 'friendly_id', ['>= 5.1.0', '< 5.3']
- s.add_dependency 'friendly_id-mobility', '~> 0.5'
+ s.add_dependency 'friendly_id', '>= 5.4.0'
+ s.add_dependency 'friendly_id-mobility', '~> 1.0.4'
s.add_dependency 'refinerycms-core', version
s.add_dependency 'seo_meta', '~> 3.0', '>= 3.0.0'
s.add_dependency 'speakingurl-rails', '~> 8.0', '>= 8.0.0'
diff --git a/pages/spec/controllers/refinery/pages_controller_spec.rb b/pages/spec/controllers/refinery/pages_controller_spec.rb
index 2e9d86a4df8..b2b5083c954 100644
--- a/pages/spec/controllers/refinery/pages_controller_spec.rb
+++ b/pages/spec/controllers/refinery/pages_controller_spec.rb
@@ -3,13 +3,13 @@
module Refinery
describe PagesController, :type => :controller do
before do
- FactoryBot.create(:page, link_url: "/")
+ FactoryBot.create(:page, { link_url: "/" })
FactoryBot.create(:page, title: "testing")
FactoryBot.create(:page, link_url: "/items")
end
describe "#home" do
- context "when page path set to default ('/') " do
+ context "when page path set to default ('/')" do
it "renders home template" do
get :home
expect(response).to render_template("home")
diff --git a/pages/spec/helpers/refinery/pages/admin/pages_helper_spec.rb b/pages/spec/helpers/refinery/pages/admin/pages_helper_spec.rb
index cbe89a03929..46186152275 100644
--- a/pages/spec/helpers/refinery/pages/admin/pages_helper_spec.rb
+++ b/pages/spec/helpers/refinery/pages/admin/pages_helper_spec.rb
@@ -18,13 +18,13 @@ module Admin
context "when page layout template is set using symbols" do
before do
- allow(Pages.config).to receive(:layout_template_whitelist).and_return [:three, :one, :two]
+ allow(Refinery::Pages.config).to receive(:layout_template_whitelist).and_return [:three, :one, :two]
end
- it "works as expected" do
- page = FactoryBot.create(:page, :layout_template => "three")
+ it "page layout template is set correctly" do
+ page = FactoryBot.create(:page, layout_template: "three")
- expect(helper.template_options(:layout_template, page)).to eq(:selected => 'three')
+ expect(helper.template_options(:layout_template, page)).to eq(selected: 'three')
end
end
@@ -57,9 +57,7 @@ module Admin
it "adds 'hidden' label" do
page.show_in_menu = false
- expect(helper.page_meta_information(page)).to eq(
- %Q{#{::I18n.t('refinery.admin.pages.page.hidden')}}
- )
+ expect(helper.page_meta_information(page)).to have_text ::I18n.t('refinery.admin.pages.page.hidden')
end
end
@@ -67,29 +65,21 @@ module Admin
it "adds 'skip to first child' label" do
page.skip_to_first_child = true
- expect(helper.page_meta_information(page)).to eq(
- %Q{#{::I18n.t('refinery.admin.pages.page.skip_to_first_child')}}
- )
+ expect(helper.page_meta_information(page)).to have_text ::I18n.t('refinery.admin.pages.page.skip_to_first_child')
end
end
context "when link_url is present" do
it "adds 'redirected' label" do
page.link_url = '/redirect'
-
- expect(helper.page_meta_information(page)).to eq(
- %Q{#{::I18n.t('refinery.admin.pages.page.redirected')}}
- )
+ expect(helper.page_meta_information(page)).to have_text ::I18n.t('refinery.admin.pages.page.redirected')
end
end
context "when draft is true" do
it "adds 'draft' label" do
page.draft = true
-
- expect(helper.page_meta_information(page)).to eq(
- %Q{#{::I18n.t('refinery.admin.pages.page.draft')}}
- )
+ expect(helper.page_meta_information(page)).to have_text ::I18n.t('refinery.admin.pages.page.draft')
end
end
end
diff --git a/pages/spec/support/selector_helpers.rb b/pages/spec/support/selector_helpers.rb
new file mode 100644
index 00000000000..fd3a0bf9084
--- /dev/null
+++ b/pages/spec/support/selector_helpers.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+def index_entry
+ 'li.record.page'
+end
+
+def index_item(id)
+ [id, '.item'].join(' ')
+end
+
+# various edit actions selectors: there are several in a single index entry
+# 1. the page title is wrapped in an edit link
+# page title
+# 2. if there are several locales there is an edit_in_locale link for each locale
+#
+# 3. the actions group has an edit icon with a link to edit the page (equivalent to 1)
+#
+#
+def edit_selector(class_name: nil, locale: nil, slug: nil)
+ class_selector = [class_name, 'edit'].compact.join('.')
+ query_selector = ("?switch_locale=#{locale}" if locale.present?)
+ "a.#{class_selector}[href$='#{slug}/edit#{query_selector}']"
+end
+
+def title_link_selector(slug: '')
+ edit_selector(slug: slug, class_name: :title)
+end
+
+def icon_link_selector(slug: '')
+ edit_selector(slug: slug, class_name: :edit_icon)
+end
+
+def locale_link_selector(locale:, slug: '')
+ edit_selector(slug: slug, class_name: :locale, locale: locale.downcase)
+end
+
+def locales
+ "span.locales"
+end
+
+def locale_picker(locale)
+ ".locales ##{locale}"
+end
diff --git a/pages/spec/system/refinery/admin/pages_spec.rb b/pages/spec/system/refinery/admin/pages_spec.rb
index fb13b476563..144b44cec2d 100644
--- a/pages/spec/system/refinery/admin/pages_spec.rb
+++ b/pages/spec/system/refinery/admin/pages_spec.rb
@@ -15,17 +15,16 @@ def expect_window_without_content(content, window: windows.last)
def switch_page_form_locale(locale)
within "#switch_locale_picker" do
- find("a", text: locale.upcase).click
+ find("a", id: locale.downcase).click
end
# make sure that the locale change has taken effect
- expect(page).to have_selector("#switch_locale_picker li.selected a##{locale.downcase}")
+ expect(page).to have_selector("#switch_locale_picker a.selected##{locale.downcase}")
end
-
module Refinery
module Admin
- describe "Pages", :type => :system do
+ describe "Pages", type: :system do
refinery_login
context "when no pages" do
@@ -88,15 +87,14 @@ module Admin
end
context "when sub pages exist" do
- let!(:company) { Page.create :title => 'Our Company' }
- let!(:team) { company.children.create :title => 'Our Team' }
- let!(:locations) { company.children.create :title => 'Our Locations' }
- let!(:location) { locations.children.create :title => 'New York' }
+ let!(:company) { Page.create title: 'Our Company' }
+ let!(:team) { company.children.create title: 'Our Team' }
+ let!(:locations) { company.children.create title: 'Our Locations' }
+ let!(:location) { locations.children.create title: 'New York' }
context "with auto expand option turned off" do
before do
allow(Refinery::Pages).to receive(:auto_expand_admin_tree).and_return(false)
-
visit refinery.admin_pages_path
end
@@ -111,15 +109,15 @@ module Admin
end
it "expands children", js: true do
- find("#page_#{company.id} .title.toggle").click
+ find("#page_#{company.id} .icon.toggle").click
expect(page).to have_content(team.title)
expect(page).to have_content(locations.title)
end
it "expands children when nested multiple levels deep", js: true do
- find("#page_#{company.id} .title.toggle").click
- find("#page_#{locations.id} .title.toggle").click
+ find("#page_#{company.id} .icon.toggle").click
+ find("#page_#{locations.id} .icon.toggle").click
expect(page).to have_content("New York")
end
@@ -127,9 +125,8 @@ module Admin
context "with auto expand option turned on" do
before do
- allow(Refinery::Pages).to receive(:auto_expand_admin_tree).and_return(true)
+ Refinery::Pages.auto_expand_admin_tree = true
Rails.cache.clear
-
visit refinery.admin_pages_path
end
@@ -138,26 +135,26 @@ module Admin
expect(page).to have_content(locations.title)
end
- it "refreshes the cache if sub_children change" do
+ it "refreshes the cache if sub_children change", js: true do
expect(page).to have_content(location.title)
- find("#page_#{location.id} .edit_icon").click
- fill_in "Title", with: 'Las Vegas'
- click_button "Save"
+ within page.find("#page_#{location.id}") do
+ first(title_link_selector).click
+ end
+ fill_in "page_title", with: 'Las Vegas'
+ click_button "Save"
expect(page).to have_content('Las Vegas')
end
end
end
end
- describe "new/create" do
- it "Creates a page", js: true do
+ describe " new / create " do
+ it " Creates a page ", js: true do
visit refinery.admin_pages_path
-
find('a', text: 'Add new page').click
-
- fill_in "Title", :with => "My first page"
+ fill_in "Title", with: "My first page"
expect { click_button "Save" }.to change(Refinery::Page, :count).from(0).to(1)
expect(page).to have_content("'My first page' was successfully added.")
@@ -174,11 +171,11 @@ module Admin
it "includes menu title field", js: true do
visit refinery.new_admin_page_path
- fill_in "Title", :with => "My first page"
+ fill_in "Title", with: "My first page"
find('#toggle_advanced_options').click
- fill_in "Menu title", :with => "The first page"
+ fill_in "Menu title", with: "The first page"
# For some reason the first click doesn't always work?
begin
@@ -192,13 +189,13 @@ module Admin
end
it "allows to easily create nested page" do
- parent_page = Page.create! :title => "Rails 4"
+ parent_page = Page.create! title: "Rails 4"
visit refinery.admin_pages_path
- find("a[href='#{refinery.new_admin_page_path(:parent_id => parent_page.id)}']").click
+ find("a[href='#{refinery.new_admin_page_path(parent_id: parent_page.id)}']").click
- fill_in "Title", :with => "Parent page"
+ fill_in "Title", with: "Parent page"
click_button "Save"
expect(page).to have_content("'Parent page' was successfully added.")
@@ -218,9 +215,9 @@ module Admin
context 'when saving and returning to index' do
it "updates page", js: true do
- find("a[href$='#{updateable_page.slug}/edit']").click
+ first(edit_selector(slug: updateable_page.slug)).click
- fill_in "Title", :with => "Updated"
+ fill_in "Title", with: "Updated"
find("#submit_button").click
expect(page).to have_content("'Updated' was successfully updated.")
@@ -229,10 +226,10 @@ module Admin
context 'when saving and continuing to edit', js: true do
before :each do
- expect(page).to have_selector("a[href$='#{updateable_page.slug}/edit']", visible: true)
- find("a[href$='#{updateable_page.slug}/edit']").click
+ expect(page).to have_selector(edit_selector(slug: updateable_page.slug), visible: true)
+ first(edit_selector(slug: updateable_page.slug)).click
- fill_in "Title", :with => "Updated you"
+ fill_in "Title", with: "Updated you"
find("#submit_continue_button").click
find('#flash').visible?
end
@@ -262,12 +259,12 @@ module Admin
describe 'Previewing', js: true do
let(:preview_content) { "Some changes I'm unsure what they will look like".freeze }
context "an existing page" do
- before { Page.create :title => 'Preview me' }
+ before { Page.create title: 'Preview me' }
it 'will show the preview changes in a new window' do
visit refinery.admin_pages_path
- find('a[tooltip^=Edit]').click
+ first(edit_selector).click
fill_in "Title", with: preview_content
window = window_opened_by do
click_button "Preview"
@@ -281,7 +278,7 @@ module Admin
it 'will not show the site bar' do
visit refinery.admin_pages_path
- find('a[tooltip^=Edit]').click
+ first(edit_selector).click
fill_in "Title", with: preview_content
window = window_opened_by do
click_button "Preview"
@@ -290,11 +287,11 @@ module Admin
expect_window_without_content(
::I18n.t('switch_to_website', scope: 'refinery.site_bar'),
window: window
- )
+ )
expect_window_without_content(
::I18n.t('switch_to_website_editor', scope: 'refinery.site_bar'),
window: window
- )
+ )
window.close
end
@@ -302,7 +299,7 @@ module Admin
it 'will not save the preview changes' do
visit refinery.admin_pages_path
- find('a[tooltip^=Edit]').click
+ first(edit_selector).click
fill_in "Title", with: preview_content
window = window_opened_by do
click_button "Preview"
@@ -311,7 +308,7 @@ module Admin
expect_window_with_content(
preview_content,
window: window
- )
+ )
window.close
@@ -322,8 +319,8 @@ module Admin
it 'will show the preview in a new window after save-and-continue' do
visit refinery.admin_pages_path
- find('a[tooltip^=Edit]').click
- fill_in "Title", :with => "Save this"
+ first(edit_selector).click
+ fill_in "Title", with: "Save this"
click_button "Save & continue editing"
expect(page).to have_content("'Save this' was successfully updated")
@@ -333,9 +330,9 @@ module Admin
expect_window_with_content("Save this", window: window)
expect_window_without_content(
- ::I18n.t('switch_to_website', :scope => 'refinery.site_bar'),
+ ::I18n.t('switch_to_website', scope: 'refinery.site_bar'),
window: window
- )
+ )
window.close
end
@@ -345,8 +342,8 @@ module Admin
it 'will save-and-continue after show the preview in a new window' do
visit refinery.admin_pages_path
- find('a[tooltip^=Edit]').click
- fill_in "Title", :with => "Save this"
+ first(title_link_selector).click
+ fill_in "Title", with: "Save this"
window = window_opened_by do
click_button "Preview"
@@ -354,23 +351,26 @@ module Admin
expect_window_with_content("Save this", window: window)
expect_window_without_content(
- ::I18n.t('switch_to_website', :scope => 'refinery.site_bar'),
+ ::I18n.t('switch_to_website', scope: 'refinery.site_bar'),
window: window
)
window.close
+ # Wait for JavaScript setTimeout to restore form action after preview
+ expect(page).to have_no_css("form[action*='/preview/']", wait: 1)
+
click_button "Save & continue editing"
expect(page).to have_content("'Save this' was successfully updated")
end
- it 'will show pages with inherited templates', js:true do
+ it 'will show pages with inherited templates', js: true do
visit refinery.admin_pages_path
- find('a[tooltip^=Edit]').click
- fill_in 'Title', :with => 'Searchable'
+ first(edit_selector).click
+ fill_in 'Title', with: 'Searchable'
find('#toggle_advanced_options').click
- select 'Searchable', :from => 'View template'
+ select 'Searchable', from: 'View template'
Timeout::timeout(5) do
click_button 'Preview'
sleep 0.1 and redo unless windows.many?
@@ -380,11 +380,11 @@ module Admin
end
context 'a brand new page' do
- it "will not save when just previewing", js:true do
+ it "will not save when just previewing", js: true do
visit refinery.admin_pages_path
find('a', text: 'Add new page').click
- fill_in "Title", :with => "My first page"
+ fill_in "Title", with: "My first page"
window = window_opened_by do
click_button "Preview"
end
@@ -397,29 +397,29 @@ module Admin
end
context 'a nested page' do
- let!(:parent_page) { Page.create :title => "Our Parent Page" }
- let!(:nested_page) { parent_page.children.create :title => 'Preview Me' }
+ let!(:parent_page) { Page.create title: "Our Parent Page" }
+ let!(:nested_page) { parent_page.children.create title: 'Preview Me' }
- it "works like an un-nested page" do
+ it "works like an un-nested page", js: true do
visit refinery.admin_pages_path
- within "#page_#{nested_page.id}" do
- find('a[tooltip^=Edit]').click
+ within "#page_#{nested_page.id} .item" do
+ first(title_link_selector).click
end
fill_in "Title", with: preview_content
- window = window_opened_by do
+ window = page.window_opened_by do
click_button "Preview"
end
- expect_window_with_content(preview_content)
+ expect_window_with_content(preview_content, window: window)
end
end
end
describe "destroy" do
- context "when page can be deleted", js:true do
- before { Page.create :title => "Delete me" }
+ context "when page can be deleted", js: true do
+ before { Page.create title: "Delete me" }
it "will show delete button" do
visit refinery.admin_pages_path
@@ -435,7 +435,7 @@ module Admin
end
context "when page can't be deleted" do
- before { Page.create :title => "Indestructible", :deletable => false }
+ before { Page.create title: "Indestructible", deletable: false }
it "wont show delete button" do
visit refinery.admin_pages_path
@@ -447,12 +447,12 @@ module Admin
end
context "duplicate page titles" do
- before { Page.create :title => "I was here first" }
+ before { Page.create title: "I was here first" }
it "will append nr to url path" do
visit refinery.new_admin_page_path
- fill_in "Title", :with => "I was here first"
+ fill_in "Title", with: "I was here first"
click_button "Save"
expect(Refinery::Page.last.url[:path].first).to match(%r{\Ai-was-here-first-.+?})
@@ -462,12 +462,14 @@ module Admin
context "with translations" do
before do
allow(Refinery::I18n).to receive(:frontend_locales).and_return([:en, :ru])
+ end
+ before do
# Create a home page in both locales (needed to test menus)
home_page = Mobility.with_locale(:en) do
- Page.create :title => 'Home',
- :link_url => '/',
- :menu_match => "^/$"
+ Page.create title: 'Home',
+ link_url: '/',
+ menu_match: "^/$"
end
Mobility.with_locale(:ru) do
@@ -476,11 +478,11 @@ module Admin
end
end
- describe "add a page with title for default locale", js:true do
+ describe "add a page with title for default locale", js: true do
before do
visit refinery.admin_pages_path
find('a', text: "Add new page").click
- fill_in "Title", :with => "News"
+ fill_in "Title", with: "News"
click_button "Save"
end
@@ -489,24 +491,21 @@ module Admin
expect(Refinery::Page.count).to eq(2)
end
- it "shows locale flag for page" do
- p = ::Refinery::Page.by_slug('news').first
- within "#page_#{p.id} .locales" do
- expect(page).to have_css('.locale_marker')
- expect(page).to have_content('EN')
+ it "doesn't show locale for default frontend locale" do
+ within "#page_#{::Refinery::Page.by_slug('news').first.id}" do
+ expect(page).not_to have_selector(".locales")
+ expect(page).not_to have_selector(locale_link_selector(locale: 'en'))
end
end
it "shows title in the admin menu" do
- p = ::Refinery::Page.by_slug('news').first
- within "#page_#{p.id}" do
+ within "#page_#{::Refinery::Page.by_slug('news').first.id}" do
expect(page).to have_content('News')
- expect(page.find('a[tooltip="Edit this page"]')[:href]).to include('news')
+ expect(page.first(title_link_selector)[:text]).to have_content('News')
end
end
it "shows in frontend menu for 'en' locale" do
- # page.driver.debug
visit "/"
within "#menu" do
@@ -520,7 +519,7 @@ module Admin
within "#menu" do
# we should only have the home page in the menu
- expect(page).to have_css('li', :count => 1)
+ expect(page).to have_css('li', count: 1)
end
end
end
@@ -531,17 +530,12 @@ module Admin
let(:ru_page_title) { 'Новости' }
let(:ru_page_slug_encoded) { '%D0%BD%D0%BE%D0%B2%D0%BE%D1%81%D1%82%D0%B8' }
let!(:news_page) do
- allow(Refinery::I18n).to receive(:frontend_locales).and_return([:en, :ru])
-
- _page = Mobility.with_locale(:en) {
- Page.create :title => en_page_title
- }
- Mobility.with_locale(:ru) do
- _page.title = ru_page_title
- _page.save
+ Mobility.with_locale(:en) { Page.create(title: en_page_title) }.tap do |localised_page|
+ Mobility.with_locale(:ru) do
+ localised_page.title = ru_page_title
+ localised_page.save
+ end
end
-
- _page
end
it "can have a title for each locale" do
@@ -551,7 +545,7 @@ module Admin
click_link "Add new page"
switch_page_form_locale "RU"
- fill_in "Title", :with => ru_page_title
+ fill_in "Title", with: ru_page_title
click_button "Save"
expect(page).to have_selector("#page_#{Page.last.id} .actions")
@@ -560,20 +554,23 @@ module Admin
end
switch_page_form_locale "EN"
- fill_in "Title", :with => en_page_title
+ fill_in "Title", with: en_page_title
find("#submit_button").click
expect(page).to have_content("'#{en_page_title}' was successfully updated.")
expect(Refinery::Page.count).to eq(2)
end
- it "is shown with both locales in the index" do
+ it "is shown with only the non-default locale in the index" do
visit refinery.admin_pages_path
- within "#page_#{news_page.id} .locales" do
- expect(page).to have_css('.locale_marker', count: 2)
- expect(page).to have_content('EN')
- expect(page).to have_content('RU')
+ within "#page_#{news_page.id}" do
+ expect(page).to have_selector(".locales")
+
+ within ".locales" do
+ expect(page).to have_selector(locale_link_selector(locale: 'ru'))
+ expect(page).to have_no_selector(locale_link_selector(locale: 'en'))
+ end
end
end
@@ -589,7 +586,7 @@ module Admin
visit refinery.admin_pages_path
within "#page_#{news_page.id}" do
- expect(page.find('a[tooltip="Edit this page"]')[:href]).to include(en_page_slug)
+ expect(page.first(title_link_selector)[:href]).to match(en_page_slug)
end
end
@@ -610,10 +607,10 @@ module Admin
end
end
- describe "add a page with title only for secondary locale", js:true do
+ describe "add a page with title only for secondary locale", js: true do
let(:ru_page) {
Mobility.with_locale(:ru) {
- Page.create :title => ru_page_title
+ Page.create title: ru_page_title
}
}
let(:ru_page_id) { ru_page.id }
@@ -630,7 +627,7 @@ module Admin
find('a', text: 'Add new page').click
switch_page_form_locale "RU"
- fill_in "Title", :with => ru_page_title
+ fill_in "Title", with: ru_page_title
click_button "Save"
expect(page).to have_content("'#{ru_page_title}' was successfully added.")
@@ -639,13 +636,13 @@ module Admin
it "shows locale indicator for page" do
within "#page_#{ru_page_id}" do
- expect(page).to have_selector('.locale_marker', text: 'RU')
+ expect(page).to have_selector(locale_link_selector(locale: 'ru'))
end
end
it "doesn't show locale indicator for primary locale" do
within "#page_#{ru_page_id}" do
- expect(page).to_not have_selector('.locale_marker', text: 'EN')
+ expect(page).to_not have_selector(locale_picker('en'))
end
end
@@ -655,9 +652,9 @@ module Admin
end
end
- it "uses slug in admin" do
+ it "uses secondary locale slug in admin" do
within "#page_#{ru_page_id}" do
- expect(page.find('a[tooltip="Edit this page"]')[:href]).to include(ru_page_slug_encoded)
+ expect(page.find(title_link_selector)[:href]).to match(ru_page_slug_encoded)
end
end
@@ -675,23 +672,23 @@ module Admin
within "#menu" do
# we should only have the home page in the menu
- expect(page).to have_css('li', :count => 1)
+ expect(page).to have_css('li', count: 1)
end
end
context "when page is a child page" do
it 'succeeds' do
ru_page.destroy!
- parent_page = Page.create(:title => "Parent page")
+ parent_page = Page.create(title: "Parent page")
sub_page = Mobility.with_locale(:ru) {
- Page.create :title => ru_page_title, :parent_id => parent_page.id
+ Page.create title: ru_page_title, parent_id: parent_page.id
}
expect(sub_page.parent).to eq(parent_page)
visit refinery.admin_pages_path
within "#page_#{sub_page.id}" do
- find("a.edit_icon").click
+ first(edit_selector).click
end
- fill_in "Title", :with => ru_page_title
+ fill_in "Title", with: ru_page_title
click_button "Save"
expect(page).to have_content("'#{ru_page_title}' was successfully updated")
end
@@ -709,7 +706,7 @@ module Admin
find("#add_page_part").click
within "#new_page_part_dialog" do
- fill_in "new_page_part_title", :with => "testy"
+ fill_in "new_page_part_title", with: "testy"
click_button "Save"
end
@@ -720,12 +717,12 @@ module Admin
end
describe "delete existing page part" do
- let!(:some_page) { Page.create! :title => "Some Page" }
+ let!(:some_page) { Page.create! title: "Some Page" }
before do
- some_page.parts.create! :title => "First Part", :slug => "first_part", :position => 1
- some_page.parts.create! :title => "Second Part", :slug => "second_part", :position => 2
- some_page.parts.create! :title => "Third Part", :slug => "third_part", :position => 3
+ some_page.parts.create! title: "First Part", slug: "first_part", position: 1
+ some_page.parts.create! title: "Second Part", slug: "second_part", position: 2
+ some_page.parts.create! title: "Third Part", slug: "third_part", position: 3
allow(Refinery::Pages).to receive(:new_page_parts).and_return(true)
end
@@ -772,10 +769,10 @@ module Admin
allow(Refinery::Pages).to receive(:use_layout_templates).and_return(true)
allow(Refinery::Pages).to receive(:layout_template_whitelist).and_return(['abc', 'refinery'])
allow(Refinery::Pages).to receive(:valid_templates).and_return(['abc', 'refinery'])
- parent_page = Page.create :title => 'Parent Page',
- :view_template => 'refinery',
- :layout_template => 'refinery'
- @page = parent_page.children.create :title => 'Child Page'
+ parent_page = Page.create title: 'Parent Page',
+ view_template: 'refinery',
+ layout_template: 'refinery'
+ @page = parent_page.children.create title: 'Child Page'
end
specify 'sub page should inherit them', js: true do
@@ -798,7 +795,7 @@ module Admin
# regression spec for https://github.com/refinery/refinerycms/issues/1891
describe "a page part with HTML" do
before do
- page = Refinery::Page.create! :title => "test"
+ page = Refinery::Page.create! title: "test"
Refinery::Pages.default_parts.each_with_index do |default_page_part, index|
page.parts.create(
title: default_page_part[:title],
@@ -809,17 +806,17 @@ module Admin
end
end
- specify "should retain the html", js:true do
+ specify "should retain the html", js: true do
visit refinery.admin_pages_path
- find('a[tooltip="Edit this page"]').click
- Capybara.ignore_hidden_elements = false
- expect(page).to have_content("header class='regression'")
- Capybara.ignore_hidden_elements = true
+ first(edit_selector(slug: 'test')).click
+ Capybara.ignore_hidden_elements do
+ expect(page).to have_content("header class='regression'")
+ end
end
end
end
- describe "TranslatePages", :type => :system do
+ describe "TranslatePages", type: :system do
before { Mobility.locale = :en }
refinery_login
@@ -827,13 +824,13 @@ module Admin
before do
allow(Refinery::I18n).to receive(:frontend_locales).and_return([:en, :lv])
end
- let(:first_page){Page.create title: 'First Page'}
+ let(:first_page) { Page.create title: 'First Page' }
it "can have a second locale added to it" do
visit refinery.edit_admin_page_path(first_page.id)
- switch_page_form_locale "LV"
- fill_in "Title", :with => "Brīva vieta reklāmai"
+ switch_page_form_locale "lv"
+ fill_in "Title", with: "Brīva vieta reklāmai"
click_button "Save"
expect(page).to have_content("'Brīva vieta reklāmai' was successfully updated.")
@@ -847,7 +844,7 @@ module Admin
# Create a page in both locales
about_page = Mobility.with_locale(:en) do
- Page.create :title => 'About'
+ Page.create title: 'About'
end
Mobility.with_locale(:ru) do
@@ -860,7 +857,7 @@ module Admin
page = Refinery::Page.last
# we need page parts so that there's a visual editor
Refinery::Pages.default_parts.each_with_index do |default_page_part, index|
- page.parts.create(:title => default_page_part[:title], :slug => default_page_part[:slug], :body => nil, :position => index)
+ page.parts.create(title: default_page_part[:title], slug: default_page_part[:slug], body: nil, position: index)
end
page
end
@@ -870,14 +867,14 @@ module Admin
before { Refinery::Pages.absolute_page_links = false }
it "shows Russian pages if we're editing the Russian locale" do
- visit refinery.link_to_admin_pages_dialogs_path(:visual_editor => true, :switch_locale => :ru)
+ visit refinery.link_to_admin_pages_dialogs_path(visual_editor: true, switch_locale: :ru)
expect(page).to have_content("About Ru")
expect(page).to have_selector("a[href='/ru/about-ru']")
end
it "shows default to the default locale if no query string is added" do
- visit refinery.link_to_admin_pages_dialogs_path(:visual_editor => true)
+ visit refinery.link_to_admin_pages_dialogs_path(visual_editor: true)
expect(page).to have_content("About")
expect(page).to have_selector("a[href='/about']")
@@ -888,17 +885,16 @@ module Admin
before { Refinery::Pages.absolute_page_links = true }
it "shows Russian pages if we're editing the Russian locale" do
- visit refinery.link_to_admin_pages_dialogs_path(:visual_editor => true, :switch_locale => :ru)
-
+ visit refinery.link_to_admin_pages_dialogs_path(visual_editor: true, switch_locale: :ru)
expect(page).to have_content("About Ru")
- expect(page).to have_selector("a[href='http://www.example.com/ru/about-ru']")
+ expect(page).to have_selector("a[href$='ru/about-ru']")
end
it "shows default to the default locale if no query string is added" do
- visit refinery.link_to_admin_pages_dialogs_path(:visual_editor => true)
+ visit refinery.link_to_admin_pages_dialogs_path(visual_editor: true)
expect(page).to have_content("About")
- expect(page).to have_selector("a[href='http://www.example.com/about']")
+ expect(page).to have_selector("a[href$='about']")
end
end
end
diff --git a/pages/spec/system/refinery/pages_spec.rb b/pages/spec/system/refinery/pages_spec.rb
index 63212ca0150..97ed958c661 100644
--- a/pages/spec/system/refinery/pages_spec.rb
+++ b/pages/spec/system/refinery/pages_spec.rb
@@ -161,7 +161,7 @@ def standard_page_menu_items_exist?
it 'should have a canonical url' do
visit '/about-us'
- expect(page).to have_selector('head link[rel="canonical"][href^="http://www.example.com/about-us"]', visible: false)
+ expect(page).to have_selector('head link[rel="canonical"][href$="about-us"]', visible: false)
end
end
diff --git a/readme.md b/readme.md
index 4526e8173e7..736d3346c52 100644
--- a/readme.md
+++ b/readme.md
@@ -1,38 +1,32 @@
-# Refinery CMS™
+# Refinery CMS
-__An open source content management system for Rails 5.1+__
-
-More information at [https://www.refinerycms.com](https://www.refinerycms.com)
-
-[](https://travis-ci.org/refinery/refinerycms) [](https://codeclimate.com/github/refinery/refinerycms) [](https://coveralls.io/r/refinery/refinerycms?branch=master)
-
-You can chat with us using Gitter:
-
-[](https://gitter.im/refinery/refinerycms)
+__An open source content management system for Rails 6.1+ through 8.1+__
You can deploy an example app to Heroku:
[](https://heroku.com/deploy?template=https://github.com/refinery/refinerycms-example-app)
+Note that some of our docs in this README are out of date, and our website is not currently live. Please refer to our [GitHub repository](https://github.com/refinery/refinerycms) for the current status and instructions. Guides can be found in the [doc/guides](https://github.com/refinery/refinerycms/tree/main/doc/guides) folder.
+
## Requirements
-* [Bundler](http://gembundler.com)
-* [ImageMagick](http://www.imagemagick.org/script/install-source.php)
+* [Bundler](https://bundler.io/)
+* [ImageMagick](https://imagemagick.org/script/install-source.php)
* :warning: Warning: ImageMagick currently has a serious security vulnerability, CVE-2016–3714. After installing, you must disable certain features in ImageMagick's policy configuration. Please see the following for details:
* https://imagetragick.com/
* Mac OS X users should use [homebrew's](https://github.com/mxcl/homebrew/wiki/installation) `brew install imagemagick` or the [magick-installer](https://github.com/maddox/magick-installer).
## How to
-* __[Install Refinery CMS™](https://www.refinerycms.com/download)__
-* [Install Refinery CMS™ on Heroku](https://www.refinerycms.com/guides/heroku)
-* [Contribute to Refinery CMS™](readme.md#contributing)
+* __[Install Refinery CMS](https://www.refinerycms.com/download)__
+* [Install Refinery CMS on Heroku](https://github.com/refinery/refinerycms/blob/main/doc/guides/7%20-%20Hosting%20and%20Deployment/1%20-%20Heroku.md)
+* [Contribute to Refinery CMS](readme.md#contributing)
## Getting Started
If you're new to Refinery, start with this guide:
-* __[Getting Started](https://www.refinerycms.com/guides/getting-started)__
+* __[Getting Started](https://github.com/refinery/refinerycms/tree/main/doc/guides/1%20-%20Getting%20Started)__
For Rails 5.1+ support, you can use version `4.0.x` using this template:
@@ -57,14 +51,12 @@ Unlike other content managers, Refinery is truly __aimed at the end user__ makin
* Easily customise the look to suit the business.
* __Extend with custom extensions__ to do anything Refinery doesn't do out of the box.
* Sticks to __"the Rails way"__ as much as possible; we don't force you to learn new templating languages.
-* Uses [jQuery](http://jquery.com/) for fast and concise Javascript.
+* Uses [jQuery](http://jquery.com/) for now, for fast and concise Javascript.
## Help and Documentation
-* [Getting Started](https://www.refinerycms.com/guides/getting-started)
-* [Guides](https://www.refinerycms.com/guides)
-* [Google Group Discussion](https://groups.google.com/forum/#!forum/refinery-cms)
-* [Gitter chat](https://gitter.im/refinery/refinerycms)
+* [Getting Started](https://github.com/refinery/refinerycms/tree/main/doc/guides/1%20-%20Getting%20Started)
+* [Google Group Discussion](https://groups.google.com/g/refinery-cms)
* [GitHub repository](https://github.com/refinery/refinerycms)
* [Developer/API documentation](http://rubydoc.info/github/refinery/refinerycms)
* [Twitter Account](https://twitter.com/refinerycms)
@@ -112,13 +104,13 @@ For help run the command without any options:
## Contributing
See [contributing.md](contributing.md)
-and [Contributing to Refinery](https://www.refinerycms.com/guides/contributing-to-refinery)
+and [Contributing to Refinery](https://github.com/refinery/refinerycms/blob/main/doc/guides/8%20-%20Contributing/1%20-%20Contributing%20to%20Refinery.md)
guide for details about contributing and running test.
## License
-Refinery CMS™ is released under the MIT license. See the [license.md file](license.md#readme) for details.
+Refinery CMS is released under the MIT license. See the [license.md file](license.md#readme) for details.
### Credits
-Many of the icons used in Refinery CMS™ are from the wonderful [Silk library by Mark James](http://www.famfamfam.com/lab/icons/silk/).
+Many of the icons used in Refinery CMS are from the wonderful [Silk library by Mark James](http://www.famfamfam.com/lab/icons/silk/).
diff --git a/refinerycms.gemspec b/refinerycms.gemspec
index 6a88a5b7a55..5642c52095e 100644
--- a/refinerycms.gemspec
+++ b/refinerycms.gemspec
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = 'refinerycms'
s.version = version
- s.description = "A CMS for Ruby on Rails, supporting Rails 6+. It's developer friendly and easy to extend."
- s.summary = 'A CMS for Ruby on Rails, supporting Rails 6+'
+ s.description = "A CMS for Ruby on Rails, supporting Rails 6.1+. It's developer friendly and easy to extend."
+ s.summary = 'A CMS for Ruby on Rails, supporting Rails 6.1+'
s.email = 'gems@p.arndt.io'
s.homepage = 'https://www.refinerycms.com'
s.authors = ['Philip Arndt', 'David Jones', 'Uģis Ozols', 'Brice Sanchez']
@@ -24,6 +24,8 @@ Gem::Specification.new do |s|
s.add_dependency 'refinerycms-images', version
s.add_dependency 'refinerycms-pages', version
s.add_dependency 'refinerycms-resources', version
+
+ s.add_development_dependency 'rspec-rails'
s.required_ruby_version = Refinery::Version.required_ruby_version
s.cert_chain = [File.expand_path('certs/parndt.pem', __dir__)]
diff --git a/resources/app/controllers/refinery/admin/resources_controller.rb b/resources/app/controllers/refinery/admin/resources_controller.rb
index 4c8c2a45682..1700aaf0407 100644
--- a/resources/app/controllers/refinery/admin/resources_controller.rb
+++ b/resources/app/controllers/refinery/admin/resources_controller.rb
@@ -1,9 +1,11 @@
module Refinery
module Admin
class ResourcesController < ::Refinery::AdminController
+ helper Refinery::Admin::ResourceHelper
crudify :'refinery/resource',
include: [:translations],
+ exclude_from_find: :show,
order: "updated_at DESC",
sortable: false
@@ -62,9 +64,9 @@ def insert
@resource_area_selected = from_dialog?
if params[:visual_editor]
- render '/refinery/admin/pages_dialogs/link_to'
- else
- render 'insert'
+ render '/refinery/admin/pages_dialogs/link_to'
+ else
+ render 'insert'
end
end
diff --git a/resources/app/helpers/refinery/admin/resource_helper.rb b/resources/app/helpers/refinery/admin/resource_helper.rb
new file mode 100644
index 00000000000..5b529a8a264
--- /dev/null
+++ b/resources/app/helpers/refinery/admin/resource_helper.rb
@@ -0,0 +1,10 @@
+module Refinery
+ module Admin
+ module ResourceHelper
+
+ def resource_meta_information(resource)
+ tag.span number_to_human_size(resource.size), class: [:label, :meta]
+ end
+ end
+ end
+end
diff --git a/resources/app/views/refinery/admin/resources/_form.html.erb b/resources/app/views/refinery/admin/resources/_form.html.erb
index 806d6347278..397fd3abbc3 100644
--- a/resources/app/views/refinery/admin/resources/_form.html.erb
+++ b/resources/app/views/refinery/admin/resources/_form.html.erb
@@ -57,4 +57,4 @@
link_dialog.init();
});
-<% end if from_dialog? %>
\ No newline at end of file
+<% end if from_dialog? %>
diff --git a/resources/app/views/refinery/admin/resources/_resource.html.erb b/resources/app/views/refinery/admin/resources/_resource.html.erb
index 86c16b44d54..5225e6e623c 100644
--- a/resources/app/views/refinery/admin/resources/_resource.html.erb
+++ b/resources/app/views/refinery/admin/resources/_resource.html.erb
@@ -1,33 +1,15 @@
<%
+ # setup params for various action links
edit_url = refinery.edit_admin_resource_path(resource)
delete_url = refinery.admin_resource_path(resource)
- delete_options = {data: {confirm: t('message', scope: 'refinery.admin.delete', title: resource.title)}}
+ delete_options = {data: {confirm: t('message', scope: 'refinery.admin.delete', title: translated_field(resource, :title))}}
+ translated_locales = locales_with_translated_field(resource, 'resource_title')
%>
-