xhtml_report_generator 3.1.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
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()