Skip to content

Commit

Permalink
Add output_preamble to match postamble (#1960)
Browse files Browse the repository at this point in the history
  • Loading branch information
CrookedGrin authored Jan 8, 2024
1 parent 5a55ad5 commit cc7c313
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 5 deletions.
Binary file added .DS_Store
Binary file not shown.
7 changes: 6 additions & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ nav_order: 5

## main

* Add `output_preamble` to match `output_postamble`, using the same safety checks.

*Kali Donovan*
*Michael Daross*

* Exclude html escaping of I18n reserved keys with `I18n::RESERVED_KEYS` rather than `I18n.reserved_keys_pattern`.

*Nick Coyne*
Expand All @@ -30,7 +35,7 @@ nav_order: 5

* Add support for Ruby 3.3.

*Reegan Viljoen*
*Reegan Viljoen*

* Allow translations to be inherited and overridden in subclasses.

Expand Down
4 changes: 4 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ that inhibits encapsulation & reuse, often making testing difficult.
A proxy through which to access helpers. Use sparingly as doing so introduces
coupling that inhibits encapsulation & reuse, often making testing difficult.

### `#output_preamble`[String]

Optional content to be returned before the rendered template.

### `#output_postamble`[String]

Optional content to be returned after the rendered template.
Expand Down
2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ ViewComponent is built by over a hundred members of the community, including:
<img src="https://avatars.githubusercontent.com/cesariouy?s=64" alt="cesariouy" width="32" />
<img src="https://avatars.githubusercontent.com/cover?s=64" alt="cover" width="32" />
<img src="https://avatars.githubusercontent.com/cpjmcquillan?s=64" alt="cpjmcquillan" width="32" />
<img src="https://avatars.githubusercontent.com/crookedgrin?s=64" alt="crookedgrin" width="32" />
<img src="https://avatars.githubusercontent.com/czj?s=64" alt="czj" width="32" />
<img src="https://avatars.githubusercontent.com/dani-sc?s=64" alt="dani-sc" width="32" />
<img src="https://avatars.githubusercontent.com/danieldiekmeier?s=64" alt="danieldiekmeier" width="32" />
Expand Down Expand Up @@ -158,6 +159,7 @@ ViewComponent is built by over a hundred members of the community, including:
<img src="https://avatars.githubusercontent.com/jwshuff?s=64" alt="jwshuff" width="32" />
<img src="https://avatars.githubusercontent.com/kaspermeyer?s=64" alt="kaspermeyer" width="32" />
<img src="https://avatars.githubusercontent.com/kylefox?s=64" alt="kylefox" width="32" />
<img src="https://avatars.githubusercontent.com/kdonovan?s=64" alt="kdonovan" width="32" />
<img src="https://avatars.githubusercontent.com/leighhalliday?s=64" alt="leighhalliday" width="32" />
<img src="https://avatars.githubusercontent.com/llenk?s=64" alt="llenk" width="32" />
<img src="https://avatars.githubusercontent.com/manuelpuyol?s=64" alt="manuelpuyol" width="32" />
Expand Down
23 changes: 19 additions & 4 deletions lib/view_component/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,13 @@ def render_in(view_context, &block)
before_render

if render?
# Avoid allocating new string when output_postamble is blank
if output_postamble.blank?
safe_render_template_for(@__vc_variant).to_s
# Avoid allocating new string when output_preamble and output_postamble are blank
rendered_template = safe_render_template_for(@__vc_variant).to_s

if output_preamble.blank? && output_postamble.blank?
rendered_template
else
safe_render_template_for(@__vc_variant).to_s + safe_output_postamble
safe_output_preamble + rendered_template + safe_output_postamble
end
else
""
Expand Down Expand Up @@ -156,6 +158,13 @@ def render_parent_to_string
end
end

# Optional content to be returned before the rendered template.
#
# @return [String]
def output_preamble
@@default_output_preamble ||= "".html_safe
end

# Optional content to be returned after the rendered template.
#
# @return [String]
Expand Down Expand Up @@ -329,6 +338,12 @@ def safe_render_template_for(variant)
end
end

def safe_output_preamble
maybe_escape_html(output_preamble) do
Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe preamble. The preamble will be automatically escaped, but you may want to investigate.")
end
end

def safe_output_postamble
maybe_escape_html(output_postamble) do
Kernel.warn("WARNING: The #{self.class} component was provided an HTML-unsafe postamble. The postamble will be automatically escaped, but you may want to investigate.")
Expand Down
15 changes: 15 additions & 0 deletions test/sandbox/app/components/before_and_after_render_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class BeforeAndAfterRenderComponent < ViewComponent::Base
def call
"Hello, ".html_safe
end

def output_preamble
"Well, ".html_safe
end

def output_postamble
"World!".html_safe
end
end
11 changes: 11 additions & 0 deletions test/sandbox/app/components/before_render_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class BeforeRenderComponent < ViewComponent::Base
def call
"Hello!".html_safe
end

def output_preamble
"Well, ".html_safe
end
end
11 changes: 11 additions & 0 deletions test/sandbox/app/components/unsafe_preamble_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class UnsafePreambleComponent < ViewComponent::Base
def call
"<div>some content</div>".html_safe
end

def output_preamble
"<script>alert('hello!')</script>"
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ def unsafe_component
render(UnsafeComponent.new)
end

def unsafe_preamble_component
render(UnsafePreambleComponent.new)
end

def unsafe_postamble_component
render(UnsafePostambleComponent.new)
end
Expand Down
1 change: 1 addition & 0 deletions test/sandbox/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
get :inherited_sidecar, to: "integration_examples#inherited_sidecar"
get :inherited_from_uncompilable_component, to: "integration_examples#inherited_from_uncompilable_component"
get :unsafe_component, to: "integration_examples#unsafe_component"
get :unsafe_preamble_component, to: "integration_examples#unsafe_preamble_component"
get :unsafe_postamble_component, to: "integration_examples#unsafe_postamble_component"
post :create, to: "integration_examples#create"

Expand Down
9 changes: 9 additions & 0 deletions test/sandbox/test/integration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,15 @@ def test_unsafe_component
)
end

def test_unsafe_preamble_component
warnings = capture_warnings { get "/unsafe_preamble_component" }
assert_select("script", false)
assert(
warnings.any? { |warning| warning.include?("component was provided an HTML-unsafe preamble") },
"Rendering UnsafePreambleComponent did not emit an HTML safety warning"
)
end

def test_unsafe_postamble_component
warnings = capture_warnings { get "/unsafe_postamble_component" }
assert_select("script", false)
Expand Down
12 changes: 12 additions & 0 deletions test/sandbox/test/rendering_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -889,12 +889,24 @@ def test_components_share_helpers_state
assert_equal 1, PartialHelper::State.calls
end

def test_output_preamble
render_inline(BeforeRenderComponent.new)

assert_text("Well, Hello!")
end

def test_output_postamble
render_inline(AfterRenderComponent.new)

assert_text("Hello, World!")
end

def test_output_preamble_and_postamble
render_inline(BeforeAndAfterRenderComponent.new)

assert_text("Well, Hello, World!")
end

def test_compilation_in_development_mode
with_compiler_mode(ViewComponent::Compiler::DEVELOPMENT_MODE) do
with_new_cache do
Expand Down

0 comments on commit cc7c313

Please sign in to comment.