diff --git a/app/models/alchemy/element.rb b/app/models/alchemy/element.rb index c51782b906..280b201e48 100644 --- a/app/models/alchemy/element.rb +++ b/app/models/alchemy/element.rb @@ -142,6 +142,18 @@ def new(attributes = {}) super(element_definition.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES)) end + # The class responsible for the +dom_id+ of elements. + # Defaults to +Alchemy::Element::DomId+. + def dom_id_class + @_dom_id_class || DomId + end + + # Register a custom +DomId+ class responsible for the +dom_id+ of elements. + # Defaults to +Alchemy::Element::DomId+. + def dom_id_class=(klass) + @_dom_id_class = klass + end + # This methods does a copy of source and all depending contents and all of their depending essences. # # == Options diff --git a/app/models/alchemy/element/dom_id.rb b/app/models/alchemy/element/dom_id.rb new file mode 100644 index 0000000000..589ca0a4ba --- /dev/null +++ b/app/models/alchemy/element/dom_id.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Alchemy + # Returns a dom id used for elements html id tag. + # + # Uses the elements name and its position on the page. + # If the element is nested in a parent element it prefixes + # the id with the parent elements dom_id. + # + # Register your own dom id class with + # + # Alchemy::Element.dom_id_class = MyDomIdClass + # + class Element < BaseRecord + class DomId + def initialize(element) + @element = element + @parent_element = element.parent_element + end + + def call + [parent_element&.dom_id, element.name, element.position].compact.join("-") + end + + private + + attr_reader :element, :parent_element + end + end +end diff --git a/app/models/alchemy/element/presenters.rb b/app/models/alchemy/element/presenters.rb index 3ce0340f44..ebc23c6935 100644 --- a/app/models/alchemy/element/presenters.rb +++ b/app/models/alchemy/element/presenters.rb @@ -82,7 +82,7 @@ def display_name_with_preview_text(maxlength = 30) # Returns a dom id used for elements html id tag. # def dom_id - [parent_element&.dom_id, name, position].compact.join("-") + self.class.dom_id_class.new(self).call end # The content that's used for element's preview text. diff --git a/spec/models/alchemy/element/dom_id_spec.rb b/spec/models/alchemy/element/dom_id_spec.rb new file mode 100644 index 0000000000..fe61d4299f --- /dev/null +++ b/spec/models/alchemy/element/dom_id_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::Element::DomId do + describe "#call" do + subject(:dom_id) do + described_class.new(element).call + end + + let(:element) { build_stubbed(:alchemy_element, position: 1) } + + it "returns a string from element name and position" do + expect(dom_id).to eq("#{element.name}-#{element.position}") + end + + context "with a parent element" do + let(:parent_element) do + build_stubbed(:alchemy_element, position: 1) + end + + let(:element) do + build_stubbed(:alchemy_element, position: 1, parent_element: parent_element) + end + + it "returns a string from element name and position" do + expect(dom_id).to eq("#{parent_element.name}-#{parent_element.position}-#{element.name}-#{element.position}") + end + end + end +end diff --git a/spec/models/alchemy/element_spec.rb b/spec/models/alchemy/element_spec.rb index a7d94aeec7..037da37cbe 100644 --- a/spec/models/alchemy/element_spec.rb +++ b/spec/models/alchemy/element_spec.rb @@ -151,6 +151,27 @@ module Alchemy end end + describe ".dom_id_class" do + it "defaults to Alchemy::Element::DomId" do + expect(described_class.dom_id_class).to eq(Alchemy::Element::DomId) + end + end + + describe ".dom_id_class=" do + let(:dummy_dom_id) { Class.new } + + around do |example| + default_class = described_class.dom_id_class + described_class.dom_id_class = dummy_dom_id + example.run + described_class.dom_id_class = default_class + end + + it "sets the dom id class" do + expect(described_class.dom_id_class).to eq(dummy_dom_id) + end + end + describe ".copy" do subject { Element.copy(element) } @@ -543,22 +564,9 @@ module Alchemy describe "#dom_id" do let(:element) { build_stubbed(:alchemy_element, position: 1) } - it "returns a string from element name and position" do - expect(element.dom_id).to eq("#{element.name}-#{element.position}") - end - - context "with a parent element" do - let(:parent_element) do - build_stubbed(:alchemy_element, position: 1) - end - - let(:element) do - build_stubbed(:alchemy_element, position: 1, parent_element: parent_element) - end - - it "returns a string from element name and position" do - expect(element.dom_id).to eq("#{parent_element.name}-#{parent_element.position}-#{element.name}-#{element.position}") - end + it "calls dom id class" do + expect(Alchemy::Element.dom_id_class).to receive(:new).with(element).and_call_original + element.dom_id end end