Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support selecting multiple fragments #670

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 17 additions & 4 deletions lib/phlex/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,32 @@ def initialize(user_context = {})
@buffer = +""
@capturing = false
@user_context = user_context
@fragment = nil
@fragments = nil
@in_target_fragment = false
@found_target_fragment = false
end

attr_accessor :buffer, :capturing, :user_context, :fragment,
:in_target_fragment, :found_target_fragment
attr_accessor :buffer, :capturing, :user_context, :in_target_fragment

attr_reader :fragments

# Added for backwards compatibility with phlex-rails. We can remove this with 2.0
def target
@buffer
end

def target_fragments(fragments)
@fragments = fragments.to_h { |it| [it, true] }
end

def begin_target(id)
@in_target_fragment = id
end

def end_target
@fragments.delete(@in_target_fragment)
@in_target_fragment = false
end

def capturing_into(new_buffer)
original_buffer = @buffer
original_capturing = @capturing
Expand Down
35 changes: 20 additions & 15 deletions lib/phlex/elements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,18 @@ def #{method_name}(**attributes, &block)

context = @_context
buffer = context.buffer
fragment = context.fragment
end_find = false
fragment = context.fragments
target_found = false

if fragment
in_target_fragment = context.in_target_fragment
return if fragment.length == 0 # we found all our fragments already

if !in_target_fragment
if !context.found_target_fragment && attributes[:id] == fragment
context.in_target_fragment = true
context.found_target_fragment = true
end_find = true
id = attributes[:id]

if !context.in_target_fragment
if fragment[id]
context.begin_target(id)
target_found = true
else
yield(self) if block
return nil
Expand Down Expand Up @@ -83,8 +84,7 @@ def #{method_name}(**attributes, &block)

#{'flush' if tag == 'head'}

# I think we can actually throw from here.
context.in_target_fragment = false if end_find
context.end_target if target_found

nil
end
Expand Down Expand Up @@ -114,14 +114,17 @@ def #{method_name}(**attributes)
#{deprecation}
context = @_context
buffer = context.buffer
fragment = context.fragment
fragment = context.fragments

if fragment
in_target_fragment = context.in_target_fragment
return if fragment.length == 0 # we found all our fragments already

id = attributes[:id]

if !in_target_fragment
if !context.found_target_fragment && attributes[:id] == fragment
context.found_target_fragment = true
if !context.in_target_fragment
if fragment[id]
context.begin_target(id)
target_found = true
else
return nil
end
Expand All @@ -134,6 +137,8 @@ def #{method_name}(**attributes)
buffer << "<#{tag}>"
end

context.end_target if target_found

nil
end

Expand Down
2 changes: 1 addition & 1 deletion lib/phlex/html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __unbuffered_class__
# Output an HTML doctype.
def doctype
context = @_context
return if context.fragment && !context.in_target_fragment
return if context.fragments && !context.in_target_fragment

context.buffer << "<!DOCTYPE html>"
nil
Expand Down
12 changes: 6 additions & 6 deletions lib/phlex/sgml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ def call(...)
end

# @api private
def __final_call__(buffer = +"", context: Phlex::Context.new, view_context: nil, parent: nil, fragment: nil, &block)
def __final_call__(buffer = +"", context: Phlex::Context.new, view_context: nil, parent: nil, fragments: nil, &block)
@_buffer = buffer
@_context = context
@_view_context = view_context
@_parent = parent
@_context.fragment = fragment if fragment
@_context.target_fragments(fragments) if fragments

block ||= @_content_block

Expand Down Expand Up @@ -147,7 +147,7 @@ def context
# @see #format_object
def plain(content)
context = @_context
return if context.fragment && !context.in_target_fragment
return if context.fragments && !context.in_target_fragment

unless __text__(content)
raise ArgumentError, "You've passed an object to plain that is not handled by format_object. See https://rubydoc.info/gems/phlex/Phlex/SGML#format_object-instance_method for more information"
Expand All @@ -161,7 +161,7 @@ def plain(content)
# @yield If a block is given, it yields the block with no arguments.
def whitespace(&block)
context = @_context
return if context.fragment && !context.in_target_fragment
return if context.fragments && !context.in_target_fragment

buffer = context.buffer

Expand All @@ -179,7 +179,7 @@ def whitespace(&block)
# @return [nil]
def comment(&block)
context = @_context
return if context.fragment && !context.in_target_fragment
return if context.fragments && !context.in_target_fragment

buffer = context.buffer

Expand All @@ -197,7 +197,7 @@ def unsafe_raw(content = nil)
return nil unless content

context = @_context
return if context.fragment && !context.in_target_fragment
return if context.fragments && !context.in_target_fragment

context.buffer << content
nil
Expand Down
13 changes: 10 additions & 3 deletions test/phlex/selective_rendering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def view_template
strong { "World" }
img(src: "image.jpg")
}
img(src: "after.jpg")
strong { "Here" }
img(id: "image", src: "after.jpg")
h1(id: "target") { "After" }
}
end
Expand Down Expand Up @@ -43,13 +44,19 @@ def view_template
describe Phlex::HTML do
it "renders the just the target fragment" do
expect(
StandardElementExample.new.call(fragment: "target")
StandardElementExample.new.call(fragments: ["target"])
).to be == %(<h1 id="target">Hello<strong>World</strong><img src="image.jpg"></h1>)
end

it "works with void elements" do
expect(
VoidElementExample.new.call(fragment: "target")
VoidElementExample.new.call(fragments: ["target"])
).to be == %(<img id="target" src="image.jpg">)
end

it "supports multiple fragments" do
expect(
StandardElementExample.new.call(fragments: ["target", "image"])
).to be == %(<h1 id="target">Hello<strong>World</strong><img src="image.jpg"></h1><img id="image" src="after.jpg">)
end
end