diff --git a/app/components/alchemy/admin/link_dialog/anchor_tab.rb b/app/components/alchemy/admin/link_dialog/anchor_tab.rb new file mode 100644 index 0000000000..6ed0bec6dc --- /dev/null +++ b/app/components/alchemy/admin/link_dialog/anchor_tab.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Alchemy + module Admin + module LinkDialog + class AnchorTab < BaseTab + def title + Alchemy.t("link_overlay_tab_label.anchor") + end + + def name + :anchor + end + + def fields + [ + anchor_select, + title_input + ] + end + + def message + render_message(:info, content_tag("p", Alchemy.t(:anchor_link_headline))) + end + + private + + def anchor_select + label = label_tag("anchor_link", Alchemy.t(:anchor), class: "control-label") + select = select_tag(:anchor_link, + options_for_select([[Alchemy.t("Please choose"), ""]]), + is: "alchemy-select") + content_tag("div", label + select, class: "input select") + end + end + end + end +end diff --git a/app/components/alchemy/admin/link_dialog/base_tab.rb b/app/components/alchemy/admin/link_dialog/base_tab.rb new file mode 100644 index 0000000000..132bc54e07 --- /dev/null +++ b/app/components/alchemy/admin/link_dialog/base_tab.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module Alchemy + module Admin + module LinkDialog + class BaseTab < ViewComponent::Base + include BaseHelper + + erb_template <<~ERB + <%= title %> + +
+ <%= message %> + <% fields.each do |field| %> + <%= field %> + <% end %> +
+ <%= button_tag(Alchemy.t(:apply)) %> +
+
+
+ ERB + + def title + raise ArgumentError, "The tab needs to have a title" + end + + def name + raise ArgumentError, "The tab needs to have a name" + end + + def fields + [] + end + + def message + "" + end + + private + + def panel_name + "overlay_tab_#{name}_link" + end + + def title_input + input_name = "#{name}_link_title" + label = label_tag(input_name, Alchemy.t(:link_title), class: "control-label") + input = text_field_tag input_name, "", class: "link_title" + content_tag("div", label + input, class: "input text") + end + + def target_select + select_name = "#{name}_link_target" + label = label_tag(select_name, Alchemy.t("Open Link in"), class: "control-label") + select = select_tag(select_name, options_for_select(Alchemy::Page.link_target_options, @target), class: "link_target") + content_tag("div", label + select, class: "input select") + end + end + end + end +end diff --git a/app/components/alchemy/admin/link_dialog/external_tab.rb b/app/components/alchemy/admin/link_dialog/external_tab.rb new file mode 100644 index 0000000000..90fac119da --- /dev/null +++ b/app/components/alchemy/admin/link_dialog/external_tab.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Alchemy + module Admin + module LinkDialog + class ExternalTab < BaseTab + def title + Alchemy.t("link_overlay_tab_label.external") + end + + def name + :external + end + + def fields + [ + url_input, + title_input, + target_select + ] + end + + def message + main_message = content_tag("h3", Alchemy.t(:enter_external_link)) + + content_tag("p", Alchemy.t(:external_link_notice_1)) + + content_tag("p", Alchemy.t(:external_link_notice_2)) + + render_message(:info, main_message) + + content_tag("div", content_tag("ul"), id: "errors", class: "errors") + end + + private + + def url_input + label = label_tag("external_link", "URL", class: "control-label") + input = text_field_tag "external_link", "" + content_tag("div", label + input, class: "input text") + end + end + end + end +end diff --git a/app/components/alchemy/admin/link_dialog/file_tab.rb b/app/components/alchemy/admin/link_dialog/file_tab.rb new file mode 100644 index 0000000000..abd6cf12ba --- /dev/null +++ b/app/components/alchemy/admin/link_dialog/file_tab.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Alchemy + module Admin + module LinkDialog + class FileTab < BaseTab + delegate :alchemy, to: :helpers + + def title + Alchemy.t("link_overlay_tab_label.file") + end + + def name + :file + end + + def fields + [ + attachment_select, + title_input, + target_select + ] + end + + def message + render_message(:info, content_tag("h3", Alchemy.t(:choose_file_to_link))) + end + + private + + def attachments + @_attachments ||= Attachment.all.collect { |f| + [f.name, alchemy.download_attachment_path(id: f.id, name: f.slug)] + } + end + + def attachment_select + label = label_tag("file_link", Alchemy.t(:file), class: "control-label") + select = select_tag "file_link", + options_for_select(attachments), + prompt: Alchemy.t("Please choose"), + is: "alchemy-select" + content_tag("div", label + select, class: "input select") + end + end + end + end +end diff --git a/app/components/alchemy/admin/link_dialog/internal_tab.rb b/app/components/alchemy/admin/link_dialog/internal_tab.rb new file mode 100644 index 0000000000..9e6865155f --- /dev/null +++ b/app/components/alchemy/admin/link_dialog/internal_tab.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Alchemy + module Admin + module LinkDialog + class InternalTab < BaseTab + def title + Alchemy.t("link_overlay_tab_label.internal") + end + + def name + :internal + end + + def fields + [ + page_select, + dom_id_select, + title_input, + target_select + ] + end + + def message + main_message = content_tag("h3", Alchemy.t(:internal_link_headline)) + + content_tag("p", Alchemy.t(:internal_link_page_elements_explanation)) + render_message(:info, main_message) + end + + private + + def page_select + label = label_tag("internal_link", Alchemy.t(:page), class: "control-label") + input = text_field_tag("internal_link", "", id: "internal_link", class: "alchemy_selectbox full_width") + content_tag("div", label + input, class: "input select") + end + + def dom_id_select + label = label_tag("element_anchor", Alchemy.t(:anchor), class: "control-label") + options = {id: "element_anchor", class: "alchemy_selectbox full_width", disabled: true, placeholder: Alchemy.t("Select a page first")} + input = text_field_tag("element_anchor", nil, options) + content_tag("div", label + input, class: "input select") + end + end + end + end +end diff --git a/app/components/alchemy/admin/link_dialog/tabs.rb b/app/components/alchemy/admin/link_dialog/tabs.rb new file mode 100644 index 0000000000..8554e4c9e1 --- /dev/null +++ b/app/components/alchemy/admin/link_dialog/tabs.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Alchemy + module Admin + module LinkDialog + class Tabs < ViewComponent::Base + erb_template <<~ERB + + <% tabs.each do |tab| %> + <%= render tab.new %> + <% end %> + + ERB + + def tabs + Alchemy.link_dialog_tabs + end + end + end + end +end diff --git a/app/controllers/alchemy/admin/pages_controller.rb b/app/controllers/alchemy/admin/pages_controller.rb index 1cea2287f1..4b37425793 100644 --- a/app/controllers/alchemy/admin/pages_controller.rb +++ b/app/controllers/alchemy/admin/pages_controller.rb @@ -163,9 +163,7 @@ def destroy end def link - @attachments = Attachment.all.collect { |f| - [f.name, download_attachment_path(id: f.id, name: f.slug)] - } + render LinkDialog::Tabs.new end def fold diff --git a/app/views/alchemy/admin/pages/_anchor_link.html.erb b/app/views/alchemy/admin/pages/_anchor_link.html.erb deleted file mode 100644 index 64b44e4e50..0000000000 --- a/app/views/alchemy/admin/pages/_anchor_link.html.erb +++ /dev/null @@ -1,22 +0,0 @@ -
- <%= render_message do %> -

