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.



229
230
231
# File 'lib/action_view/helpers/tag_helper.rb', line 229

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)



337
338
339
340
341
342
343
# File 'lib/action_view/helpers/tag_helper.rb', line 337

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.to_s.underscore) ⇒ Object



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

def self.define_element(name, code_generator:, method_name: name.to_s.underscore)
  code_generator.define_cached_method(method_name, namespace: :tag_builder) do |batch|
    batch.push(<<~RUBY) unless instance_methods.include?(method_name.to_sym)
      def #{method_name}(content = nil, escape: true, **options, &block)
        tag_string("#{name}", content, options, escape: escape, &block)
      end
    RUBY
  end
end

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



82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/action_view/helpers/tag_helper.rb', line 82

def self.define_self_closing_element(name, code_generator:, method_name: name.to_s.underscore)
  code_generator.define_cached_method(method_name, namespace: :tag_builder) do |batch|
    batch.push(<<~RUBY)
      def #{method_name}(content = nil, escape: true, **options, &block)
        if content || block
          tag_string("#{name}", content, options, escape: escape, &block)
        else
          self_closing_tag_string("#{name}", options, escape)
        end
      end
    RUBY
  end
end

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



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/action_view/helpers/tag_helper.rb', line 61

def self.define_void_element(name, code_generator:, method_name: name.to_s.underscore)
  code_generator.define_cached_method(method_name, namespace: :tag_builder) do |batch|
    batch.push(<<~RUBY)
      def #{method_name}(content = nil, escape: true, **options, &block)
        if content || block
          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
          tag_string("#{name}", content, options, escape: escape, &block)
        else
          self_closing_tag_string("#{name}", options, escape, ">")
        end
      end
    RUBY
  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">


238
239
240
# File 'lib/action_view/helpers/tag_helper.rb', line 238

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

#boolean_tag_option(key) ⇒ Object



303
304
305
# File 'lib/action_view/helpers/tag_helper.rb', line 303

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

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



252
253
254
255
256
257
258
259
# File 'lib/action_view/helpers/tag_helper.rb', line 252

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

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



248
249
250
# File 'lib/action_view/helpers/tag_helper.rb', line 248

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



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

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



261
262
263
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
# File 'lib/action_view/helpers/tag_helper.rb', line 261

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



242
243
244
245
246
# File 'lib/action_view/helpers/tag_helper.rb', line 242

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

  (name, content, options, escape)
end