xhtml_report_generator 3.1.1 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
metadata CHANGED
@@ -1,21 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xhtml_report_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manuel Widmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-11 00:00:00.000000000 Z
11
+ date: 2020-07-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: "The generator can be used to create html or xhtml files. It comes with
14
- many utility functions.\n \nThe javascript to render the table of contents, the
15
- custom generator functions and style sheet all can be\nsupplied by your own, if
16
- necessary. By default there are methods to insert tables, links, paragraphs, preformatted
17
- text\nand arbitrary xhtml code. Due to the xml nature it is also easy to insert
18
- SVG graphs / pictures.\n\nCheckout the github project to see some examples.\n"
13
+ description: |
14
+ The generator can be used to create html or xhtml files. It comes with many utility functions.
15
+
16
+ The javascript to render the table of contents, the custom generator functions and style sheet all can be
17
+ supplied by your own, if necessary. By default there are methods to insert tables, links, paragraphs, preformatted text
18
+ and arbitrary xhtml code. Due to the xml nature it is also easy to insert SVG graphs / pictures.
19
+
20
+ Checkout the github project to see some examples.
19
21
  email: m-widmer@gmx.ch
20
22
  executables: []
21
23
  extensions: []
@@ -24,13 +26,21 @@ files:
24
26
  - LICENSE
25
27
  - README.md
26
28
  - lib/xhtml_report_generator.rb
27
- - lib/xhtml_report_generator/custom.rb
28
- - lib/xhtml_report_generator/jquery.min.js
29
- - lib/xhtml_report_generator/print_template.css
30
- - lib/xhtml_report_generator/split.min.js
31
- - lib/xhtml_report_generator/style_template.css
32
- - lib/xhtml_report_generator/toc.min.js
33
- - lib/xhtml_report_generator/version.rb
29
+ - resource/c3v0.7.18/c3.min.css
30
+ - resource/c3v0.7.18/c3.min.js
31
+ - resource/css/horizontal.png
32
+ - resource/css/print.css
33
+ - resource/css/style.css
34
+ - resource/css/vertical.png
35
+ - resource/d3v5.16.0/d3.min.js
36
+ - resource/js/jquery-3.5.1.min.js
37
+ - resource/js/layout_split.js
38
+ - resource/js/split.min.js
39
+ - resource/js/table_of_contents.js
40
+ - resource/js/toggle_linewrap.js
41
+ - resource/passfail_bgcolor.js
42
+ - resource/toc.min.js
43
+ - resource/toc_full.js
34
44
  homepage: https://rubygems.org/gems/xhtml_report_generator
35
45
  licenses:
36
46
  - MIT
@@ -50,8 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
60
  - !ruby/object:Gem::Version
51
61
  version: '0'
52
62
  requirements: []
53
- rubyforge_project:
54
- rubygems_version: 2.4.5.1
63
+ rubygems_version: 3.1.2
55
64
  signing_key:
56
65
  specification_version: 4
57
66
  summary: A simple html or xhtml generator or logger to create human readable reports
