Module: Hyraft::Compiler::HtmlPurifier

Included in:
HyraftRenderer
Defined in:
lib/hyraft/compiler/html_purifier.rb

Instance Method Summary collapse

Instance Method Details

#escape_html(unsafe) ⇒ Object

Alias for purify_html for different use cases



18
19
20
# File 'lib/hyraft/compiler/html_purifier.rb', line 18

def escape_html(unsafe)
  purify_html(unsafe)
end

#format_datetime(datetime, format: '%Y-%m-%d %H:%M', default: '') ⇒ String

Format datetime object

Parameters:

  • datetime (Time, DateTime, String)

    The datetime to format

  • format (String) (defaults to: '%Y-%m-%d %H:%M')

    strftime format string (default: ‘%Y-%m-%d %H:%M’)

  • default (String) (defaults to: '')

    Default value if datetime is nil (default: ”)

Returns:

  • (String)

    Formatted datetime



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/hyraft/compiler/html_purifier.rb', line 137

def format_datetime(datetime, format: '%Y-%m-%d %H:%M', default: '')
  return default unless datetime
  
  if datetime.is_a?(String)
    # Try to parse the string
    begin
      datetime = Time.parse(datetime)
    rescue
      return default
    end
  end
  
  if datetime.respond_to?(:strftime)
    datetime.strftime(format)
  else
    default
  end
end

#highlight_text(text, term, highlight_tag: 'mark', css_class: nil) ⇒ String

Highlight text with search term while maintaining HTML safety

Parameters:

  • text (String)

    The text to search within

  • term (String)

    The search term to highlight

  • highlight_tag (String) (defaults to: 'mark')

    HTML tag to use for highlighting (default: ‘mark’)

  • css_class (String) (defaults to: nil)

    CSS class to add to highlight tag (optional)

Returns:

  • (String)

    Text with highlighted terms



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/hyraft/compiler/html_purifier.rb', line 51

