Class: TaskJuggler::RichTextElement

Inherits:
Object
  • Object
show all
Defined in:
lib/taskjuggler/RichText/Element.rb

Overview

The RichTextElement class models the nodes of the intermediate representation that the RichTextParser generates. Each node can reference an Array of other RichTextElement nodes, building a tree that represents the syntactical structure of the parsed RichText. Each node has a certain category that identifies the content of the node.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rt, category, arg = nil) ⇒ RichTextElement

Create a new RichTextElement node. rt is the RichText object this element belongs to. category is the type of the node. It can be :title, :bold, etc. arg is an overloaded argument. It can either be another node or an Array of RichTextElement nodes.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/taskjuggler/RichText/Element.rb', line 49

def initialize(rt, category, arg = nil)
  @richText = rt
  @category = category
  if arg
    if arg.is_a?(Array)
      @children = arg
    else
      unless arg.is_a?(RichTextElement) || arg.is_a?(String)
        raise "Element must be of type RichTextElement instead of " +
              "#{arg.class}"
      end
      @children = [ arg ]
    end
  else
    @children = []
  end

  # Certain elements such as titles,references and numbered bullets can be
  # require additional data. This variable is used for this. It can hold an
  # Array of counters or a link label.
  @data = nil
  @appendSpace = false
end

Instance Attribute Details

#appendSpaceObject

Returns the value of attribute appendSpace.



43
44
45
# File 'lib/taskjuggler/RichText/Element.rb', line 43

def appendSpace
  @appendSpace
end

#categoryObject (readonly)

Returns the value of attribute category.



41
42
43
# File 'lib/taskjuggler/RichText/Element.rb', line 41

def category
  @category
end

#childrenObject (readonly)

Returns the value of attribute children.



41
42
43
# File 'lib/taskjuggler/RichText/Element.rb', line 41

def children
  @children
end

#data=(value) ⇒ Object (writeonly)

Sets the attribute data

Parameters:

  • value

    the value to set the attribute data to.



42
43
44
# File 'lib/taskjuggler/RichText/Element.rb', line 42

def data=(value)
  @data = value
end

#richTextObject (readonly)

Returns the value of attribute richText.



41
42
43
# File 'lib/taskjuggler/RichText/Element.rb', line 41

def richText
  @richText
end

Instance Method Details

#checkHandlerObject



498
499
500
501
502
503
504
505
# File 'lib/taskjuggler/RichText/Element.rb', line 498

def checkHandler
  unless @data[0] && @data[0].is_a?(String)
    raise "Bad RichText function '#{@data[0]}' requested"
  end
  if @richText.functionHandler(@data[0]).nil?
    raise "No handler for #{@data[0]} registered"
  end
end

#children_to_sObject

Convert all childern into a single plain text String.



490
491
492
493
494
495
496
# File 'lib/taskjuggler/RichText/Element.rb', line 490

def children_to_s
  text = ''
  @children.each do |c|
    text << c.to_s + (c.is_a?(RichTextElement) && c.appendSpace ? ' ' : '')
  end
  text
end

#cleanUpObject

Remove a paragraph node from the richtext node if it is the only node in richtext. The paragraph children will become richtext children.



75
76
77
78
79
80
81
# File 'lib/taskjuggler/RichText/Element.rb', line 75

def cleanUp
  if @category == :richtext && @children.length == 1 &&
     @children[0].category == :paragraph
     @children = @children[0].children
  end
  self
end

#convertToID(text) ⇒ Object

This function converts a String into a new String that only contains characters that are acceptable for HTML tag IDs.



509
510
511
512
513
514
515
516
517
518
# File 'lib/taskjuggler/RichText/Element.rb', line 509

def convertToID(text)
  out = ''
  text.each_utf8_char do |c|
    out << c if (c >= 'A' && c <= 'Z') ||
                (c >= 'a' && c <= 'z') ||
                (c >= '0' && c <= '9')
    out << '_' if c == ' '
  end
  out.chomp('_')
end

#empty?Boolean

Return true of the node contains an empty RichText tree.

Returns:

  • (Boolean)


84
85
86
# File 'lib/taskjuggler/RichText/Element.rb', line 84

def empty?
  @category == :richtext && @children.empty?