<%= Alchemy.t(:anchor_link_headline) %>

- <% end %> -
- - <%= select_tag(:anchor_link, - options_for_select([[Alchemy.t('Please choose'), '']]), - is: 'alchemy-select') %> -
-
- - <%= text_field_tag "anchor_link_title", '', class: 'link_title' %> -
-
- <%= button_tag Alchemy.t(:apply) %> -
-
diff --git a/app/views/alchemy/admin/pages/_external_link.html.erb b/app/views/alchemy/admin/pages/_external_link.html.erb deleted file mode 100644 index e6e21653b5..0000000000 --- a/app/views/alchemy/admin/pages/_external_link.html.erb +++ /dev/null @@ -1,31 +0,0 @@ -
- <%= render_message do %> -

<%= Alchemy.t(:enter_external_link) %>

-

<%= Alchemy.t(:external_link_notice_1) %>

-

<%= Alchemy.t(:external_link_notice_2) %>

- <% end %> -
- -
-
- - <%= text_field_tag "external_link" %> -
-
- - <%= text_field_tag "external_link_title", '', class: 'link_title' %> -
-
- - <%= select_tag 'external_link_target', - options_for_select(Alchemy::Page.link_target_options), - class: 'link_target' %> -
-
- <%= button_tag Alchemy.t(:apply) %> -
-
diff --git a/app/views/alchemy/admin/pages/_file_link.html.erb b/app/views/alchemy/admin/pages/_file_link.html.erb deleted file mode 100644 index 355d3adaf5..0000000000 --- a/app/views/alchemy/admin/pages/_file_link.html.erb +++ /dev/null @@ -1,31 +0,0 @@ -
- <%= render_message do %> -

