Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/phlex-ruby/phlex
Browse files Browse the repository at this point in the history
joeldrapper committed Mar 2, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 61bb641 + f42f824 commit 841748e
Showing 5 changed files with 120 additions and 10 deletions.
5 changes: 4 additions & 1 deletion lib/phlex/context.rb
Original file line number Diff line number Diff line change
@@ -5,9 +5,12 @@ class Phlex::Context
def initialize
@buffer = +""
@capturing = false
@fragment = nil
@in_target_fragment = false
@found_target_fragment = false
end

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

# Added for backwards compatibility with phlex-rails. We can remove this with 2.0
def target
40 changes: 38 additions & 2 deletions lib/phlex/elements.rb
Original file line number Diff line number Diff line change
@@ -42,7 +42,26 @@ def register_element(method_name, tag: method_name.name.tr("_", "-"), deprecated
def #{method_name}(**attributes, &block)
#{deprecation}
buffer = @_context.buffer
context = @_context
buffer = context.buffer
fragment = context.fragment
end_find = false
if fragment
in_target_fragment = context.in_target_fragment
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
else
yield if block
return nil
end
end
end
if attributes.length > 0 # with attributes
if block # with content block
@@ -64,6 +83,9 @@ 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
nil
end
@@ -90,7 +112,21 @@ def register_void_element(method_name, tag: method_name.name.tr("_", "-"), depre
def #{method_name}(**attributes)
#{deprecation}
buffer = @_context.buffer
context = @_context
buffer = context.buffer
fragment = context.fragment
if fragment
in_target_fragment = context.in_target_fragment
if !in_target_fragment
if !context.found_target_fragment && attributes[:id] == fragment
context.found_target_fragment = true
else
return nil
end
end
end
if attributes.length > 0 # with attributes
buffer << "<#{tag}" << (Phlex::ATTRIBUTE_CACHE[respond_to?(:process_attributes) ? (attributes.hash + self.class.hash) : attributes.hash] || __attributes__(**attributes)) << ">"
5 changes: 4 additions & 1 deletion lib/phlex/html.rb
Original file line number Diff line number Diff line change
@@ -29,7 +29,10 @@ def __unbuffered_class__

# Output an HTML doctype.
def doctype
@_context.buffer << "<!DOCTYPE html>"
context = @_context
return if context.fragment && !context.in_target_fragment

context.buffer << "<!DOCTYPE html>"
nil
end

25 changes: 19 additions & 6 deletions lib/phlex/sgml.rb
Original file line number Diff line number Diff line change
@@ -95,18 +95,19 @@ def await(task)
end

# Renders the view and returns the buffer. The default buffer is a mutable String.
def call(buffer = +"", context: Phlex::Context.new, view_context: nil, parent: nil, &block)
__final_call__(buffer, context: context, view_context: view_context, parent: parent, &block).tap do
def call(buffer = +"", context: Phlex::Context.new, view_context: nil, parent: nil, fragment: nil, &block)
__final_call__(buffer, context: context, view_context: view_context, parent: parent, fragment: fragment, &block).tap do
self.class.rendered_at_least_once!
end
end

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

block ||= @_content_block

@@ -139,6 +140,9 @@ def __final_call__(buffer = +"", context: Phlex::Context.new, view_context: nil,
# @return [nil]
# @see #format_object
def plain(content)
context = @_context
return if context.fragment && !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"
end
@@ -150,7 +154,10 @@ def plain(content)
# @return [nil]
# @yield If a block is given, it yields the block with no arguments.
def whitespace(&block)
buffer = @_context.buffer
context = @_context
return if context.fragment && !context.in_target_fragment

buffer = context.buffer

buffer << " "

@@ -165,7 +172,10 @@ def whitespace(&block)
# Output an HTML comment.
# @return [nil]
def comment(&block)
buffer = @_context.buffer
context = @_context
return if context.fragment && !context.in_target_fragment

buffer = context.buffer

buffer << "<!-- "
yield_content(&block)
@@ -180,7 +190,10 @@ def comment(&block)
def unsafe_raw(content = nil)
return nil unless content

@_context.buffer << content
context = @_context
return if context.fragment && !context.in_target_fragment

context.buffer << content
nil
end

55 changes: 55 additions & 0 deletions test/phlex/selective_rendering.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

class StandardElementExample < Phlex::HTML
def view_template
doctype
div {
comment { h1(id: "target") }
h1 { "Before" }
img(src: "before.jpg")
whitespace
comment { "This is a comment" }
h1(id: "target") {
plain "Hello"
strong { "World" }
img(src: "image.jpg")
}
img(src: "after.jpg")
h1(id: "target") { "After" }
}
end
end

class VoidElementExample < Phlex::HTML
def view_template
doctype
div {
comment { h1(id: "target") }
h1 { "Before" }
img(src: "before.jpg")
whitespace
comment { "This is a comment" }
h1 {
plain "Hello"
strong { "World" }
img(id: "target", src: "image.jpg")
}
img(src: "after.jpg")
h1(id: "target") { "After" }
}
end
end

describe Phlex::HTML do
it "renders the just the target fragment" do
expect(
StandardElementExample.new.call(fragment: "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")
).to be == %(<img id="target" src="image.jpg">)
end
end

0 comments on commit 841748e

Please sign in to comment.