end

#internalReferencesObject

Return an Array with all other snippet names that are referenced by internal references in this RichTextElement.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/taskjuggler/RichText/Element.rb', line 123

def internalReferences
  references = []
  if @category == :ref && !@data.include?(':')
      references << @data
  else
    @children.each do |el|
      if el.is_a?(RichTextElement)
        references += el.internalReferences
      end
    end
  end

  # We only need each reference once.
  references.uniq
end

#tableOfContents(toc, fileName) ⇒ Object

Recursively extract the section headings from the RichTextElement and build the TableOfContents toc with the gathered sections. fileName is the base name (without .html or other suffix) of the file the TOCEntries should point to.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/taskjuggler/RichText/Element.rb', line 93

def tableOfContents(toc, fileName)
  number = nil
  case @category
  when :title1
    number = "#{@data[0]} "
  when :title2
    number = "#{@data[0]}.#{@data[1]} "
  when :title3
    number = "#{@data[0]}.#{@data[1]}.#{@data[2]} "
  when :title4
    number = "#{@data[0]}.#{@data[1]}.#{@data[2]}.#{@data[3]} "
  end
  if number
    # We've found a section heading. The String value of the Element is the
    # title.
    title = children_to_s
    tag = convertToID(title)
    toc.addEntry(TOCEntry.new(number, title, fileName, tag))
  else
    # Recursively extract the TOC from the child objects.
    @children.each do |el|
      el.tableOfContents(toc, fileName) if el.is_a?(RichTextElement)
    end
  end

  toc
end

#to_htmlObject

Convert the intermediate representation into HTML elements.



376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/taskjuggler/RichText/Element.rb', line 376

def to_html
  noChilds = false
  attrs = {}
  attrs['class'] = @richText.cssClass if @richText.cssClass
  html =
  case @category
  when :richtext
    XMLElement.new(@richText.blockMode ? 'div' : 'span', attrs)
  when :title1
    htmlTitle(1)
  when :title2
    htmlTitle(2)
  when :title3
    htmlTitle(3)
  when :title4
    htmlTitle(4)
  when :hline
    noChilds = true
    XMLElement.new('hr', attrs, true)
  when :paragraph
    XMLElement.new('p', attrs)
  when :pre
    noChilds = true
    attrs['codesection'] = '1'
    div = XMLElement.new('div', attrs)
    div << (pre = XMLElement.new('pre', attrs))
    pre << XMLText.new(@children[0])
    div
  when :bulletlist1
    XMLElement.new('ul')
  when :bulletitem1
    XMLElement.new('li')
  when :bulletlist2
    XMLElement.new('ul')
  when :bulletitem2
    XMLElement.new('li')
  when :bulletlist3
    XMLElement.new('ul')
  when :bulletitem3
    XMLElement.new('li')
  when :bulletlist4
    XMLElement.new('ul')
  when :bulletitem4
    XMLElement.new('li')
  when :numberlist1
    XMLElement.new('ol')
  when :numberitem1
    XMLElement.new('li')
  when :numberlist2
    XMLElement.new('ol')
  when :numberitem2
    XMLElement.new('li')
  when :numberlist3
    XMLElement.new('ol')
  when :numberitem3
    XMLElement.new('li')
  when :numberlist4
    XMLElement.new('ol')
  when :numberitem4
    XMLElement.new('li')
  when :img
    htmlObject
  when :ref
    href = if @data.include?('#')
             # If the @data includes a reference to an anchor, we put the
             # anchor part after the .html extension.
             pre, post = @data.split('#')
             pre + '.html#' + post
           else
             @data + '.html'
           end
    XMLElement.new('a', 'href' => href)
  when :href
    a = XMLElement.new('a', 'href' => @data.to_s)
    a['target'] = @richText.linkTarget if @richText.linkTarget
    a
  when :blockfunc
    noChilds = true
    checkHandler
    @richText.functionHandler(@data[0]).to_html(@data[1])
  when :inlinefunc
    noChilds = true
    checkHandler
    @richText.functionHandler(@data[0]).to_html(@data[1])
  when :italic
    XMLElement.new('i')
  when :bold
    XMLElement.new('b')
  when :fontCol
    XMLElement.new('span', 'style' => "color:#{@data}")
  when :code
    XMLElement.new('code', attrs)
  when :htmlblob
    noChilds = true
    XMLBlob.new(@children[0])
  when :text
    noChilds = true
    XMLText.new(@children[0])
  else
    raise "Unknown RichTextElement category #{@category}"
  end

  # Some elements never have leaves.
  return html if noChilds

  @children.each do |el_i|
    html << el_i.to_html
    html << XMLText.new(' ') if el_i.appendSpace
  end

  html