@@ -1,597 +0,0 @@
1
- # encoding: utf-8
2
- require 'base64'
3
- # The module name doesn't matter, just make sure at the end to 'extend' it
4
- # because it will be 'eval'ed by the initialize method of the XhtmlReportGenerator::Generator class.
5
- module Custom
6
-
7
- # creates the basic page layout and sets the current Element to the main content area (middle div)
8
- # @example The middle div is matched by the following xPath
9
- # //body/div[@id='middle']
10
- # @param title [String] the title of the document
11
- # @param layout [Fixnum] one of 0,1,2,3 where 0 means minimal layout without left and right table of contents,
12
- # 1 means only left toc, 2 means only right toc, and 3 means full layout with left and right toc.
13
- def create_layout(title, layout=3)
14
- raise "invalid layout selector, choose from 0..3" if (layout < 0) || (layout > 3)
15
-
16
- @body = @document.elements["//body"]
17
- # only add the layout if it is not already there
18
- if !@layout
19
- head = @body.add_element("div", {"class" => "head", "id" => "head"})
20
- head.add_element("button", {"id" => "pre_toggle_linewrap"}).add_text("Toggle Linewrap")
21
-
22
- if (layout & 0x1) != 0
23
- div = @body.add_element("div", {"class" => "lefttoc split split-horizontal", "id" => "ltoc"})
24
- div.add_text("Table of Contents")
25
- div.add_element("br")
26
- end
27
-
28
- @div_middle = @body.add_element("div", {"class" => "middle split split-horizontal", "id" => "middle"})
29
-
30
- if (layout & 0x2) != 0
31
- div = @body.add_element("div", {"class" => "righttoc split split-horizontal", "id" => "rtoc"})
32
- div.add_text("Quick Links")
33
- div.add_element("br");div.add_element("br")
34
- end
35
-
36
- @body.add_element("p", {"class" => "#{layout}", "id" => "layout"}).add_text("this text should be hidden")
37
-
38
- @layout = true
39
- end
40
- @current = @document.elements["//body/div[@id='middle']"]
41
- set_title(title)
42
- end
43
-
44
- # sets the title of the document in the <head> section as well as in the layout header div
45
- # create_layout must be called before!
46
- # @param title [String] the text which will be insertead
47
- def set_title(title)
48
- if !@layout
49
- raise "call create_layout first"
50
- end
51
- pagetitle = @document.elements["//head/title"]
52
- pagetitle.text = title
53
- div = @document.elements["//body/div[@id='head']"]
54
- div.text = title
55
- end
56
-
57
- # returns the title text of the report
58
- # @return [String] The title of the report
59
- def get_title()
60
- pagetitle = @document.elements["//head/title"]
61
- return pagetitle.text
62
- end
63
-
64
- # set the current element to the element or first element matched by the xpath expression.
65
- # The current element is the one which can be modified through highlighting.
66
- # @param xpath [REXML::Element|String] the element or an xpath string
67
- def set_current!(xpath)
68
- if xpath.is_a?(REXML::Element)
69
- @current = xpath
70
- elsif xpath.is_a?(String)
71
- @current = @document.elements[xpath]
72
- else
73
- raise "xpath is neither a String nor a REXML::Element"
74
- end
75
- end
76
-
77
- # returns the current xml element
78
- # @return [REXML::Element] the xml element after which the following elements will be added
79
- def get_current()
80
- return @current
81
- end
82
-
83
- # returns the plain text without any xml tags of the specified element and all its children
84
- # @param el [REXML::Element] The element from which to fetch the text children. Defaults to @current
85
- # @param recursive [Boolean] whether or not to recurse into the children of the given "el"
86
- # @return [String] text contents of xml node
87
- def get_element_text(el = @current, recursive = true)
88
- out = ""
89
- el.to_a.each { |child|
90
- if child.is_a?(REXML::Text)
91
- out << child.value()
92
- else
93
- if recursive
94
- out << get_element_text(child, true)
95
- end
96
- end
97
- }
98
- return out
99
- end
100
-
101
- # @param elem [REXML::Element]
102
- # @return [String]
103
- def element_to_string(elem)
104
- f = REXML::Formatters::Transitive.new(0) # use Transitive to preserve source formatting (e.g. <pre> tags)
105
- out = ""
106
- f.write(elem, out)
107
- return out
108
- end
109
-
110
- # @see #code
111
- # Instead of adding content to the report, this method returns the produced html code as a string.
112
- # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
113
- # @return [String] the code including <pre> tags as a string
114
- def get_code_html(attrs={}, &block)
115
- temp = REXML::Element.new("pre")
116
- temp.add_attributes(attrs)
117
- raise "Block argument is mandatory" unless block_given?
118
- text = encoding_fixer(block.call())
119
- temp.add_text(text)
120
- element_to_string(temp)
121
- end
122
-
123
- # Appends a <pre> node after the @current node
124
- # @param attrs [Hash] attributes for the <pre> element. The following classes can be passed as attributes and are predefined with a different
125
- # background for your convenience !{"class" => "code0"} (light-blue), !{"class" => "code1"} (red-brown),
126
- # !{"class" => "code2"} (light-green), !{"class" => "code3"} (light-yellow). You may also specify your own background
127
- # as follows: !{"style" => "background: #FF00FF;"}.
128
- # @yieldreturn [String] the text to be added to the <pre> element
129
- # @return [REXML::Element] the Element which was just added
130
- def code(attrs={}, &block)
131
- temp = REXML::Element.new("pre")
132
- temp.add_attributes(attrs)
133
- @div_middle.insert_after(@current, temp)
134
- @current = temp
135
- raise "Block argument is mandatory" unless block_given?
136
- text = encoding_fixer(block.call())
137
- @current.add_text(text)
138
- return @current
139
- end
140
-
141
- # @see #content
142
- # Instead of adding content to the report, this method returns the produced html code as a string.
143
- # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
144
- # @return [String] the code including <pre> tags as a string
145
- def get_content_html(attrs={}, &block)
146
- temp = REXML::Element.new("p")
147
- temp.add_attributes(attrs)
148
- raise "Block argument is mandatory" unless block_given?
149
- text = encoding_fixer(block.call())
150
- temp.add_text(text)
151
- element_to_string(temp)
152
- end
153
-
154
- # Appends a <p> node after the @current node
155
- # @param attrs [Hash] attributes for the <p> element
156
- # @yieldreturn [String] the text to be added to the <p> element
157
- # @return [REXML::Element] the Element which was just added
158
- def content(attrs={}, &block)
159
- temp = REXML::Element.new("p")
160
- temp.add_attributes(attrs)
161
- @div_middle.insert_after(@current, temp)
162
- @current = temp
163
- raise "Block argument is mandatory" unless block_given?
164
- text = encoding_fixer(block.call())
165
- @current.add_text(text)
166
- return @current
167
- end
168
-
169
- # insert arbitrary xml code after the @current element in the content pane (div middle)
170
- # @param text [String] valid xhtml code which is included into the document
171
- # @return [REXML::Element] the Element which was just added
172
- def html(text)
173
- # we need to create a new document with a pseudo root becaus having multiple nodes at top
174
- # level is not valid xml
175
- doc = REXML::Document.new("<root>"+text+"</root>")
176
- # then we move all children of root to the actual div middle element and insert after current
177
- for i in doc.root.to_a do
178
- @div_middle.insert_after(@current, i)
179
- @current = i
180
- end
181
- return @current
182
- end
183
-
184
- # @see #link
185
- # Instead of adding content to the report, this method returns the produced html code as a string.
186
- # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
187
- # @return [String] the code including <pre> tags as a string
188
- def get_link_html(href, attrs={}, &block)
189
- temp = REXML::Element.new("a")
190
- attrs.merge!({"href" => href})
191
- temp.add_attributes(attrs)
192
- raise "Block argument is mandatory" unless block_given?
193
- text = encoding_fixer(block.call())
194
- temp.add_text(text)
195
- element_to_string(temp)
196
- end
197
-
198
- # Appends a <a href = > node after the @current nodes
199
- # @param href [String] this is the
200
- # @param attrs [Hash] attributes for the <a> element
201
- # @yieldreturn [String] the text to be added to the <a> element
202
- # @return [REXML::Element] the Element which was just added
203
- def link(href, attrs={}, &block)
204
- temp = REXML::Element.new("a")
205
- attrs.merge!({"href" => href})
206
- temp.add_attributes(attrs)
207
- @div_middle.insert_after(@current, temp)
208
- @current = temp
209
- raise "Block argument is mandatory" unless block_given?
210
- text = encoding_fixer(block.call())
211
- @current.add_text(text)
212
- return @current
213
- end
214
-
215
- # @see #image
216
- # Instead of adding content to the report, this method returns the produced html code as a string.
217
- # This can be used to insert code into #custom_table (with the option data_is_xhtml: true)
218
- # @return [String] the code including <pre> tags as a string
219
- def get_image_html(path, attributes = {})
220
- # read image as binary and do a base64 encoding
221
- binary_data = Base64.strict_encode64(IO.binread(path))
222
- type = File.extname(path).gsub('.', '')
223
- # create the element
224
- temp = REXML::Element.new("img")
225
- # add the picture
226
- temp.add_attribute("src","data:image/#{type};base64,#{binary_data}")
227
- temp.add_attributes(attributes)
228
- element_to_string(temp)
229
- end
230
-
231
- # @param path [String] absolute or relative path to the image that should be inserted into the report
232
- # @param attributes [Hash] attributes for the <img> element, any valid html attributes can be specified
233
- # you may specify attributes such "alt", "height", "width"
234
- # @option attrs [String] "class" by default every heading is added to the left table of contents (toc)
235
- def image(path, attributes = {})
236
- # read image as binary and do a base64 encoding
237
- binary_data = Base64.strict_encode64(IO.binread(path))
238
- type = File.extname(path).gsub('.', '')
239
- # create the element
240
- temp = REXML::Element.new("img")
241
- # add the picture
242
- temp.add_attribute("src","data:image/#{type};base64,#{binary_data}")
243
- temp.add_attributes(attributes)
244
-
245
- @div_middle.insert_after(@current, temp)
246
- @current = temp
247
- return @current
248
- end
249
-
250
- # Scans all REXML::Text children of an REXML::Element for any occurrences of regex.
251
- # The text will be matched as one, not line by line as you might think.
252
- # If you want to write a regexp matching multiple lines keep in mind that the dot "." by default doesn't
253
- # match newline characters. Consider using the "m" option (e.g. /regex/m ) which makes dot match newlines
254
- # or match newlines explicitly.
255
- # highlight_captures then puts a <span> </span> tag around all captures of the regex
256
- # NOTE: nested captures are not supported and don't make sense in this context!!
257
- # @param regex [Regexp] a regular expression that will be matched
258
- # @param color [String] either one of "y", "r", "g", "b" (yellow, red, green, blue) or a valid html color code (e.g. "#80BFFF")
259
- # @param el [REXML::Element] the Element (scope) which will be searched for pattern matches, by default the last inserted element will be scanned
260
- # @return [Fixnum] the number of highlighted captures
261
- def highlight_captures(regex, color="y", el = @current)
262
- # get all children of the current node
263
- arr = el.to_a()
264
- num_matches = 0
265
- # first we have to detach all children from parent, otherwise we can cause ordering issues
266
- arr.each {|i| i.remove() }
267
- # depth first recursion into grand-children
268
- for i in arr do
269
- if i.is_a?(REXML::Text)
270
- # in general a text looks as follows:
271
- # .*(matchstring|.*)*
272
-
273
- # We get an array of [[start,length], [start,length], ...] for all our regex SUB-matches
274
- positions = i.value().enum_for(:scan, regex).flat_map {
275
- # Regexp.last_match is a MatchData object, the index 0 is the entire match, 1 to n are captures
276
- array = Array.new
277
- for k in 1..Regexp.last_match.length - 1 do
278
- array.push([Regexp.last_match.begin(k),
279
- Regexp.last_match.end(k)-Regexp.last_match.begin(k)])
280
- end
281
- # return the array for the flat_map
282
- array
283
- }
284
- num_matches += positions.length
285
- if ["y","r","g","b"].include?(color)
286
- attr = {"class" => color}
287
- elsif color.match(/^#[A-Fa-f0-9]{6}$/)
288
- attr = {"style" => "background: #{color};"}
289
- else
290
- raise "invalid color: #{color}"
291
- end
292
- replace_text_with_elements(el, i, "span", attr, positions)
293
- else
294
- # for non-text nodes we recurse into it and finally reattach to our parent to preserve ordering
295
- num_matches += highlight_captures(regex, color, i)
296
- el.add(i)
297
- end # if i.is_a?(REXML::Text)
298
- end # for i in arr do
299
- return num_matches
300
- end
301
-
302
- # Scans all REXML::Text children of an REXML::Element for any occurrences of regex.
303
- # The text will be matched as one, not line by line as you might think.
304
- # If you want to write a regexp matching multiple lines keep in mind that the dot "." by default doesn't
305
- # match newline characters. Consider using the "m" option (e.g. /regex/m ) which makes dot match newlines
306
- # or match newlines explicitly.
307
- # highlight then puts a <span> </span> tag around all matches of regex
308
- # @param regex [Regexp] a regular expression that will be matched
309
- # @param color [String] either one of "y", "r", "g", "b" (yellow, red, green, blue) or a valid html color code (e.g. "#80BFFF")
310
- # @param el [REXML::Element] the Element (scope) which will be searched for pattern matches
311
- # @return [Fixnum] the number of highlighted captures
312
- def highlight(regex, color="y", el = @current)
313
- # get all children of the current node
314
- arr = el.to_a()
315
- num_matches = 0
316
- #puts arr.inspect
317
- # first we have to detach all children from parent, otherwise we can cause ordering issues
318
- arr.each {|i| i.remove() }
319
- # depth first recursion into grand-children
320
- for i in arr do
321
- #puts i.class.to_s()
322
- if i.is_a?(REXML::Text)
323
- # in general a text looks as follows:
324
- # .*(matchstring|.*)*
325
-
326
- # We get an array of [[start,length], [start,length], ...] for all our regex matches
327
- positions = i.value().enum_for(:scan, regex).map {
328
- [Regexp.last_match.begin(0),
329
- Regexp.last_match.end(0)-Regexp.last_match.begin(0)]
330
- }
331
- num_matches += positions.length
332
- if ["y","r","g","b"].include?(color)
333
- attr = {"class" => color}
334
- elsif color.match(/^#[A-Fa-f0-9]{6}$/)
335
- attr = {"style" => "background: #{color};"}
336
- else
337
- raise "invalid color: #{color}"
338
- end
339
- replace_text_with_elements(el, i, "span", attr, positions)
340
- else
341
- # for non-text nodes we recurse into it and finally reattach to our parent to preserve ordering
342
- # puts "recurse"
343
- num_matches += highlight(regex, color, i)
344
- el.add(i)
345
- end # if i.is_a?(REXML::Text)
346
- end # for i in arr do
347
- return num_matches
348
- end
349
-
350
- # creates a html table from two dimensional array of the form Array [row] [col]
351
- # @param table_data [Array<Array>] of the form Array [row] [col] containing all data, the '.to_s' method will be called on each element,
352
- # @param headers [Number] either of 0, 1, 2, 3. Where 0 is no headers (<th>) at all, 1 is only the first row,
353
- # 2 is only the first column and 3 is both, first row and first column as <th> elements. Every other number
354
- # is equivalent to the bitwise AND of the two least significant bits with 1, 2 or 3
355
- # @return [REXML::Element] the Element which was just added
356
- def table(table_data, headers=0, table_attrs={}, tr_attrs={}, th_attrs={}, td_attrs={})
357
- opts = {
358
- headers: headers,
359
- data_is_xhtml: false,
360
- table_attrs: table_attrs,
361
- th_attrs: th_attrs,
362
- tr_attrs: tr_attrs,
363
- td_attrs: td_attrs,
364
- }
365
- custom_table(table_data, opts)
366
- end
367
-
368
- # creates a html table from two dimensional array of the form Array [row] [col]
369
- # @param table_data [Array<Array>] of the form Array [row] [col] containing all data, the '.to_s' method will be called on each element,
370
- # @option opts [Number] :headers either of 0, 1, 2, 3. Where 0 is no headers (<th>) at all, 1 is only the first row,
371
- # 2 is only the first column and 3 is both, first row and first column as <th> elements. Every other number
372
- # is equivalent to the bitwise AND of the two least significant bits with 1, 2 or 3
373
- # @option opts [Boolean] :data_is_xhtml defaults to false, if true table_data is inserted as xhtml without any sanitation or escaping.
374
- # This way a table can be used for custom layouts.
375
- # @option opts [Hash] :table_attrs html attributes for the <table> tag
376
- # @option opts [Hash] :th_attrs html attributes for the <th> tag
377
- # @option opts [Hash] :tr_attrs html attributes for the <tr> tag
378
- # @option opts [Hash] :td_attrs html attributes for the <td> tag
379
- # @option opts [Array<Hash>] :special Array of hashes for custom attributes on specific cells (<td> only) of the table
380
- # @example Example of the :special attributes
381
- # opts[:special] = [
382
- # {
383
- # col_title: 'rx_DroppedFrameCount', # string or regexp or nil # if neither title nor index are present, the condition is evaluated for all <td> cells
384
- # col_index: 5..7, # Fixnum, Range or nil # index has precedence over title
385
- # row_title: 'D_0_BE_iMix', # string or regexp or nil
386
- # row_index: 6, # Fixnum, Range or nil
387
- # condition: Proc.new { |e| Integer(e) != 0 }, # a proc
388
- # attributes: {"style" => "background-color: #DB7093;"},
389
- # },
390
- # ]
391
- # @return [REXML::Element] the Element which was just added
392
- def custom_table(table_data, opts = {})
393
- defaults = {
394
- headers: 0,
395
- data_is_xhtml: false,
396
- table_attrs: {},
397
- th_attrs: {},
398
- tr_attrs: {},
399
- td_attrs: {},
400
- special: [],
401
- }
402
- o = defaults.merge(opts)
403
-
404
- temp = REXML::Element.new("table")
405
- temp.add_attributes(o[:table_attrs])
406
- row_titles = table_data.collect{|row| row[0].to_s}
407
- col_titles = table_data[0].collect{|title| title.to_s}
408
-
409
- for i in 0..table_data.length-1 do # row
410
- row = temp.add_element("tr", o[:tr_attrs])
411
- for j in 0..table_data[i].length-1 do # column
412
- if (i == 0 && (0x1 & o[:headers])==0x1)
413
- col = row.add_element("th", o[:th_attrs])
414
- elsif (j == 0 && (0x2 & o[:headers])==0x2)
415
- col = row.add_element("th", o[:th_attrs])
416
- elsif ((i == 0 || j ==0) && (0x3 & o[:headers])==0x3)
417
- col = row.add_element("th", o[:th_attrs])
418
- else
419
- # we need to deepcopy the attributes
420
- _td_attrs = Marshal.load(Marshal.dump(o[:td_attrs]))
421
-
422
- # check all special criteria
423
- o[:special].each do |h|
424
- # check if the current cell is a candidate for special
425
- if !h[:col_index].nil?
426
- if h[:col_index].is_a?(Range)
427
- next if (!h[:col_index].include?(j)) # skip if not in range
428
- elsif h[:col_index].is_a?(Integer)
429
- next if (h[:col_index] != j) # skip if not at index
430
- end
431
- elsif !h[:col_title].nil?
432
- next if !col_titles[j].match(h[:col_title])
433
- end
434
- # check if the current cell is a candidate for special
435
- if !h[:row_index].nil?
436
- if h[:row_index].is_a?(Range)
437
- next if (!h[:row_index].include?(i)) # skip if not in range
438
- elsif h[:row_index].is_a?(Integer)
439
- next if (h[:row_index] != i) # skip if not at index
440
- end
441
- elsif !h[:row_title].nil?
442
- next if !row_titles[i].match(h[:row_title])
443
- end
444
-
445
- # here we are a candidate for special, so we check if we meet the condition
446
- # puts h[:attributes].inspect
447
- # puts "cell value row #{i} col #{j}: #{table_data[i][j]}"
448
- # puts h[:condition].call(table_data[i][j]).inspect
449
- if h[:condition].call(table_data[i][j])
450
- h[:attributes].each { |attr, val|
451
- # debug, verify deepcopy
452
- # puts "objects are equal: #{_td_attrs[attr].equal?(o[:td_attrs][attr])}"
453
- if !_td_attrs[attr].nil?
454
- # assume the existing attribute is a string (other types don't make much sense for html)
455
- _td_attrs[attr] << val
456
- else
457
- # create the attribute if it is not already there
458
- _td_attrs[attr] = val
459
- end
460
- }
461
- end
462
- end
463
-
464
- col = row.add_element("td", _td_attrs)
465
- end
466
- if o[:data_is_xhtml]
467
- # we need to create a new document with a pseudo root because having multiple nodes at top
468
- # level is not valid xml
469
- doc = REXML::Document.new("<root>" + table_data[i][j].to_s + "</root>")
470
- # then we move all children of root to the actual div middle element and insert after current
471
- for elem in doc.root.to_a do
472
- col.add_element(elem) # add the td element
473
- end
474
- else
475
- col.add_text(table_data[i][j].to_s)
476
- end
477
- end
478
- end
479
-
480
- @div_middle.insert_after(@current, temp)
481
- @current = temp
482
- return @current
483
- end
484
-
485
-
486
- # Appends a new heading element to body, and sets current to this new heading
487
- # @param tag_type [String] specifiy "h1", "h2", "h3" for the heading, defaults to "h1"
488
- # @param attrs [Hash] attributes for the <h#> element, any valid html attributes can be specified
489
- # @option attrs [String] "class" by default every heading is added to the left table of contents (toc)
490
- # use the class "onlyrtoc" or "bothtoc" to add a heading only to the right toc or to both tocs respectively
491
- # @yieldreturn [String] the text to be added to the <h#> element
492
- # @return [REXML::Element] the Element which was just added
493
- def heading(tag_type="h1", attrs={}, &block)
494
- temp = REXML::Element.new(tag_type)
495
- temp.add_attributes(attrs)
496
-
497
- @div_middle.insert_after(@current, temp)
498
- @current = temp
499
- raise "Block argument is mandatory" unless block_given?
500
- text = encoding_fixer(block.call())
501
- @current.text = text
502
- return @current
503
- end
504
-
505
- # Inserts a new heading element at the very beginning of the middle div section, and points @current to this heading
506
- # @param tag_type [String] specifiy "h1", "h2", "h3" for the heading, defaults to "h1"
507
- # @param attrs [Hash] attributes for the <h#> element, any valid html attributes can be specified
508
- # @option attrs [String] "class" by default every heading is added to the left table of contents (toc)
509
- # use the class "onlyrtoc" or "bothtoc" to add a heading only to the right toc or to both tocs respectively
510
- # @yieldreturn [String] the text to be added to the <h#> element
511
- # @return [REXML::Element] the Element which was just added
512
- def heading_top(tag_type="h1", attrs={}, &block)
513
- temp = REXML::Element.new(tag_type)
514
- temp.add_attributes(attrs)
515
-
516
- # check if there are any child elements
517
- if @div_middle.has_elements?()
518
- # insert before the first child of div middle
519
- @div_middle.insert_before("//div[@id='middle']/*[1]", temp)
520
- else
521
- # middle is empty, just insert the heading
522
- @div_middle.insert_after(@current, temp)
523
- end
524
-
525
- @current = temp
526
- raise "Block argument is mandatory" unless block_given?
527
- text = encoding_fixer(block.call())
528
- @current.text = text
529
- return @current
530
- end
531
-
532
- # Helper Method for the highlight methods. it will introduce specific xhtml tags around parts of a text child of an xml element.
533
- # @example
534
- # we have the following xml part
535
- # <test>
536
- # some arbitrary
537
- # text child content
538
- # </test>
539
- # now we call replace_text_with_elements to place <span> around the word "arbitrary"
540
- # =>
541
- # <test>
542
- # some <span>arbitrary</span>
543
- # text child content
544
- # </test>
545
- # @param parent [REXML::Element] the parent to which "element" should be attached after parsing, e.g. <test>
546
- # @param element [REXML::Element] the Text element, into which tags will be added at the specified indices of @index_length_array, e.g. the REXML::Text children of <test> in the example
547
- # @param tagname [String] the tag that will be introduced as <tagname> at the indices specified
548
- # @param attribs [Hash] Attributes that will be added to the inserted tag e.g. <tagname attrib="test">
549
- # @param index_length_array [Array] Array of the form [[index, lenght], [index, lenght], ...] that specifies
550
- # the start position and length of the substring around which the tags will be introduced
551
- def replace_text_with_elements(parent, element, tagname, attribs, index_length_array)
552
- last_end = 0
553
- index = 0
554
- #puts index_length_array.inspect
555
- #puts element.inspect
556
- for j in index_length_array do
557
- # reattach normal (unmatched) text
558
- if j[0] > last_end
559
- # text = REXML::Text.new(element.value()[ last_end, j[0] - last_end ])
560
- # parent.add_text(text)
561
- # add text without creating a textnode, textnode screws up formatting (e.g. all whitespace are condensed into one)
562
- parent.add_text( element.value()[ last_end, j[0] - last_end ] )
563
- end
564
- #create the tag node with attributes and add the text to it
565
- tag = parent.add_element(REXML::Element.new(tagname), attribs)
566
- tag.add_text(element.value()[ j[0], j[1] ])
567
- last_end = j[0]+j[1]
568
-
569
- # in the last round check for any remaining text
570
- if index == index_length_array.length - 1
571
- if last_end < element.value().length
572
- # text = REXML::Text.new(element.value()[ last_end, element.value().length - last_end ])
573
- # parent.add(text)
574
- # add text without creating a textnode, textnode screws up formatting (e.g. all whitespace are condensed into one)
575
- parent.add_text( element.value()[ last_end, element.value().length - last_end ] )
576
- end
577
- end
578
- index += 1
579
- end # for j in positions do
580
-
581
- # don't forget to reattach the textnode if there are no regex matches at all
582
- if index == 0
583
- parent.add(element)
584
- end
585
-
586
- end
587
-
588
- #private_instance_methods(:replace_text_with_elements)
589
-
590
- end
591
-
592
- extend Custom
593
- #class Test
594
- # include XhtmlReportGenerator::Custom
595
- #
596
- #end
597
- #puts Test.new.header()