Class: HtmlGen::Element

Inherits:
Object
  • Object
show all
Defined in:
lib/html_gen/element.rb

Overview

This class can be used to generate HTML.

Examples

ele = HtmlGen::Element.new(:a) #=> #<HtmlGen::Element:0x00000000e5f650 @attr={}, @name=:a, @classes=[], @str_html="" ...>
ele.classes << "custom_link"
ele.css["font-weight"] = "bold"
ele.attr[:href] = "http://www.youtube.com"

b = ele.add_ele(:b)
b.str = "Title of link"

ele.html #=> "<a href=\"http://www.youtube.com\" style=\"font-weight: bold;\" class=\"custom_link\">\n\t<b>\n\t\tTitle of link\n\t</b>\n</a>\n"

Constant Summary collapse

FORBIDDEN_SHORT =
%w(div i script span).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, args = {}) ⇒ Element

You can give various arguments as shortcuts to calling the methods. You can also decide what should be used for newline and indentation.

HtmlGen::Element.new(:b, {
  css: {"font-weight" => "bold"},
  attr: {"href" => "http://www.youtube.com"},
  classes: ["class1", "class2"],
  str: "A title",
  str_html: "Some custom URL as title",
  nl: "\n",
  inden: "\t",
  eles: [HtmlGen::Element.new("i", str: "Hello world!")
})


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/html_gen/element.rb', line 65

def initialize(name, args = {})
  raise "'name' should be a string or a symbol but was a '#{name.class.name}'." if !name.is_a?(String) && !name.is_a?(Symbol)
  @name = name

  {attr: {}, data: {}, classes: [], str_html: "", str: "", css: {}, eles: [], nl: "\n", inden: "  "}.each do |arg, default_val|
    if args[arg]
      instance_variable_set("@#{arg}", args[arg])
    else
      instance_variable_set("@#{arg}", default_val)
    end

    args.delete(arg)
  end

  raise "Unknown arguments: '#{args.keys.join(",")}'." unless args.empty?
end

Instance Attribute Details

#attrObject (readonly)

Attributes hash which will be used to generate attributes-elements.

Example

element.attr[:href] = "http://www.youtube.com"


18
19
20
# File 'lib/html_gen/element.rb', line 18

def attr
  @attr
end

#classesObject (readonly)

Classes-array which will be used to generate the ‘class’-attribute.

Example

element.classes += ["class1", "class2"]
element.html #=> ... class="class1 class2"...


32
33
34
# File 'lib/html_gen/element.rb', line 32

def classes
  @classes
end

#cssObject (readonly)

CSS-hash which will be used to generate the ‘style’-attribute.

Example

element.css["font-weight"] = "bold"


23
24
25
# File 'lib/html_gen/element.rb', line 23

def css
  @css
end

#dataObject (readonly)

Data hash which will nest keys.



26
27
28
# File 'lib/html_gen/element.rb', line 26

def data
  @data
end

#elesObject

An array holding all the sub-elements of this element.



49
50
51
# File 'lib/html_gen/element.rb', line 49

def eles
  @eles
end

#nameObject

The name of the element. “a” for <a> and such.



52
53
54
# File 'lib/html_gen/element.rb', line 52

def name
  @name
end

#strObject

This string is used to generate the value of an element. It will be HTML-escaped.

Example

element = HtmlGen::Element.new("b")
element.str = "Te<i>s</i>t"
element.html(pretty: false) #=> "<b>Te&lt;i&gt;s&lt;/i&gt;t</b>"


39
40
41
# File 'lib/html_gen/element.rb', line 39

def str
  @str
end

#str_htmlObject

This string is used to generate the value of an element. It will not be HTML-escaped.

Example

element = HtmlGen::Element.new("b")
element.str_html = "Te<i>s</i>t"
element.html #=> "<b>Te<i>s</i>t</b>"


46
47
48
# File 'lib/html_gen/element.rb', line 46

def str_html
  @str_html
end

Instance Method Details

#add_ele(name, args = {}) ⇒ Object Also known as: add

Adds a sub-element to the element.

Examples

element = HtmlGen::Element.new("a")
another_ele = element.add_ele("b")
another_ele.str = "Hello world!"
element.html #=> "<a>\n\t<b>\n\t\tHello world!\n\t</b>\n</a>\n"


88
89
90
91
92
# File 'lib/html_gen/element.rb', line 88

def add_ele(name, args = {})
  ele = HtmlGen::Element.new(name, args.merge(nl: @nl, inden: @inden))
  @eles << ele
  ele
end

#add_html(html) ⇒ Object

Add a text-element to the element.



104
105
106
107
108
# File 'lib/html_gen/element.rb', line 104

def add_html(html)
  ele = HtmlGen::TextEle.new(html: html, inden: @inden, nl: @nl)
  @eles << ele
  ele
end

#add_html_if_safe(html) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/html_gen/element.rb', line 110

def add_html_if_safe(html)
  if html.respond_to?(:html_safe?) && html.html_safe?
    add_html(html)
  else
    add_str(html)
  end
end

#add_str(str) ⇒ Object

Add a text-element to the element.



97
98
99
100
101
# File 'lib/html_gen/element.rb', line 97

def add_str(str)
  ele = HtmlGen::TextEle.new(str: str, inden: @inden, nl: @nl)
  @eles << ele
  ele
end

#convert_data_attributes_to_dataObject



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/html_gen/element.rb', line 267

def convert_data_attributes_to_data
  @attr.delete_if do |key, value|
    match = key.to_s.match(/\Adata-(.+)\Z/)

    if match
      data_keys = match[1].split("-")
      last_key = data_keys.pop

      current_data_element = @data
      data_keys.each do |key_part|
        current_data_element = current_data_element[key_part] ||= {}
      end

      current_data_element[last_key] = value

      true
    else
      false
    end
  end
end

#convert_style_to_cssObject

Converts the content of the ‘style’-attribute to css-hash-content.



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/html_gen/element.rb', line 243

def convert_style_to_css
  if !@attr[:style].to_s.strip.empty?
    style = @attr[:style]
  elsif !@attr["style"].to_s.strip.empty?
    style = @attr["style"]
  else
    raise "No style set in element."
  end

  loop do
    if (match = style.match(/\A\s*(\S+?):\s*(.+?)\s*(;|\Z)/))
      style.gsub!(match[0], "")
      key = match[1]
      val = match[2]
      raise "Such a key already exists in CSS-hash: '#{key}'." if @css.key?(key)
      @css[key] = val
    elsif (match = style.slice!(/\A\s*\Z/))
      break
    else
      raise "Dont know what to do with style-variable: '#{style}'."
    end
  end
end

#eles_namesObject

Returns the names of all sub-elements in an array.



233
234
235
236
237
238
239
240
# File 'lib/html_gen/element.rb', line 233

def eles_names
  names = []
  @eles.each do |ele|
    names << ele.name
  end

  names
end

#html(args = {}) ⇒ Object

Returns the HTML for the element. To avoid indentation and newlines you can use the ‘pretty’-argument:

element.html(pretty: false)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/html_gen/element.rb', line 121

def html(args = {})
  if args[:level]
    level = args[:level]
  else
    level = 0
  end

  if args.key?(:pretty)
    pretty = args[:pretty]
  else
    pretty = true
  end

  # Used for keeping 'pretty'-value and correct indentation according to parent elements.
  pass_args = {level: (level + 1), pretty: pretty, inden: @inden}

  # Clone the attributes-hash since we are going to add stuff to it, and it shouldnt be reflected
  # (if 'html' is called multiple times, it will bug unless we clone).
  attr = @attr.clone

  # Start generating the string with HTML (possible go give a custom 'str'-variable where the content should be pushed to).
  if args[:str]
    str = args[:str]
  else
    str = ""
  end

  str << @inden * level if pretty && level > 0
  str << "<#{@name}"

  # Add content from the 'css'-hash to the 'style'-attribute in the right format.
  unless @css.empty?
    style = ""
    @css.each do |key, val|
      style << "; " unless style.empty?
      style << "#{key}: #{val};"
    end

    if attr[:style] && !attr[:style].empty?
      attr[:style] << "; #{style}"
    else
      attr[:style] = style
    end
  end

  # Add content from the 'classes'-array to the 'class'-attribute in the right format.
  unless @classes.empty?
    class_str = @classes.join(" ")

    if @attr[:class] && !@attr[:class].empty?
      attr[:class] << " #{class_str}"
    else
      attr[:class] = class_str
    end
  end

  # Write out the attributes to the string.
  attr.each do |key, val|
    str << " #{key}=\"#{HtmlGen.escape_html(val)}\""
  end

  str << " #{data_attributes(@data, "data")}" if @data.any?

  forbidden_short = FORBIDDEN_SHORT.include?(@name.to_s)
  skip_pretty = false

  if @eles.empty? && @str.empty? && @str_html.empty? && !forbidden_short
    # If no sub-string, sub-HTML or sub-elements are given, we should end the HTML with " />".
    str << " />"
    str << @nl if pretty
  else
    # Write end-of-element and then all sub-elements.
    str << ">"

    if @eles.empty? && @str.empty? && @str_html.empty? && forbidden_short
      skip_pretty = true
    end

    str << @nl if pretty && !skip_pretty

    unless @str.empty?
      str << @inden * (level + 1) if pretty

      if @str.respond_to?(:html_safe?) && @str.html_safe?
        str << @str
      else
        str << HtmlGen.escape_html(@str)
      end

      str << @nl if pretty
    end

    unless @str_html.empty?
      str << @inden * (level + 1) if pretty
      str << @str_html
      str << @nl if pretty
    end

    @eles.each do |subele|
      str << subele.html(pass_args)
    end

    str << @inden * level if pretty && level > 0 && !skip_pretty
    str << "</#{@name}>"
    str << @nl if pretty
  end

  str = str.html_safe if str.respond_to?(:html_safe)
  str
end