end

#to_sObject

Conver the intermediate representation into a plain text again. All elements that can’t be represented in plain text easily will be ignored or just their value will be included.



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
231
232
233
234
# File 'lib/taskjuggler/RichText/Element.rb', line 142

def to_s
  pre = ''
  post = ''
  case @category
  when :richtext
  when :title1
    return textBlockFormat(@richText.indent + @richText.titleIndent,
                           sTitle(1), children_to_s,
                           @richText.lineWidth) + "\n"
  when :title2
    return textBlockFormat(@richText.indent + @richText.titleIndent,
                           sTitle(2), children_to_s,
                           @richText.lineWidth) + "\n"
  when :title3
    return textBlockFormat(@richText.indent + @richText.titleIndent,
                           sTitle(3), children_to_s,
                           @richText.lineWidth) + "\n"
  when :title4
    return textBlockFormat(@richText.indent + @richText.titleIndent,
                           sTitle(4), children_to_s,
                           @richText.lineWidth) + "\n"
  when :hline
    return "#{' ' * @richText.indent}" +
           "#{'-' * (@richText.lineWidth - @richText.indent)}\n"
  when :paragraph
    return textBlockFormat(@richText.indent + @richText.parIndent,
                           '', children_to_s, @richText.lineWidth) + "\n"
  when :pre
    return TextFormatter.new(@richText.lineWidth,
                             @richText.indent + @richText.preIndent).
      indent(children_to_s) + "\n"
  when :bulletlist1
  when :bulletitem1
    return textBlockFormat(@richText.indent + @richText.listIndent,
                           '* ', children_to_s,
                           @richText.lineWidth) + "\n"
  when :bulletlist2
  when :bulletitem2
    return textBlockFormat(@richText.indent + @richText.listIndent * 2,
                           '* ', children_to_s,
                           @richText.lineWidth) + "\n"
  when :bulletlist3
  when :bulletitem3
    return textBlockFormat(@richText.indent + @richText.listIndent * 3,
                           '* ', children_to_s,
                           @richText.lineWidth) + "\n"
  when :bulletlist4
  when :bulletitem4
    return textBlockFormat(@richText.indent + @richText.listIndent * 4,
                           '* ', children_to_s,
                           @richText.lineWidth) + "\n"
  when :numberlist1
  when :numberitem1
    return textBlockFormat(@richText.indent + @richText.listIndent,
                           "#{@data[0]}. ", children_to_s,
                           @richText.lineWidth) + "\n"
  when :numberlist2
  when :numberitem2
    return textBlockFormat(@richText.indent + @richText.listIndent,
                           "#{@data[0]}.#{@data[1]} ", children_to_s,
                           @richText.lineWidth) + "\n"
  when :numberlist3
  when :numberitem3
    return textBlockFormat(@richText.indent + @richText.listIndent,
                           "#{@data[0]}.#{@data[1]}.#{@data[2]} ",
                           children_to_s, @richText.lineWidth) + "\n"
  when :numberlist4
  when :numberitem4
    return textBlockFormat(@richText.indent + @richText.listIndent,
                           "#{@data[0]}.#{@data[1]}.#{@data[2]}." +
                           "#{@data[3]} ",
                           children_to_s, @richText.lineWidth) + "\n"
  when :img
    pre = @data.altText if @data.altText
  when :ref
  when :href
  when :blockfunc
  when :inlinefunc
    checkHandler
    pre = @richText.functionHandler(@data[0]).to_s(@data[1])
  when :italic
  when :bold
  when :fontCol
  when :code
  when :text
  when :htmlblob
    return ''
  else
    raise "Unknown RichTextElement category #{@category}"
  end

  pre + children_to_s + post
