Method: ActionView::Helpers::TextHelper#highlight

Defined in:
actionview/lib/action_view/helpers/text_helper.rb

#highlight(text, phrases, options = {}, &block) ⇒ Object

Highlights occurrences of phrases in text by formatting them with a highlighter string. phrases can be one or more strings or regular expressions. The result will be marked HTML safe. By default, text is sanitized before highlighting to prevent possible XSS attacks.

If a block is specified, it will be used instead of the highlighter string. Each occurrence of a phrase will be passed to the block, and its return value will be inserted into the final result.

Options

:highlighter

The highlighter string. Uses \1 as the placeholder for a phrase, similar to String#sub. Defaults to "<mark>\1</mark>". This option is ignored if a block is specified.

:sanitize

Whether to sanitize text before highlighting. Defaults to true.

Examples

highlight('You searched for: rails', 'rails')
# => "You searched for: <mark>rails</mark>"

highlight('You searched for: rails', /for|rails/)
# => "You searched <mark>for</mark>: <mark>rails</mark>"

highlight('You searched for: ruby, rails, dhh', 'actionpack')
# => "You searched for: ruby, rails, dhh"

highlight('You searched for: rails', ['for', 'rails'], highlighter: '<em>\1</em>')
# => "You searched <em>for</em>: <em>rails</em>"

highlight('You searched for: rails', 'rails', highlighter: '<a href="search?q=\1">\1</a>')
# => "You searched for: <a href=\"search?q=rails\">rails</a>"

highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match)) }
# => "You searched for: <a href=\"search?q=rails\">rails</a>"

highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
# => "<a href=\"javascript:alert('no!')\">ruby</a> on <mark>rails</mark>"


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'actionview/lib/action_view/helpers/text_helper.rb', line 174

def highlight(text, phrases, options = {}, &block)
  text = sanitize(text) if options.fetch(:sanitize, true)

  if text.blank? || phrases.blank?
    text || ""
  else
    patterns = Array(phrases).map { |phrase| Regexp === phrase ? phrase : Regexp.escape(phrase) }
    pattern = /(#{patterns.join("|")})/i
    highlighter = options.fetch(:highlighter, '<mark>\1</mark>') unless block

    text.scan(/<[^>]*|[^<]+/).each do |segment|
      if !segment.start_with?("<")
        if block
          segment.gsub!(pattern, &block)
        else
          segment.gsub!(pattern, highlighter)
        end
      end
    end.join
  end.html_safe
end