poml 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/lib/poml/components/base.rb +45 -7
- data/lib/poml/components/data.rb +259 -0
- data/lib/poml/components/examples.rb +159 -13
- data/lib/poml/components/formatting.rb +148 -0
- data/lib/poml/components/media.rb +34 -0
- data/lib/poml/components/meta.rb +248 -0
- data/lib/poml/components/template.rb +334 -0
- data/lib/poml/components/utilities.rb +508 -0
- data/lib/poml/components.rb +91 -2
- data/lib/poml/context.rb +41 -2
- data/lib/poml/parser.rb +128 -15
- data/lib/poml/renderer.rb +26 -7
- data/lib/poml/template_engine.rb +101 -4
- data/lib/poml/version.rb +1 -1
- data/lib/poml.rb +67 -1
- data/{README.md → readme.md} +9 -1
- metadata +8 -4
- data/examples/_generate_expects.py +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c09d0d76e15b722fd0ac52fc6dfe843eebe6f85e18f9b4a4444c43d6c8ca651
|
4
|
+
data.tar.gz: fb88b15378606b36242f7c80b3db61502bc3be8c0403565601250d0e9bce748a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f61b599f4f5548c38e74fd1413fba6ed3489f8cf8ca4b518d943dcf7205cf8101ae962ef95fc9d9a8eba46ace47f303f0a8d2abcdce643fa1e32be7d6c86abf
|
7
|
+
data.tar.gz: a28b8954f93dd2c5a54a2353029401f37e78047b9d2e74b721d43ec3eb03ab5939cffedf52eabdbc38d73ae6f9d37dcbc65ddf059750167da5a8bd1ee24208d1
|
data/lib/poml/components/base.rb
CHANGED
@@ -16,7 +16,8 @@ module Poml
|
|
16
16
|
|
17
17
|
def apply_stylesheet
|
18
18
|
# Apply stylesheet rules to the element
|
19
|
-
|
19
|
+
stylesheet = @context.respond_to?(:stylesheet) ? @context.stylesheet : {}
|
20
|
+
style_rules = stylesheet[@element.tag_name.to_s] || {}
|
20
21
|
style_rules.each do |attr, value|
|
21
22
|
@element.attributes[attr] ||= value
|
22
23
|
end
|
@@ -24,7 +25,7 @@ module Poml
|
|
24
25
|
# Apply class-based styles
|
25
26
|
class_name = @element.attributes['classname'] || @element.attributes['className']
|
26
27
|
if class_name
|
27
|
-
class_rules =
|
28
|
+
class_rules = stylesheet[".#{class_name}"] || {}
|
28
29
|
class_rules.each do |attr, value|
|
29
30
|
@element.attributes[attr] ||= value
|
30
31
|
end
|
@@ -32,7 +33,11 @@ module Poml
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def xml_mode?
|
35
|
-
@context.determine_syntax
|
36
|
+
if @context.respond_to?(:determine_syntax)
|
37
|
+
@context.determine_syntax(@element) == 'xml'
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
36
41
|
end
|
37
42
|
|
38
43
|
def render_as_xml(tag_name, content = nil, attributes = {})
|
@@ -81,13 +86,17 @@ module Poml
|
|
81
86
|
rendered_children.each_with_index do |child_content, index|
|
82
87
|
result << child_content
|
83
88
|
|
84
|
-
# Add spacing if current element is text and next element is a component
|
89
|
+
# Add spacing if current element is text and next element is a block-level component
|
85
90
|
if index < rendered_children.length - 1
|
86
91
|
current_element = @element.children[index]
|
87
92
|
next_element = @element.children[index + 1]
|
88
93
|
|
94
|
+
# Only add spacing for block-level components, not inline components
|
89
95
|
if current_element.text? && next_element.component?
|
90
|
-
|
96
|
+
next_component_class = Components::COMPONENT_MAPPING[next_element.tag_name]
|
97
|
+
if next_component_class && !is_inline_component?(next_component_class)
|
98
|
+
result << "\n\n"
|
99
|
+
end
|
91
100
|
end
|
92
101
|
end
|
93
102
|
end
|
@@ -102,8 +111,9 @@ module Poml
|
|
102
111
|
component_name = self.class.name.split('::').last.gsub('Component', '').downcase
|
103
112
|
|
104
113
|
# Check for text transformation in stylesheet - first try component-specific, then "cp" (for captioned paragraph inheritance)
|
105
|
-
|
106
|
-
|
114
|
+
stylesheet = @context.respond_to?(:stylesheet) ? @context.stylesheet : {}
|
115
|
+
transform = stylesheet.dig(component_name, 'captionTextTransform') ||
|
116
|
+
stylesheet.dig('cp', 'captionTextTransform')
|
107
117
|
|
108
118
|
case transform
|
109
119
|
when 'upper'
|
@@ -116,6 +126,34 @@ module Poml
|
|
116
126
|
text
|
117
127
|
end
|
118
128
|
end
|
129
|
+
|
130
|
+
def inline_component?
|
131
|
+
# Override this in inline components
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.inline_component_classes
|
136
|
+
# List of component classes that should be treated as inline
|
137
|
+
@inline_component_classes ||= []
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.register_inline_component(component_class)
|
141
|
+
inline_component_classes << component_class
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def is_inline_component?(component_class)
|
147
|
+
# Check if the component class is registered as inline
|
148
|
+
# For now, we'll use a simple list of known inline formatting components
|
149
|
+
inline_component_names = %w[
|
150
|
+
BoldComponent ItalicComponent UnderlineComponent StrikethroughComponent
|
151
|
+
CodeComponent InlineComponent
|
152
|
+
]
|
153
|
+
|
154
|
+
component_class_name = component_class.name.split('::').last
|
155
|
+
inline_component_names.include?(component_class_name)
|
156
|
+
end
|
119
157
|
end
|
120
158
|
|
121
159
|
# Component registry and factory
|
data/lib/poml/components/data.rb
CHANGED
@@ -22,6 +22,9 @@ module Poml
|
|
22
22
|
load_table_data(src, parser)
|
23
23
|
elsif records_attr
|
24
24
|
parse_records_attribute(records_attr)
|
25
|
+
elsif @element.children.any? { |child| child.tag_name == :tr }
|
26
|
+
# Handle HTML-style table markup
|
27
|
+
parse_html_table_children
|
25
28
|
else
|
26
29
|
{ records: [], columns: [] }
|
27
30
|
end
|
@@ -147,6 +150,39 @@ module Poml
|
|
147
150
|
{ records: records.is_a?(Array) ? records : [records], columns: columns }
|
148
151
|
end
|
149
152
|
|
153
|
+
def parse_html_table_children
|
154
|
+
records = []
|
155
|
+
columns = []
|
156
|
+
|
157
|
+
# Extract rows from tr children
|
158
|
+
@element.children.each do |child|
|
159
|
+
next unless child.tag_name == :tr
|
160
|
+
|
161
|
+
row_data = {}
|
162
|
+
child.children.each_with_index do |cell, index|
|
163
|
+
next unless cell.tag_name == :td || cell.tag_name == :th
|
164
|
+
|
165
|
+
# Get cell content (render children to get text)
|
166
|
+
cell_content = cell.children.map do |cell_child|
|
167
|
+
Components.render_element(cell_child, @context)
|
168
|
+
end.join('').strip
|
169
|
+
|
170
|
+
# Use cell content as content, index as key for now
|
171
|
+
column_key = "col_#{index}"
|
172
|
+
row_data[column_key] = cell_content
|
173
|
+
|
174
|
+
# Track columns
|
175
|
+
unless columns.any? { |col| col[:field] == column_key }
|
176
|
+
columns << { field: column_key, header: "Column #{index + 1}" }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
records << row_data unless row_data.empty?
|
181
|
+
end
|
182
|
+
|
183
|
+
{ records: records, columns: columns }
|
184
|
+
end
|
185
|
+
|
150
186
|
def apply_selection(data, selected_columns, selected_records, max_records, max_columns)
|
151
187
|
records = data[:records]
|
152
188
|
columns = data[:columns]
|
@@ -327,6 +363,229 @@ module Poml
|
|
327
363
|
end
|
328
364
|
end
|
329
365
|
|
366
|
+
# Object component for displaying structured data
|
367
|
+
class ObjectComponent < Component
|
368
|
+
require 'json'
|
369
|
+
require 'yaml'
|
370
|
+
|
371
|
+
def render
|
372
|
+
apply_stylesheet
|
373
|
+
|
374
|
+
data = get_attribute('data')
|
375
|
+
syntax = get_attribute('syntax', 'json')
|
376
|
+
|
377
|
+
return '' unless data
|
378
|
+
|
379
|
+
if xml_mode?
|
380
|
+
render_as_xml('obj', serialize_data(data, syntax))
|
381
|
+
else
|
382
|
+
serialize_data(data, syntax)
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
private
|
387
|
+
|
388
|
+
def serialize_data(data, syntax)
|
389
|
+
case syntax.downcase
|
390
|
+
when 'json'
|
391
|
+
JSON.pretty_generate(data)
|
392
|
+
when 'yaml', 'yml'
|
393
|
+
YAML.dump(data)
|
394
|
+
when 'xml'
|
395
|
+
# Simple XML serialization for basic data structures
|
396
|
+
serialize_to_xml(data)
|
397
|
+
else
|
398
|
+
data.to_s
|
399
|
+
end
|
400
|
+
rescue => e
|
401
|
+
"[Error serializing data: #{e.message}]"
|
402
|
+
end
|
403
|
+
|
404
|
+
def serialize_to_xml(data, root_name = 'data', indent = 0)
|
405
|
+
spaces = ' ' * indent
|
406
|
+
|
407
|
+
case data
|
408
|
+
when Hash
|
409
|
+
result = ["#{spaces}<#{root_name}>"]
|
410
|
+
data.each do |key, value|
|
411
|
+
result << serialize_to_xml(value, key, indent + 1)
|
412
|
+
end
|
413
|
+
result << "#{spaces}</#{root_name}>"
|
414
|
+
result.join("\n")
|
415
|
+
when Array
|
416
|
+
result = ["#{spaces}<#{root_name}>"]
|
417
|
+
data.each_with_index do |item, index|
|
418
|
+
result << serialize_to_xml(item, "item#{index}", indent + 1)
|
419
|
+
end
|
420
|
+
result << "#{spaces}</#{root_name}>"
|
421
|
+
result.join("\n")
|
422
|
+
else
|
423
|
+
"#{spaces}<#{root_name}>#{escape_xml(data)}</#{root_name}>"
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def escape_xml(text)
|
428
|
+
text.to_s.gsub('&', '&').gsub('<', '<').gsub('>', '>')
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
# Webpage component for displaying web content
|
433
|
+
class WebpageComponent < Component
|
434
|
+
def render
|
435
|
+
apply_stylesheet
|
436
|
+
|
437
|
+
url = get_attribute('url')
|
438
|
+
src = get_attribute('src')
|
439
|
+
buffer = get_attribute('buffer')
|
440
|
+
base64 = get_attribute('base64')
|
441
|
+
extract_text = get_attribute('extractText', false)
|
442
|
+
selector = get_attribute('selector', 'body')
|
443
|
+
syntax = get_attribute('syntax', 'text')
|
444
|
+
|
445
|
+
content = if url
|
446
|
+
fetch_webpage_content(url, selector, extract_text)
|
447
|
+
elsif src
|
448
|
+
read_html_file(src, selector, extract_text)
|
449
|
+
elsif buffer
|
450
|
+
process_html_content(buffer, selector, extract_text)
|
451
|
+
elsif base64
|
452
|
+
require 'base64'
|
453
|
+
decoded = Base64.decode64(base64)
|
454
|
+
process_html_content(decoded, selector, extract_text)
|
455
|
+
else
|
456
|
+
'[Webpage: no source specified]'
|
457
|
+
end
|
458
|
+
|
459
|
+
if xml_mode?
|
460
|
+
render_as_xml('webpage', content)
|
461
|
+
else
|
462
|
+
content
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
private
|
467
|
+
|
468
|
+
def fetch_webpage_content(url, selector, extract_text)
|
469
|
+
begin
|
470
|
+
require 'net/http'
|
471
|
+
require 'uri'
|
472
|
+
|
473
|
+
uri = URI.parse(url)
|
474
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
475
|
+
http.use_ssl = true if uri.scheme == 'https'
|
476
|
+
http.read_timeout = 10
|
477
|
+
|
478
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
479
|
+
request['User-Agent'] = 'POML/1.0'
|
480
|
+
|
481
|
+
response = http.request(request)
|
482
|
+
|
483
|
+
if response.code == '200'
|
484
|
+
process_html_content(response.body, selector, extract_text)
|
485
|
+
else
|
486
|
+
"[Webpage: HTTP #{response.code} error fetching #{url}]"
|
487
|
+
end
|
488
|
+
rescue => e
|
489
|
+
"[Webpage: Error fetching #{url}: #{e.message}]"
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def read_html_file(file_path, selector, extract_text)
|
494
|
+
begin
|
495
|
+
# Resolve relative paths
|
496
|
+
full_path = if file_path.start_with?('/')
|
497
|
+
file_path
|
498
|
+
else
|
499
|
+
base_path = @context.source_path ? File.dirname(@context.source_path) : Dir.pwd
|
500
|
+
File.join(base_path, file_path)
|
501
|
+
end
|
502
|
+
|
503
|
+
unless File.exist?(full_path)
|
504
|
+
return "[Webpage: File not found: #{file_path}]"
|
505
|
+
end
|
506
|
+
|
507
|
+
html_content = File.read(full_path)
|
508
|
+
process_html_content(html_content, selector, extract_text)
|
509
|
+
rescue => e
|
510
|
+
"[Webpage: Error reading file #{file_path}: #{e.message}]"
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
def process_html_content(html_content, selector, extract_text)
|
515
|
+
begin
|
516
|
+
require 'nokogiri'
|
517
|
+
|
518
|
+
doc = Nokogiri::HTML(html_content)
|
519
|
+
|
520
|
+
# Apply selector if specified
|
521
|
+
if selector && selector != 'body'
|
522
|
+
selected = doc.css(selector).first
|
523
|
+
return "[Webpage: Selector '#{selector}' not found]" unless selected
|
524
|
+
doc = selected
|
525
|
+
end
|
526
|
+
|
527
|
+
if extract_text
|
528
|
+
# Extract plain text
|
529
|
+
doc.text.strip.gsub(/\s+/, ' ')
|
530
|
+
else
|
531
|
+
# Convert HTML to structured POML-like format
|
532
|
+
convert_html_to_poml(doc)
|
533
|
+
end
|
534
|
+
rescue LoadError
|
535
|
+
# Nokogiri not available, do simple text extraction
|
536
|
+
if extract_text
|
537
|
+
html_content.gsub(/<[^>]*>/, ' ').gsub(/\s+/, ' ').strip
|
538
|
+
else
|
539
|
+
html_content
|
540
|
+
end
|
541
|
+
rescue => e
|
542
|
+
"[Webpage: Error processing HTML: #{e.message}]"
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
def convert_html_to_poml(element)
|
547
|
+
case element.name.downcase
|
548
|
+
when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
|
549
|
+
level = element.name[1].to_i
|
550
|
+
"#{('#' * level)} #{element.text.strip}\n\n"
|
551
|
+
when 'p'
|
552
|
+
"#{element.text.strip}\n\n"
|
553
|
+
when 'ul', 'ol'
|
554
|
+
items = element.css('li').map { |li| "- #{li.text.strip}" }
|
555
|
+
"#{items.join("\n")}\n\n"
|
556
|
+
when 'strong', 'b'
|
557
|
+
"**#{element.text.strip}**"
|
558
|
+
when 'em', 'i'
|
559
|
+
"*#{element.text.strip}*"
|
560
|
+
when 'code'
|
561
|
+
"`#{element.text.strip}`"
|
562
|
+
when 'pre'
|
563
|
+
"```\n#{element.text.strip}\n```\n\n"
|
564
|
+
when 'blockquote'
|
565
|
+
lines = element.text.strip.split("\n")
|
566
|
+
quoted = lines.map { |line| "> #{line}" }
|
567
|
+
"#{quoted.join("\n")}\n\n"
|
568
|
+
when 'a'
|
569
|
+
href = element['href']
|
570
|
+
text = element.text.strip
|
571
|
+
href ? "[#{text}](#{href})" : text
|
572
|
+
when 'img'
|
573
|
+
alt = element['alt'] || 'Image'
|
574
|
+
src = element['src']
|
575
|
+
src ? "" : "[#{alt}]"
|
576
|
+
else
|
577
|
+
# For other elements, process children recursively
|
578
|
+
if element.children.any?
|
579
|
+
element.children.map { |child|
|
580
|
+
child.text? ? child.text : convert_html_to_poml(child)
|
581
|
+
}.join('')
|
582
|
+
else
|
583
|
+
element.text.strip
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
330
589
|
# Image component
|
331
590
|
class ImageComponent < Component
|
332
591
|
def render
|
@@ -5,7 +5,38 @@ module Poml
|
|
5
5
|
apply_stylesheet
|
6
6
|
|
7
7
|
content = @element.content.empty? ? render_children : @element.content
|
8
|
-
|
8
|
+
caption = get_attribute('caption', 'Example')
|
9
|
+
caption_style = get_attribute('captionStyle', 'hidden')
|
10
|
+
chat = get_attribute('chat', nil)
|
11
|
+
|
12
|
+
if xml_mode?
|
13
|
+
render_as_xml('example', content)
|
14
|
+
else
|
15
|
+
# Determine if chat format should be used
|
16
|
+
if chat.nil?
|
17
|
+
# Auto-detect: use chat format for markup syntaxes by default
|
18
|
+
use_chat = @context.determine_syntax(@element) != 'xml'
|
19
|
+
else
|
20
|
+
use_chat = chat
|
21
|
+
end
|
22
|
+
|
23
|
+
if use_chat && caption_style == 'hidden'
|
24
|
+
content
|
25
|
+
else
|
26
|
+
case caption_style
|
27
|
+
when 'header'
|
28
|
+
"## #{caption}\n\n#{content}\n\n"
|
29
|
+
when 'bold'
|
30
|
+
"**#{caption}:** #{content}\n\n"
|
31
|
+
when 'plain'
|
32
|
+
"#{caption}: #{content}\n\n"
|
33
|
+
when 'hidden'
|
34
|
+
"#{content}\n\n"
|
35
|
+
else
|
36
|
+
"#{content}\n\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
9
40
|
end
|
10
41
|
end
|
11
42
|
|
@@ -15,7 +46,26 @@ module Poml
|
|
15
46
|
apply_stylesheet
|
16
47
|
|
17
48
|
content = @element.content.empty? ? render_children : @element.content
|
18
|
-
|
49
|
+
caption = get_attribute('caption', 'Input')
|
50
|
+
caption_style = get_attribute('captionStyle', 'hidden')
|
51
|
+
speaker = get_attribute('speaker', 'human')
|
52
|
+
|
53
|
+
if xml_mode?
|
54
|
+
render_as_xml('input', content, { speaker: speaker })
|
55
|
+
else
|
56
|
+
case caption_style
|
57
|
+
when 'header'
|
58
|
+
"## #{caption}\n\n#{content}\n\n"
|
59
|
+
when 'bold'
|
60
|
+
"**#{caption}:** #{content}\n\n"
|
61
|
+
when 'plain'
|
62
|
+
"#{caption}: #{content}\n\n"
|
63
|
+
when 'hidden'
|
64
|
+
"#{content}\n\n"
|
65
|
+
else
|
66
|
+
"#{content}\n\n"
|
67
|
+
end
|
68
|
+
end
|
19
69
|
end
|
20
70
|
end
|
21
71
|
|
@@ -25,7 +75,71 @@ module Poml
|
|
25
75
|
apply_stylesheet
|
26
76
|
|
27
77
|
content = @element.content.empty? ? render_children : @element.content
|
28
|
-
|
78
|
+
caption = get_attribute('caption', 'Output')
|
79
|
+
caption_style = get_attribute('captionStyle', 'hidden')
|
80
|
+
speaker = get_attribute('speaker', 'ai')
|
81
|
+
|
82
|
+
if xml_mode?
|
83
|
+
render_as_xml('output', content, { speaker: speaker })
|
84
|
+
else
|
85
|
+
case caption_style
|
86
|
+
when 'header'
|
87
|
+
"## #{caption}\n\n#{content}\n\n"
|
88
|
+
when 'bold'
|
89
|
+
"**#{caption}:** #{content}\n\n"
|
90
|
+
when 'plain'
|
91
|
+
"#{caption}: #{content}\n\n"
|
92
|
+
when 'hidden'
|
93
|
+
"#{content}\n\n"
|
94
|
+
else
|
95
|
+
"#{content}\n\n"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Example set component for managing multiple examples
|
102
|
+
class ExampleSetComponent < Component
|
103
|
+
def render
|
104
|
+
apply_stylesheet
|
105
|
+
|
106
|
+
caption = get_attribute('caption', 'Examples')
|
107
|
+
caption_style = get_attribute('captionStyle', 'header')
|
108
|
+
chat = get_attribute('chat', true)
|
109
|
+
introducer = get_attribute('introducer', '')
|
110
|
+
|
111
|
+
content = @context.with_chat_context(chat) { render_children }
|
112
|
+
|
113
|
+
if xml_mode?
|
114
|
+
render_as_xml('examples', content)
|
115
|
+
else
|
116
|
+
result = []
|
117
|
+
|
118
|
+
case caption_style
|
119
|
+
when 'header'
|
120
|
+
result << "# #{caption}"
|
121
|
+
when 'bold'
|
122
|
+
result << "**#{caption}:**"
|
123
|
+
when 'plain'
|
124
|
+
result << "#{caption}:"
|
125
|
+
when 'hidden'
|
126
|
+
# No caption
|
127
|
+
else
|
128
|
+
result << "# #{caption}"
|
129
|
+
end
|
130
|
+
|
131
|
+
result << "" unless result.empty? # Add blank line after caption
|
132
|
+
|
133
|
+
unless introducer.empty?
|
134
|
+
result << introducer
|
135
|
+
result << ""
|
136
|
+
end
|
137
|
+
|
138
|
+
result << content
|
139
|
+
result << ""
|
140
|
+
|
141
|
+
result.join("\n")
|
142
|
+
end
|
29
143
|
end
|
30
144
|
end
|
31
145
|
|
@@ -38,17 +152,49 @@ module Poml
|
|
38
152
|
caption_style = get_attribute('captionStyle', 'header')
|
39
153
|
content = @element.content.empty? ? render_children : @element.content
|
40
154
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
155
|
+
if xml_mode?
|
156
|
+
render_as_xml('outputFormat', content)
|
157
|
+
else
|
158
|
+
case caption_style
|
159
|
+
when 'header'
|
160
|
+
"# #{caption}\n\n#{content}\n\n"
|
161
|
+
when 'bold'
|
162
|
+
"**#{caption}:** #{content}\n\n"
|
163
|
+
when 'plain'
|
164
|
+
"#{caption}: #{content}\n\n"
|
165
|
+
when 'hidden'
|
166
|
+
"#{content}\n\n"
|
167
|
+
else
|
168
|
+
"# #{caption}\n\n#{content}\n\n"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Introducer component
|
175
|
+
class IntroducerComponent < Component
|
176
|
+
def render
|
177
|
+
apply_stylesheet
|
178
|
+
|
179
|
+
content = @element.content.empty? ? render_children : @element.content
|
180
|
+
caption = get_attribute('caption', 'Introducer')
|
181
|
+
caption_style = get_attribute('captionStyle', 'hidden')
|
182
|
+
|
183
|
+
if xml_mode?
|
184
|
+
render_as_xml('introducer', content)
|
50
185
|
else
|
51
|
-
|
186
|
+
case caption_style
|
187
|
+
when 'header'
|
188
|
+
"# #{caption}\n\n#{content}\n\n"
|
189
|
+
when 'bold'
|
190
|
+
"**#{caption}:** #{content}\n\n"
|
191
|
+
when 'plain'
|
192
|
+
"#{caption}: #{content}\n\n"
|
193
|
+
when 'hidden'
|
194
|
+
"#{content}\n\n"
|
195
|
+
else
|
196
|
+
"#{content}\n\n"
|
197
|
+
end
|
52
198
|
end
|
53
199
|
end
|
54
200
|
end
|