end

#to_taggedObject

Convert the tree of RichTextElement nodes into an XML like text representation. This is primarily intended for unit testing. The tag names are similar to HTML tags, but this is not meant to be valid HTML.



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/taskjuggler/RichText/Element.rb', line 239

def to_tagged
  pre = ''
  post = ''
  case @category
  when :richtext
    pre = '<div>'
    post = '</div>'
  when :title1
    pre = "<h1>#{@data[0]} "
    post = "</h1>\n\n"
  when :title2
    pre = "<h2>#{@data[0]}.#{@data[1]} "
    post = "</h2>\n\n"
  when :title3
    pre = "<h3>#{@data[0]}.#{@data[1]}.#{@data[2]} "
    post = "</h3>\n\n"
  when :title4
    pre = "<h4>#{@data[0]}.#{@data[1]}.#{@data[2]}.#{@data[3]} "
    post = "</h4>\n\n"
  when :hline
    pre = '<hr>'
    post = "</hr>\n"
  when :paragraph
    pre = '<p>'
    post = "</p>\n\n"
  when :pre
    pre = '<pre>'
    post = "</pre>\n\n"
  when :bulletlist1
    pre = '<ul>'
    post = '</ul>'
  when :bulletitem1
    pre = '<li>* '
    post = "</li>\n"
  when :bulletlist2
    pre = '<ul>'
    post = '</ul>'
  when :bulletitem2
    pre = '<li> * '
    post = "</li>\n"
  when :bulletlist3
    pre = '<ul>'
    post = '</ul>'
  when :bulletitem3
    pre = '<li>  * '
    post = "</li>\n"
  when :bulletlist4
    pre = '<ul>'
    post = '</ul>'
  when :bulletitem4
    pre = '<li>   * '
    post = "</li>\n"
  when :numberlist1
    pre = '<ol>'
    post = '</ol>'
  when :numberitem1
    pre = "<li>#{@data[0]} "
    post = "</li>\n"
  when :numberlist2
    pre = '<ol>'
    post = '</ol>'
  when :numberitem2
    pre = "<li>#{@data[0]}.#{@data[1]} "
    post = "</li>\n"
  when :numberlist3
    pre = '<ol>'
    post = '</ol>'
  when :numberitem3
    pre = "<li>#{@data[0]}.#{@data[1]}.#{@data[2]} "
    post = "</li>\n"
  when :numberlist4
    pre = '<ol>'
    post = '</ol>'
  when :numberitem4
    pre = "<li>#{@data[0]}.#{@data[1]}.#{@data[2]}.#{@data[3]} "
    post = "</li>\n"
  when :img
    pre = "<img file=\"#{@data.fileName}\"/>"
  when :ref
    pre = "<ref data=\"#{@data}\">"
    post = '</ref>'
  when :href
    pre = "<a href=\"#{@data}\" #{@richText.linkTarget ?
                                  "target=\"#{@richText.linkTarget}\"" :
                                  ""}>"
    post = '</a>'
  when :blockfunc
    pre = "<blockfunc:#{@data[0]}"
    if @data[1]
      @data[1].keys.sort.each do |key|
        pre += " #{key}=\"#{@data[1][key].gsub(/"/, '\"')}\""
      end
    end
    post = "/>"
  when :inlinefunc
    pre = "<inlinefunc:#{@data[0]}"
    if @data[1]
      @data[1].keys.sort.each do |key|
        pre += " #{key}=\"#{@data[1][key]}\""
      end
    end
    post = "/>"
  when :italic
    pre = '<i>'
    post = '</i>'
  when :bold
    pre = '<b>'
    post = '</b>'
  when :fontCol
    pre = "<fcol:#{@data}>"
    post = '</fcol>'
  when :code
    pre = '<code>'
    post = '</code>'
  when :htmlblob
    pre = '<html>'
    post = '</html>'
  when :text
    pre = '['
    post = ']'
  else
    raise "Unknown RichTextElement category #{@category}"
  end

  out = ''
  @children.each do |el|
    if el.is_a?(RichTextElement)
      out << el.to_tagged + (el.appendSpace ? ' ' : '')
    else
      out << el.to_s
    end
  end

  pre + out + post
end