phlex icon indicating copy to clipboard operation
phlex copied to clipboard

Inline tags declaration

Open Xanderwot opened this issue 1 year ago • 2 comments

Hi everyone,

I have a question (more like an advice) about phlex tag registration improvement.

We are doing a migration from another rendering gem (fortitude) to phlex and have a lot of legacy code, which supports both block and inline tags:

div do
  'Some content'
end

# returns same result
div 'Some content'

I did patch register_element method here like this:

def #{method_name}(inline_content = nil, **attributes, &block)
#...
          elsif inline_content.present? # with inline content
            buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[respond_to?(:process_attributes) ? (attributes.hash + self.class.hash) : attributes.hash] || __attributes__(**attributes)) << ">"
            inline_content_block = Proc.new { inline_content }
            yield_content(&inline_content_block)
            buffer << "</#{tag}>"
          else
#...
end

(without attributes part also updated)

to support both approaches and its works pretty good in most of places except some specific cases.

After applying this patch to a Phlex::HTML::StandardElements

Phlex::HTML::StandardElements.module_eval { extend PhlexElementRegisterer }

and re-registering all elements with patched register_element method:

Phlex::HTML::StandardElements.registered_elements.each do |method_name, tag|
  Phlex::HTML::StandardElements.register_element(method_name, tag: tag)
end

For example nested tags like tables:

table do 
  tr do 
    td 'Content'
  end
end

generate expected html:

<table>
  <tr>
    <td>Content</td>
  </tr>
</table>

but if I do something more specific:

table do 
  tr do 
    td div { 'Content' }
  end
end

it moves div block outside table tag:

<div>Content</div>
<table>
  <tr>
    <td></td>
  </tr>
</table>

When debugging I see that the div tag method was called with &block and after it the td method also called, but without any arguments or even a block.

As a second example it happens not only with table tag:

def link_tag(text)
  div do
    link_to(text, '#')
  end
end

div class: 'first_nested' do
  div class: 'second_nested' do
    div link_tag('something'), class: 'third_nested'
  end
end

Will return:

<div class="first_nested">
  <div class="second_nested">
    <div><a href="#">something</a></div>
    <div class="third_nested"></div>
  </div>
</div>

Maybe you will see how this issue can be solved? If solved, will this approach (supporting inline tags) be acceptable, as a future patch, to phlex (after it will be stable and test covered)?

Thanks!

Xanderwot avatar Aug 20 '24 17:08 Xanderwot