Class: ActionView::Helpers::TagHelper::TagBuilder

Inherits:
Object
  • Object
show all
Includes:
CaptureHelper, OutputSafetyHelper
Defined in:
lib/action_view/helpers/tag_helper.rb

Overview

:nodoc:

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OutputSafetyHelper

#raw, #safe_join, #to_sentence

Methods included from CaptureHelper

#capture, #content_for, #content_for?, #provide, #with_output_buffer

Constructor Details

#initialize(view_context) ⇒ TagBuilder

Returns a new instance of TagBuilder.



232
233
234
# File 'lib/action_view/helpers/tag_helper.rb', line 232

def initialize(view_context)
  @view_context = view_context
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(called, *args, escape: true, **options, &block) ⇒ Object (private)



340
341
342
343
344
345
346
# File 'lib/action_view/helpers/tag_helper.rb', line 340

def method_missing(called, *args, escape: true, **options, &block)
  name = called.name.dasherize

  TagHelper.ensure_valid_html5_tag_name(name)

  tag_string(name, *args, options, escape: escape, &block)
end

Class Method Details

.define_element(name, code_generator:, method_name: name) ⇒ Object



61
62
63
64
65
66
67
68
69
70
# File 'lib/action_view/helpers/tag_helper.rb', line 61

def self.define_element(name, code_generator:, method_name: name)
  return if method_defined?(name)

  code_generator.class_eval do |batch|
    batch << "\n" <<
      "def #{method_name}(content = nil, escape: true, **options, &block)" <<
      "  tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
      "end"
  end
end

.define_self_closing_element(name, code_generator:, method_name: name) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/action_view/helpers/tag_helper.rb', line 86

def self.define_self_closing_element(name, code_generator:, method_name: name)
  code_generator.class_eval do |batch|
    batch << "\n" <<
      "def #{method_name}(content = nil, escape: true, **options, &block)" <<
      "  if content || block" <<
      "    tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
      "  else" <<
      "   self_closing_tag_string(#{name.inspect}, options, escape)" <<
      "  end" <<
      "end"
  end
end

.define_void_element(name, code_generator:, method_name: name) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/action_view/helpers/tag_helper.rb', line 72

def self.define_void_element(name, code_generator:, method_name: name)
  code_generator.class_eval do |batch|
    batch << "\n" <<
      "def #{method_name}(content = nil, escape: true, **options, &block)" <<
      "  if content || block" <<
      "    deprecated_void_content(#{name.inspect})" <<
      "    tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
      "  else" <<
      "    self_closing_tag_string(#{name.inspect}, options, escape, '>')" <<
      "  end" <<
      "end"
  end
end

Instance Method Details

#attributes(attributes) ⇒ Object

Transforms a Hash into HTML Attributes, ready to be interpolated into ERB.

<input <%= tag.attributes(type: :text, aria: { label: "Search" }) %> >
# => <input type="text" aria-label="Search">


241
242
243
# File 'lib/action_view/helpers/tag_helper.rb', line 241

def attributes(attributes)
  tag_options(attributes.to_h).to_s.strip.html_safe
end

#boolean_tag_option(key) ⇒ Object



306
307
308
# File 'lib/action_view/helpers/tag_helper.rb', line 306

def boolean_tag_option(key)
  %(#{key}="#{key}")
end

#content_tag_string(name, content, options, escape = true) ⇒ Object



255
256
257
258
259
260
261
262
# File 'lib/action_view/helpers/tag_helper.rb', line 255

def (name, content, options, escape = true)
  tag_options = tag_options(options, escape) if options

  if escape && content.present?
    content = ERB::Util.unwrapped_html_escape(content)
  end
  "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
end

#deprecated_void_content(name) ⇒ Object



51
52
53
54
55
56
57
58
59
# File 'lib/action_view/helpers/tag_helper.rb', line 51

def deprecated_void_content(name)
  ActionView.deprecator.warn <<~TEXT
    Putting content inside a void element (#{name}) is invalid
    according to the HTML5 spec, and so it is being deprecated
    without replacement. In Rails 8.0, passing content as a
    positional argument will raise, and using a block will have
    no effect.
  TEXT
end

#self_closing_tag_string(name, options, escape = true, tag_suffix = " />") ⇒ Object



251
252
253
# File 'lib/action_view/helpers/tag_helper.rb', line 251

def self_closing_tag_string(name, options, escape = true, tag_suffix = " />")
  "<#{name}#{tag_options(options, escape)}#{tag_suffix}".html_safe
end

#tag_option(key, value, escape) ⇒ Object



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/action_view/helpers/tag_helper.rb', line 310

def tag_option(key, value, escape)
  key = ERB::Util.xml_name_escape(key) if escape

  case value
  when Array, Hash
    value = TagHelper.build_tag_values(value) if key.to_s == "class"
    value = escape ? safe_join(value, " ") : value.join(" ")
  when Regexp
    value = escape ? ERB::Util.unwrapped_html_escape(value.source) : value.source
  else
    value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
  end
  value = value.gsub('"', "&quot;") if value.include?('"')

  %(#{key}="#{value}")
end

#tag_options(options, escape = true) ⇒ Object



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/action_view/helpers/tag_helper.rb', line 264

def tag_options(options, escape = true)
  return if options.blank?
  output = +""
  sep    = " "
  options.each_pair do |key, value|
    type = TAG_TYPES[key]
    if type == :data && value.is_a?(Hash)
      value.each_pair do |k, v|
        next if v.nil?
        output << sep
        output << prefix_tag_option(key, k, v, escape)
      end
    elsif type == :aria && value.is_a?(Hash)
      value.each_pair do |k, v|
        next if v.nil?

        case v
        when Array, Hash
          tokens = TagHelper.build_tag_values(v)
          next if tokens.none?

          v = safe_join(tokens, " ")
        else
          v = v.to_s
        end

        output << sep
        output << prefix_tag_option(key, k, v, escape)
      end
    elsif type == :boolean
      if value
        output << sep
        output << boolean_tag_option(key)
      end
    elsif !value.nil?
      output << sep
      output << tag_option(key, value, escape)
    end
  end
  output unless output.empty?
end

#tag_string(name, content = nil, options, escape: true, &block) ⇒ Object



245
246
247
248
249
# File 'lib/action_view/helpers/tag_helper.rb', line 245

def tag_string(name, content = nil, options, escape: true, &block)
  content = @view_context.capture(self, &block) if block

  (name, content, options, escape)
end