def highlight_text(text, term, highlight_tag: 'mark', css_class: nil)
  return text if term.empty? || text.empty?
  
  # First purify the text to make it safe
  safe_text = purify_html(text)
  safe_term = purify_html(term)
  
  # Escape the term for regex
  escaped_term = Regexp.escape(safe_term)
  
  # Build the opening tag with optional CSS class
  opening_tag = if css_class
    "<#{highlight_tag} class=\"#{purify_html_attribute(css_class)}\">"
  else
    "<#{highlight_tag}>"
  end
  
  closing_tag = "</#{highlight_tag}>"
  
  # Highlight the term
  safe_text.gsub(/(#{escaped_term})/i) do |match|
    "#{opening_tag}#{match}#{closing_tag}"
  end
end

#highlight_with_class(text, term, highlight_class: 'bg-warning text-dark px-1 rounded') ⇒ String

Alternative highlighting with span and default Bootstrap classes

Parameters:

  • text (String)

    The text to search within

  • term (String)

    The search term to highlight

  • highlight_class (String) (defaults to: 'bg-warning text-dark px-1 rounded')

    CSS class for highlighting (default: ‘bg-warning text-dark px-1 rounded’)

Returns:

  • (String)

    Text with highlighted terms



81
82
83
# File 'lib/hyraft/compiler/html_purifier.rb', line 81

def highlight_with_class(text, term, highlight_class: 'bg-warning text-dark px-1 rounded')
  highlight_text(text, term, highlight_tag: 'span', css_class: highlight_class)
end

Create a safe HTML link

Parameters:

  • text (String)

    The link text

  • url (String)

    The link URL

  • attrs (Hash)

    Additional HTML attributes (e.g., ‘btn’, target: ‘_blank’)

Returns:

  • (String)

    Safe HTML <a> tag



121
122
123
124
125
126
127
128
129
130
# File 'lib/hyraft/compiler/html_purifier.rb', line 121

def link_to(text, url, **attrs)
  # Build attributes string
  attr_string = attrs.map do |key, value|
    "#{key}=\"#{purify_html_attribute(value)}\""
  end.join(' ')
  
  attr_string = " #{attr_string}" unless attr_string.empty?
  
  "<a href=\"#{purify_html_attribute(url)}\"#{attr_string}>#{purify_html(text)}</a>"
end

#number_with_delimiter(number, delimiter: ',', separator: '.') ⇒ String

Format a number with commas (e.g., 1000 -> “1,000”)

Parameters:

  • number (Numeric, String)

    The number to format

  • delimiter (String) (defaults to: ',')

    Thousands delimiter (default: ‘,’)

  • separator (String) (defaults to: '.')

    Decimal separator (default: ‘.’)

Returns:

  • (String)

    Formatted number



161
162
163
164
165
166
167
168
# File 'lib/hyraft/compiler/html_purifier.rb', line 161

def number_with_delimiter(number, delimiter: ',', separator: '.')
  return '' unless number
  
  parts = number.to_s.split('.')
  parts[0] = parts[0].reverse.scan(/\d{1,3}/).join(delimiter).reverse
  
  parts.join(separator)
end

#pluralize(count, singular, plural = nil) ⇒ String

Pluralize a word based on count

Parameters:

  • count (Integer)

    The count

  • singular (String)

    Singular form of the word

  • plural (String) (defaults to: nil)

    Plural form of the word (optional, will add ‘s’ by default)

Returns:

  • (String)

    Pluralized phrase



175
176
177
178
# File 'lib/hyraft/compiler/html_purifier.rb', line 175

def pluralize(count, singular, plural = nil)
  plural ||= singular + 's'
  count == 1 ? "1 #{singular}" : "#{count} #{plural}"
end

#purify_html(unsafe) ⇒ Object

Purifies HTML content by escaping dangerous characters to prevent XSS attacks Usage: purify_html(user_input) - makes any string safe for HTML output



7
8
9
10
11
12
13
14
15
# File 'lib/hyraft/compiler/html_purifier.rb', line 7

def purify_html(unsafe)
  return '' unless unsafe
  unsafe.to_s
    .gsub(/&/, "&amp;")
    .gsub(/</, "&lt;")
    .gsub(/>/, "&gt;")
    .gsub(/"/, "&quot;")
    .gsub(/'/, "&#039;")
end

#purify_html_attribute(unsafe) ⇒ Object

Additional HTML safety methods



23
24
25
26
27
28
29
30
31
32
# File 'lib/hyraft/compiler/html_purifier.rb', line 23

def purify_html_attribute(unsafe)
  return '' unless unsafe
  unsafe.to_s
    .gsub(/&/, "&amp;")
    .gsub(/</, "&lt;")
    .gsub(/>/, "&gt;")
    .gsub(/"/, "&quot;")
    .gsub(/'/, "&#x27;")
    .gsub(/\//, "&#x2F;")
end

#purify_javascript(unsafe) ⇒ Object



34
35
36
37
38
39
40
41
42
43
# File 'lib/hyraft/compiler/html_purifier.rb', line 34

def purify_javascript(unsafe)
  return '' unless unsafe
  unsafe.to_s
    .gsub(/\\/, "\\\\")
    .gsub(/'/, "\\'")
    .gsub(/"/, "\\\"")
    .gsub(/\n/, "\\n")
    .gsub(/\r/, "\\r")
    .gsub(/</, "\\u003C")
end

#truncate_text(text, length: 100, suffix: '...', preserve_words: false) ⇒ String

Truncate text to specified length

Parameters:

  • text (String)

    The text to truncate

  • length (Integer) (defaults to: 100)

    Maximum length before truncation (default: 100)

  • suffix (String) (defaults to: '...')

    Suffix to add when truncated (default: ‘…’)

  • preserve_words (Boolean) (defaults to: false)

    Whether to preserve whole words (default: false)

Returns:

  • (String)

    Truncated text



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/hyraft/compiler/html_purifier.rb', line 93

def truncate_text(text, length: 100, suffix: '...', preserve_words: false)
  return '' unless text
  text = text.to_s
  
  if text.length <= length
    return text
  end
  
  if preserve_words
    # Try to break at a word boundary
    truncated = text[0, length]
    last_space = truncated.rindex(/\s/)
    
    if last_space && last_space > length * 0.8  # Only break if we have a reasonable word boundary
      truncated = text[0, last_space]
    end
    
    truncated + suffix
  else
    text[0, length] + suffix
  end
end