<%= Alchemy.t(:choose_file_to_link) %>

- <% end %> -
- - <%= select_tag "file_link", - options_for_select(@attachments), - prompt: Alchemy.t('Please choose'), - is: "alchemy-select" %> -
-
- - <%= text_field_tag "file_link_title", '', class: 'link_title' %> -
-
- - <%= select_tag 'file_link_target', - options_for_select(Alchemy::Page.link_target_options), - class: 'link_target' %> -
-
- <%= button_tag Alchemy.t(:apply) %> -
-
diff --git a/app/views/alchemy/admin/pages/_internal_link.html.erb b/app/views/alchemy/admin/pages/_internal_link.html.erb deleted file mode 100644 index 7280ec8f3c..0000000000 --- a/app/views/alchemy/admin/pages/_internal_link.html.erb +++ /dev/null @@ -1,35 +0,0 @@ -
- <%= render_message do %> -

<%= Alchemy.t(:internal_link_headline) %>

-

<%= Alchemy.t(:internal_link_page_elements_explanation) %>

- <% end %> -
- - -
-
- - -
-
- - <%= text_field_tag "internal_link_title", '', class: 'link_title' %> -
-
- - <%= select_tag 'internal_link_target', - options_for_select(Alchemy::Page.link_target_options), - class: 'link_target' %> -
-
- <%= button_tag Alchemy.t(:apply) %> -
-
diff --git a/app/views/alchemy/admin/pages/link.html.erb b/app/views/alchemy/admin/pages/link.html.erb deleted file mode 100644 index 733e4a51be..0000000000 --- a/app/views/alchemy/admin/pages/link.html.erb +++ /dev/null @@ -1,26 +0,0 @@ - - - <%= Alchemy.t('link_overlay_tab_label.internal') %> - - - <%= Alchemy.t('link_overlay_tab_label.anchor') %> - - - <%= Alchemy.t('link_overlay_tab_label.external') %> - - - <%= Alchemy.t('link_overlay_tab_label.file') %> - - - <%= render partial: 'internal_link' %> - - - <%= render partial: 'anchor_link' %> - - - <%= render partial: 'external_link' %> - - - <%= render partial: 'file_link' %> - - diff --git a/lib/alchemy.rb b/lib/alchemy.rb index b4cc25d568..04435e7129 100644 --- a/lib/alchemy.rb +++ b/lib/alchemy.rb @@ -102,4 +102,40 @@ def self.publish_targets # JS Importmap instance singleton_class.attr_accessor :importmap self.importmap = Importmap::Map.new + + # Configure tabs in the link dialog + # + # With this configuration that tabs in the link dialog can be extended + # without overwriting or defacing the Admin Interface. + # + # == Example + # + # # components/acme/link_tab.rb + # module Acme + # class LinkTab < ::Alchemy::Admin::LinkDialog::BaseTab + # def title + # "Awesome Tab Title" + # end + # + # def name + # :unique_name + # end + # + # def fields + # [ title_input, target_select ] + # end + # end + # end + # + # # config/initializers/alchemy.rb + # Alchemy.link_dialog_tabs << Acme::LinkTab + # + def self.link_dialog_tabs + @_link_dialog_tabs ||= Set.new([ + Alchemy::Admin::LinkDialog::InternalTab, + Alchemy::Admin::LinkDialog::AnchorTab, + Alchemy::Admin::LinkDialog::ExternalTab, + Alchemy::Admin::LinkDialog::FileTab + ]) + end end diff --git a/spec/components/alchemy/admin/link_dialog/anchor_tab_spec.rb b/spec/components/alchemy/admin/link_dialog/anchor_tab_spec.rb new file mode 100644 index 0000000000..e39de4a6a6 --- /dev/null +++ b/spec/components/alchemy/admin/link_dialog/anchor_tab_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::Admin::LinkDialog::AnchorTab, type: :component do + before do + render_inline(described_class.new) + end + + it "should have an anchor select" do + expect(page).to have_selector("select[name=anchor_link] option") + end + + it "should have a title input" do + expect(page).to have_selector("input[name=anchor_link_title]") + end +end diff --git a/spec/components/alchemy/admin/link_dialog/base_tab_spec.rb b/spec/components/alchemy/admin/link_dialog/base_tab_spec.rb new file mode 100644 index 0000000000..6df9271230 --- /dev/null +++ b/spec/components/alchemy/admin/link_dialog/base_tab_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "rails_helper" + +class BaseTestTab < Alchemy::Admin::LinkDialog::BaseTab + delegate :render_message, to: :helpers + + def title + "Base Test Tab" + end + + def name + :base_test + end + + def fields + [ + title_input, + target_select + ] + end +end + +RSpec.describe Alchemy::Admin::LinkDialog::BaseTab, type: :component do + before do + render_inline(BaseTestTab.new) + end + + it "should render a tab with a panel" do + expect(page).to have_selector("sl-tab[panel='overlay_tab_base_test_link']") + expect(page).to have_selector("sl-tab-panel[name='overlay_tab_base_test_link']") + end + + it "should have a title" do + expect(page).to have_text("Base Test Tab") + end + + it "should allow to add title input" do + expect(page).to have_selector("input[name=base_test_link_title]") + end + + it "should allow to add target select" do + expect(page).to have_selector("select[name=base_test_link_target]") + end +end diff --git a/spec/components/alchemy/admin/link_dialog/external_tab_spec.rb b/spec/components/alchemy/admin/link_dialog/external_tab_spec.rb new file mode 100644 index 0000000000..caae666c5a --- /dev/null +++ b/spec/components/alchemy/admin/link_dialog/external_tab_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::Admin::LinkDialog::ExternalTab, type: :component do + before do + render_inline(described_class.new) + end + + it "should have an url input" do + expect(page).to have_selector("input[name=external_link]") + end + + it "should have a title input" do + expect(page).to have_selector("input[name=external_link_title]") + end + + it "should have a target select" do + expect(page).to have_selector("select[name=external_link_target]") + end +end diff --git a/spec/components/alchemy/admin/link_dialog/file_tab_spec.rb b/spec/components/alchemy/admin/link_dialog/file_tab_spec.rb new file mode 100644 index 0000000000..c3c8658ff4 --- /dev/null +++ b/spec/components/alchemy/admin/link_dialog/file_tab_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::Admin::LinkDialog::FileTab, type: :component do + let!(:attachment) { create(:alchemy_attachment) } + let(:url) { Alchemy::Engine.routes.url_helpers.download_attachment_path(id: attachment.id, name: attachment.slug) } + + before do + render_inline(described_class.new) + end + + it "should render a pre-filled file select" do + expect(page.find(:css, "select[name=file_link] option:last-child").value).to eq(url) + end + + it "should have a title input" do + expect(page).to have_selector("input[name=file_link_title]") + end + + it "should have a target select" do + expect(page).to have_selector("select[name=file_link_target]") + end +end diff --git a/spec/components/alchemy/admin/link_dialog/internal_tab_spec.rb b/spec/components/alchemy/admin/link_dialog/internal_tab_spec.rb new file mode 100644 index 0000000000..2282afcb87 --- /dev/null +++ b/spec/components/alchemy/admin/link_dialog/internal_tab_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::Admin::LinkDialog::InternalTab, type: :component do + before do + render_inline(described_class.new) + end + + it "should have an url input" do + expect(page).to have_selector("input[name=internal_link]") + end + + it "should have a dom id select" do + expect(page).to have_selector("input[name=element_anchor]") + end + + it "should have a title input" do + expect(page).to have_selector("input[name=internal_link_title]") + end + + it "should have a target select" do + expect(page).to have_selector("select[name=internal_link_target]") + end +end diff --git a/spec/features/admin/link_overlay_spec.rb b/spec/features/admin/link_overlay_spec.rb index 42d02d1531..dc52a93325 100644 --- a/spec/features/admin/link_overlay_spec.rb +++ b/spec/features/admin/link_overlay_spec.rb @@ -2,6 +2,20 @@ require "rails_helper" +class TestTab < Alchemy::Admin::LinkDialog::BaseTab + def title + "Test Tab" + end + + def name + :test_tab + end + + def fields + [title_input, target_select] + end +end + RSpec.describe "Link overlay", type: :system do let!(:language) { create(:alchemy_language) } @@ -29,6 +43,17 @@ visit link_admin_pages_path within("#overlay_tabs") { expect(page).to have_content("File") } end + + context "add new tab" do + before do + Alchemy.link_dialog_tabs << TestTab + end + + it "has a new tab" do + visit link_admin_pages_path + within("#overlay_tabs") { expect(page).to have_content("Test Tab") } + end + end end context "linking pages", js: true do