asciidoctor-dita-topic 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/dita-topic.rb +704 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a78953056690681fd5bd90e2ddc9bf86fc58a97e13ef88e3493aaccfd841af38
|
4
|
+
data.tar.gz: a6f0615ccc0706a2c70411596d7d6bf535530643548b45ca3647b9763e75c289
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e4844fa7069d23b72d084a398a1d9895e1ce34c8a2a888508d9b83aefefa36cf4c56d681a6b6ffdd5f5891f7223128f5806e73fdb94624228399726d085a9253
|
7
|
+
data.tar.gz: 47bf20454de4e0b2c4ad8386ac6a4f81d5d792c3ee7ff0b73b2b2fe1cba700a3cd93f65edce4ecf082f3ea2d0954aeada3a685213005de3e49bf95dc9920736c
|
data/lib/dita-topic.rb
ADDED
@@ -0,0 +1,704 @@
|
|
1
|
+
# A custom AsciiDoc converter that generates individual DITA topics
|
2
|
+
# Copyright (C) 2024 Jaromir Hradilek
|
3
|
+
|
4
|
+
# MIT License
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the "Soft-
|
8
|
+
# ware"), to deal in the Software without restriction, including without
|
9
|
+
# limitation the rights to use, copy, modify, merge, publish, distribute,
|
10
|
+
# sublicense, and/or sell copies of the Software, and to permit persons to
|
11
|
+
# whom the Software is furnished to do so, subject to the following condi-
|
12
|
+
# tions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included
|
15
|
+
# in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
18
|
+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABI-
|
19
|
+
# LITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
20
|
+
# SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
21
|
+
# OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
22
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
23
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
# frozen_string_literal: true
|
26
|
+
|
27
|
+
module Asciidoctor
|
28
|
+
class DitaConverter < Asciidoctor::Converter::Base
|
29
|
+
NAME = 'dita-topic'
|
30
|
+
register_for NAME
|
31
|
+
|
32
|
+
def initialize *args
|
33
|
+
super
|
34
|
+
outfilesuffix '.dita'
|
35
|
+
end
|
36
|
+
|
37
|
+
def convert_document node
|
38
|
+
# Check if the modular documentation content type is specified:
|
39
|
+
content_type = (node.attr? '_mod-docs-content-type') ? %( outputclass="#{(node.attr '_mod-docs-content-type').downcase}") : ''
|
40
|
+
|
41
|
+
# Return the XML output:
|
42
|
+
<<~EOF.chomp
|
43
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
44
|
+
<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
|
45
|
+
<topic#{compose_id (node.id or node.attributes['docname'])}#{content_type}>
|
46
|
+
<title>#{node.doctitle}</title>
|
47
|
+
<body>
|
48
|
+
#{node.content}
|
49
|
+
</body>
|
50
|
+
</topic>
|
51
|
+
EOF
|
52
|
+
end
|
53
|
+
|
54
|
+
def convert_admonition node
|
55
|
+
# NOTE: Unlike admonitions in AsciiDoc, the <note> element in DITA
|
56
|
+
# cannot have its own <title>. Admonition titles are therefore not
|
57
|
+
# preserved.
|
58
|
+
|
59
|
+
# Issue a warning if the admonition has a title:
|
60
|
+
if node.title?
|
61
|
+
logger.warn "#{NAME}: Admonition title not supported in DITA: #{node.title}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return the XML output:
|
65
|
+
<<~EOF.chomp
|
66
|
+
<note type="#{node.attr 'name'}">
|
67
|
+
#{node.content}
|
68
|
+
</note>
|
69
|
+
EOF
|
70
|
+
end
|
71
|
+
|
72
|
+
def convert_audio node
|
73
|
+
# Issue a warning if audio content is present:
|
74
|
+
logger.warn "#{NAME}: Audio macro not supported"
|
75
|
+
return ''
|
76
|
+
end
|
77
|
+
|
78
|
+
# FIXME: Figure out how to handle this along with convert_inline_callout.
|
79
|
+
# A definition list looks like a reasonable option.
|
80
|
+
def convert_colist node
|
81
|
+
# Issue a warning if a callout list is present:
|
82
|
+
logger.warn "#{NAME}: Callout list support not implemented"
|
83
|
+
return ''
|
84
|
+
end
|
85
|
+
|
86
|
+
# FIXME: Add support for a title.
|
87
|
+
def convert_dlist node
|
88
|
+
# Check if a different list style is set:
|
89
|
+
return compose_horizontal_dlist node if node.style == 'horizontal'
|
90
|
+
return compose_qanda_dlist node if node.style == 'qanda'
|
91
|
+
|
92
|
+
# Open the definition list:
|
93
|
+
result = ['<dl>']
|
94
|
+
|
95
|
+
# Process individual list items:
|
96
|
+
node.items.each do |terms, description|
|
97
|
+
# Open the definition entry:
|
98
|
+
result << %(<dlentry>)
|
99
|
+
|
100
|
+
# Process individual terms:
|
101
|
+
terms.each do |item|
|
102
|
+
result << %(<dt>#{item.text}</dt>)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Check if the term description is specified:
|
106
|
+
if description
|
107
|
+
# Check if the description contains multiple block elements:
|
108
|
+
if description.blocks?
|
109
|
+
result << %(<dd>)
|
110
|
+
result << %(<p>#{description.text}</p>) if description.text?
|
111
|
+
result << description.content
|
112
|
+
result << %(</dd>)
|
113
|
+
else
|
114
|
+
result << %(<dd>#{description.text}</dd>)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Close the definition entry:
|
119
|
+
result << %(</dlentry>)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Close the definition list:
|
123
|
+
result << '</dl>'
|
124
|
+
|
125
|
+
# Return the XML output:
|
126
|
+
result.join LF
|
127
|
+
end
|
128
|
+
|
129
|
+
def convert_example node
|
130
|
+
<<~EOF.chomp
|
131
|
+
<example#{compose_id node.id}>
|
132
|
+
#{compose_title node.title}#{node.content}
|
133
|
+
</example>
|
134
|
+
EOF
|
135
|
+
end
|
136
|
+
|
137
|
+
def convert_floating_title node
|
138
|
+
compose_floating_title node.title, node.level
|
139
|
+
end
|
140
|
+
|
141
|
+
# FIXME: Add support for additional attributes.
|
142
|
+
def convert_image node
|
143
|
+
# Check if the image has a title specified:
|
144
|
+
if node.title?
|
145
|
+
<<~EOF.chomp
|
146
|
+
<fig>
|
147
|
+
<title>#{node.title}</title>
|
148
|
+
<image href="#{node.image_uri(node.attr 'target')}" placement="break">
|
149
|
+
<alt>#{node.alt}</alt>
|
150
|
+
</image>
|
151
|
+
</fig>
|
152
|
+
EOF
|
153
|
+
else
|
154
|
+
<<~EOF.chomp
|
155
|
+
<image href="#{node.image_uri(node.attr 'target')}" placement="break">
|
156
|
+
<alt>#{node.alt}</alt>
|
157
|
+
</image>
|
158
|
+
EOF
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def convert_inline_anchor node
|
163
|
+
# Determine the type of the anchor:
|
164
|
+
case node.type
|
165
|
+
when :link
|
166
|
+
# Compose an external link:
|
167
|
+
%(<xref href="#{node.target}" scope="external">#{node.text}</xref>)
|
168
|
+
when :xref
|
169
|
+
# NOTE: While AsciiDoc is happy to reference an ID that is not
|
170
|
+
# defined in the same AsciiDoc file, DITA requires the topic ID as
|
171
|
+
# part of the reference. As this script does not have direct access
|
172
|
+
# to the topic IDs of external files and to avoid performance issues
|
173
|
+
# I do not want to process them from this script, I choose to issue a
|
174
|
+
# warning so that the user can resolve the problem.
|
175
|
+
|
176
|
+
# Determine whether the cross reference links to a file path or an ID:
|
177
|
+
if (path = node.attributes['path'])
|
178
|
+
# Issue a warning if the cross reference includes an ID:
|
179
|
+
logger.warn "#{NAME}: Possible invalid reference: #{node.target}" if node.target.include? '#'
|
180
|
+
|
181
|
+
# Compose a cross reference:
|
182
|
+
%(<xref href="#{node.target}">#{node.text || path}</xref>)
|
183
|
+
else
|
184
|
+
# Issue a warning as the cross reference is unlikely to work:
|
185
|
+
logger.warn "#{NAME}: Possible invalid reference: #{node.target}"
|
186
|
+
|
187
|
+
# Compose the cross reference:
|
188
|
+
node.text ? %(<xref href="#{node.target}">#{node.text}</xref>) : %(<xref href="#{node.target}" />)
|
189
|
+
end
|
190
|
+
when :ref
|
191
|
+
# NOTE: DITA does not have a dedicated element for inline anchors or
|
192
|
+
# a direct equivalent of the <span> element from HTML. The solution
|
193
|
+
# below is the least invasive way I could find to achieve the
|
194
|
+
# equivalent behavior.
|
195
|
+
|
196
|
+
# Compose an inline anchor:
|
197
|
+
%(<i id="#{node.id}" />)
|
198
|
+
when :bibref
|
199
|
+
# NOTE: DITA does not have a dedicated element for inline anchors or
|
200
|
+
# a direct equivalent of the <span> element from HTML. The solution
|
201
|
+
# below is the least invasive way I could find to achieve the
|
202
|
+
# equivalent behavior.
|
203
|
+
|
204
|
+
# Compose a bibliographic reference:
|
205
|
+
%(<i id="#{node.id}" />[#{node.reftext || node.id}])
|
206
|
+
else
|
207
|
+
# Issue a warning if an unknown anchor type is present:
|
208
|
+
logger.warn "#{NAME}: Unknown anchor type: #{node.type}"
|
209
|
+
''
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def convert_inline_break node
|
214
|
+
# NOTE: Unlike AsciiDoc, DITA does not support inline line breaks.
|
215
|
+
|
216
|
+
# Issue a warning if an inline line break is present:
|
217
|
+
logger.warn "#{NAME}: Inline breaks not supported in DITA"
|
218
|
+
|
219
|
+
# Return the XML output:
|
220
|
+
%(#{node.text}<!-- break -->)
|
221
|
+
end
|
222
|
+
|
223
|
+
def convert_inline_button node
|
224
|
+
%(<uicontrol outputclass="button">#{node.text}</uicontrol>)
|
225
|
+
end
|
226
|
+
|
227
|
+
def convert_inline_callout node
|
228
|
+
# Issue a warning if an inline callout is present:
|
229
|
+
logger.warn "#{NAME}: Inline callout support not implemented"
|
230
|
+
return ''
|
231
|
+
end
|
232
|
+
|
233
|
+
# FIXME: Add support for footnoteref equivalent.
|
234
|
+
def convert_inline_footnote node
|
235
|
+
%(<fn>#{node.text}</fn>)
|
236
|
+
end
|
237
|
+
|
238
|
+
# FIXME: Add support for additional attributes.
|
239
|
+
def convert_inline_image node
|
240
|
+
%(<image href="#{node.image_uri node.target}" placement="inline"><alt>#{node.alt}</alt></image>)
|
241
|
+
end
|
242
|
+
|
243
|
+
def convert_inline_indexterm node
|
244
|
+
# Issue a warning if an inline index term is present:
|
245
|
+
logger.warn "#{NAME}: Inline index terms not implemented"
|
246
|
+
return ''
|
247
|
+
end
|
248
|
+
|
249
|
+
# FIXME: Investigate if there is an equivalent of <span> in DITA that
|
250
|
+
# would group individual <uicontrol> elements together.
|
251
|
+
def convert_inline_kbd node
|
252
|
+
# Check if there is more than one key:
|
253
|
+
if (keys = node.attr 'keys').size == 1
|
254
|
+
%(<uicontrol outputclass="key">#{keys[0]}</uicontrol>)
|
255
|
+
else
|
256
|
+
%(<uicontrol outputclass="key">#{keys.join '</uicontrol>+<uicontrol outputclass="key">'}</uicontrol>)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def convert_inline_menu node
|
261
|
+
# Compose the markup for the menu:
|
262
|
+
menu = %(<uicontrol>#{node.attr 'menu'}</uicontrol>)
|
263
|
+
|
264
|
+
# Compose the markup for possible submenus:
|
265
|
+
submenus = (not (node.attr 'submenus').empty?) ? %(<uicontrol>#{(node.attr 'submenus').join '</uicontrol><uicontrol>'}</uicontrol>) : ''
|
266
|
+
|
267
|
+
# Compose the markup for the menu item:
|
268
|
+
menuitem = (node.attr 'menuitem') ? %(<uicontrol>#{node.attr 'menuitem'}</uicontrol>) : ''
|
269
|
+
|
270
|
+
# Return the XML output:
|
271
|
+
%(<menucascade>#{menu}#{submenus}#{menuitem}</menucascade>)
|
272
|
+
end
|
273
|
+
|
274
|
+
def convert_inline_quoted node
|
275
|
+
# Determine the inline markup type:
|
276
|
+
case node.type
|
277
|
+
when :emphasis
|
278
|
+
%(<i>#{node.text}</i>)
|
279
|
+
when :strong
|
280
|
+
%(<b>#{node.text}</b>)
|
281
|
+
when :monospaced
|
282
|
+
%(<tt>#{node.text}</tt>)
|
283
|
+
when :superscript
|
284
|
+
%(<sup>#{node.text}</sup>)
|
285
|
+
when :subscript
|
286
|
+
%(<sub>#{node.text}</sub>)
|
287
|
+
when :double
|
288
|
+
%(“#{node.text}”)
|
289
|
+
when :single
|
290
|
+
%(‘#{node.text}’)
|
291
|
+
else
|
292
|
+
node.text
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def convert_listing node
|
297
|
+
# Check the listing style:
|
298
|
+
if node.style == 'source'
|
299
|
+
# Check whether the source language is defined:
|
300
|
+
language = (node.attributes.key? 'language') ? %( outputclass="language-#{node.attributes['language']}") : ''
|
301
|
+
|
302
|
+
# Return the XML output:
|
303
|
+
<<~EOF.chomp
|
304
|
+
<codeblock#{language}>
|
305
|
+
#{node.content}
|
306
|
+
</codeblock>
|
307
|
+
EOF
|
308
|
+
else
|
309
|
+
# Return the XML output:
|
310
|
+
<<~EOF.chomp
|
311
|
+
<screen>
|
312
|
+
#{node.content}
|
313
|
+
</screen>
|
314
|
+
EOF
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def convert_literal node
|
319
|
+
<<~EOF.chomp
|
320
|
+
<pre>
|
321
|
+
#{node.content}
|
322
|
+
</pre>
|
323
|
+
EOF
|
324
|
+
end
|
325
|
+
|
326
|
+
# FIXME: Add support for titles.
|
327
|
+
def convert_olist node
|
328
|
+
# Open the ordered list:
|
329
|
+
result = ['<ol>']
|
330
|
+
|
331
|
+
# Process individual list items:
|
332
|
+
node.items.each do |item|
|
333
|
+
# Check if the list item contains multiple block elements:
|
334
|
+
if item.blocks?
|
335
|
+
result << %(<li>)
|
336
|
+
result << %(<p>#{item.text}</p>)
|
337
|
+
result << item.content
|
338
|
+
result << %(</li>)
|
339
|
+
else
|
340
|
+
result << %(<li>#{item.text}</li>)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
# Close the ordered list:
|
345
|
+
result << '</ol>'
|
346
|
+
|
347
|
+
# Return the XML output:
|
348
|
+
result.join LF
|
349
|
+
end
|
350
|
+
|
351
|
+
# FIXME: This is not the top priority.
|
352
|
+
def convert_open node
|
353
|
+
''
|
354
|
+
end
|
355
|
+
|
356
|
+
def convert_page_break node
|
357
|
+
# NOTE: Unlike AsciiDoc, DITA does not support page breaks.
|
358
|
+
|
359
|
+
# Issue a warning if a page break is present:
|
360
|
+
logger.warn "#{NAME}: Page breaks not supported in DITA"
|
361
|
+
|
362
|
+
# Return the XML output:
|
363
|
+
%(<p outputclass="page-break"></p>)
|
364
|
+
end
|
365
|
+
|
366
|
+
def convert_paragraph node
|
367
|
+
# Check if the paragraph has a title assigned:
|
368
|
+
if node.title?
|
369
|
+
<<~EOF.chomp
|
370
|
+
<div outputclass="paragraph">
|
371
|
+
#{compose_floating_title node.title}<p>#{node.content}</p>
|
372
|
+
</div>
|
373
|
+
EOF
|
374
|
+
else
|
375
|
+
%(<p>#{node.content}</p>)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def convert_preamble node
|
380
|
+
node.content
|
381
|
+
end
|
382
|
+
|
383
|
+
def convert_quote node
|
384
|
+
# Check if the author is defined:
|
385
|
+
author = (node.attr? 'attribution') ? %(\n<p>— #{node.attr 'attribution'}</p>) : ''
|
386
|
+
|
387
|
+
# Check if the citation source is defined:
|
388
|
+
source = (node.attr? 'citetitle') ? %(\n<cite>#{node.attr 'citetitle'}</cite>) : ''
|
389
|
+
|
390
|
+
# Check if the content contains multiple block elements:
|
391
|
+
if node.content_model == :compound
|
392
|
+
<<~EOF.chomp
|
393
|
+
<lq>
|
394
|
+
#{compose_floating_title node.title}#{node.content}#{author}#{source}
|
395
|
+
</lq>
|
396
|
+
EOF
|
397
|
+
else
|
398
|
+
<<~EOF.chomp
|
399
|
+
<lq>
|
400
|
+
#{compose_floating_title node.title}<p>#{node.content}</p>#{author}#{source}
|
401
|
+
</lq>
|
402
|
+
EOF
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def convert_section node
|
407
|
+
# NOTE: Unlike sections in AsciiDoc, the <section> element in DITA
|
408
|
+
# cannot be nested. Consequently, converting AsciiDoc files that do
|
409
|
+
# contain nested subsections will result in invalid markup.
|
410
|
+
#
|
411
|
+
# I explored the possibility to use the <topic> element instead as it
|
412
|
+
# can be nested, but that presents a problem with closing the <body>
|
413
|
+
# element of the parent <topic>. As only a very small number of
|
414
|
+
# AsciiDoc modules contain nested subsections, I chose the simple
|
415
|
+
# markup.
|
416
|
+
|
417
|
+
# Issue a warning if there are nested sections:
|
418
|
+
logger.warn "#{NAME}: Nesting of sections not supported in DITA" if node.level > 1
|
419
|
+
|
420
|
+
# Return the XML output:
|
421
|
+
<<~EOF.chomp
|
422
|
+
<section#{compose_id node.id}>
|
423
|
+
<title>#{node.title}</title>
|
424
|
+
#{node.content}
|
425
|
+
</section>
|
426
|
+
EOF
|
427
|
+
end
|
428
|
+
|
429
|
+
def convert_sidebar node
|
430
|
+
# NOTE: Unlike AsciiDoc, DITA does not provide markup for a sidebar. As
|
431
|
+
# a workaround, I decided to use a div with the outputclass attribute.
|
432
|
+
|
433
|
+
# Check if the content contains multiple block elements:
|
434
|
+
if node.content_model == :compound
|
435
|
+
<<~EOF.chomp
|
436
|
+
<div outputclass="sidebar">
|
437
|
+
#{compose_floating_title node.title}#{node.content}
|
438
|
+
</div>
|
439
|
+
EOF
|
440
|
+
else
|
441
|
+
<<~EOF.chomp
|
442
|
+
<div outputclass="sidebar">
|
443
|
+
#{compose_floating_title node.title}<p>#{node.content}</p>
|
444
|
+
</div>
|
445
|
+
EOF
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
def convert_stem node
|
450
|
+
# Issue a warning if a STEM content is present:
|
451
|
+
logger.warn "#{NAME}: STEM support not implemented"
|
452
|
+
return ''
|
453
|
+
end
|
454
|
+
|
455
|
+
def convert_table node
|
456
|
+
# Open the table:
|
457
|
+
result = ['<table>']
|
458
|
+
|
459
|
+
# Check if the title is specified:
|
460
|
+
result << %(<title>#{node.title}</title>) if node.title?
|
461
|
+
|
462
|
+
# Define the table properties and open the tgroup:
|
463
|
+
result << %(<tgroup cols="#{node.attr 'colcount'}">)
|
464
|
+
|
465
|
+
# Define column properties:
|
466
|
+
node.columns.each do |column|
|
467
|
+
result << %(<colspec colname="col_#{column.attr 'colnumber'}" colwidth="#{column.attr ((node.attr? 'width') ? 'colabswidth' : 'colpcwidth')}*"/>)
|
468
|
+
end
|
469
|
+
|
470
|
+
# Process each table section (header, body, and footer):
|
471
|
+
node.rows.to_h.each do |type, rows|
|
472
|
+
# Skip empty sections:
|
473
|
+
next if rows.empty?
|
474
|
+
|
475
|
+
# Issue a warning if a table footer is present:
|
476
|
+
if type == :foot
|
477
|
+
logger.warn "#{NAME}: Table footers not supported in DITA"
|
478
|
+
next
|
479
|
+
end
|
480
|
+
|
481
|
+
# Open the section:
|
482
|
+
result << %(<t#{type}>)
|
483
|
+
|
484
|
+
# Process each row:
|
485
|
+
rows.each do |row|
|
486
|
+
# Open the row:
|
487
|
+
result <<%(<row>)
|
488
|
+
|
489
|
+
# Process each cell:
|
490
|
+
row.each do |cell|
|
491
|
+
# Check if the cell spans multiple columns:
|
492
|
+
colspan = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{column + cell.colspan - 1}") : ''
|
493
|
+
|
494
|
+
# Check if the cell spans multiple rows:
|
495
|
+
rowspan = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
|
496
|
+
|
497
|
+
# Compose the entry tag:
|
498
|
+
entry_tag = %(entry#{colspan}#{rowspan})
|
499
|
+
|
500
|
+
# Determine the formatting of the entry:
|
501
|
+
if type == :head
|
502
|
+
result << %(<#{entry_tag}>#{cell.text}</entry>)
|
503
|
+
next
|
504
|
+
end
|
505
|
+
case cell.style
|
506
|
+
when :asciidoc
|
507
|
+
result << %(<#{entry_tag}>#{cell.content}</entry>)
|
508
|
+
when :literal
|
509
|
+
result << %(<#{entry_tag}><pre>#{cell.text}</pre></entry>)
|
510
|
+
else
|
511
|
+
result << %(<#{entry_tag}>)
|
512
|
+
cell.content.each do |line|
|
513
|
+
result << %(<p>#{line}</p>)
|
514
|
+
end
|
515
|
+
result << %(</entry>)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
# Close the row:
|
520
|
+
result <<%(</row>)
|
521
|
+
end
|
522
|
+
|
523
|
+
# Close the section:
|
524
|
+
result << %(</t#{type}>)
|
525
|
+
end
|
526
|
+
|
527
|
+
# Close the table:
|
528
|
+
result << %(</tgroup>)
|
529
|
+
result << %(</table>)
|
530
|
+
|
531
|
+
# Return the XML output:
|
532
|
+
result.join LF
|
533
|
+
end
|
534
|
+
|
535
|
+
def convert_thematic_break node
|
536
|
+
# NOTE: Unlike AsciiDoc, DITA does not support thematic breaks.
|
537
|
+
|
538
|
+
# Issue a warning if a thematic break is present:
|
539
|
+
logger.warn "#{NAME}: Thematic breaks not supported in DITA"
|
540
|
+
|
541
|
+
# Return the XML output:
|
542
|
+
%(<p outputclass="thematic-break"></p>)
|
543
|
+
end
|
544
|
+
|
545
|
+
# FIXME: Add support for titles.
|
546
|
+
def convert_ulist node
|
547
|
+
# Open the unordered list:
|
548
|
+
result = ['<ul>']
|
549
|
+
|
550
|
+
# Process individual list items:
|
551
|
+
node.items.each do |item|
|
552
|
+
# Check if the list item is part of a checklist:
|
553
|
+
unless item.attr? 'checkbox'
|
554
|
+
check_box = ''
|
555
|
+
else
|
556
|
+
check_box = (item.attr? 'checked') ? '✓ ' : '❏ '
|
557
|
+
end
|
558
|
+
|
559
|
+
# Check if the list item contains multiple block elements:
|
560
|
+
if item.blocks?
|
561
|
+
result << %(<li>)
|
562
|
+
result << %(<p>#{check_box}#{item.text}</p>)
|
563
|
+
result << item.content
|
564
|
+
result << %(</li>)
|
565
|
+
else
|
566
|
+
result << %(<li>#{check_box}#{item.text}</li>)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
# Close the unordered list:
|
571
|
+
result << '</ul>'
|
572
|
+
|
573
|
+
# Returned the XML output:
|
574
|
+
result.join LF
|
575
|
+
end
|
576
|
+
|
577
|
+
def convert_verse node
|
578
|
+
# Check if the author is defined:
|
579
|
+
author = (node.attr? 'attribution') ? %(\n— #{node.attr 'attribution'}) : ''
|
580
|
+
|
581
|
+
# Check if the citation source is defined:
|
582
|
+
source = (node.attr? 'citetitle') ? %(\n<cite>#{node.attr 'citetitle'}</cite>) : ''
|
583
|
+
|
584
|
+
# Return the XML output:
|
585
|
+
<<~EOF.chomp
|
586
|
+
<lines>
|
587
|
+
#{node.content}#{author}#{source}
|
588
|
+
</lines>
|
589
|
+
EOF
|
590
|
+
end
|
591
|
+
|
592
|
+
def convert_video node
|
593
|
+
# Issue a warning if video content is present:
|
594
|
+
logger.warn "#{NAME}: Video macro not supported"
|
595
|
+
return ''
|
596
|
+
end
|
597
|
+
|
598
|
+
def compose_qanda_dlist node
|
599
|
+
# Open the ordered list:
|
600
|
+
result = ['<ol>']
|
601
|
+
|
602
|
+
# Process individual list items:
|
603
|
+
node.items.each do |terms, description|
|
604
|
+
# Open the list item:
|
605
|
+
result << %(<li>)
|
606
|
+
|
607
|
+
# Process individual terms:
|
608
|
+
terms.each do |item|
|
609
|
+
result << %(<p outputclass="question"><i>#{item.text}</i></p>)
|
610
|
+
end
|
611
|
+
|
612
|
+
# Check if the term description is specified:
|
613
|
+
if description
|
614
|
+
result << %(<p>#{description.text}</p>)
|
615
|
+
result << description.content if description.blocks?
|
616
|
+
end
|
617
|
+
|
618
|
+
# Close the list item:
|
619
|
+
result << %(</li>)
|
620
|
+
end
|
621
|
+
|
622
|
+
# Close the ordered list:
|
623
|
+
result << '</ol>'
|
624
|
+
|
625
|
+
# Return the XML output:
|
626
|
+
result.join LF
|
627
|
+
end
|
628
|
+
|
629
|
+
def compose_horizontal_dlist node
|
630
|
+
# Open the table:
|
631
|
+
result = ['<table>']
|
632
|
+
|
633
|
+
# Define the table properties and open the tgroup:
|
634
|
+
result << %(<tgroup cols="2">)
|
635
|
+
result << %(<colspec colwidth="#{node.attr 'labelwidth', 15}*" />)
|
636
|
+
result << %(<colspec colwidth="#{node.attr 'itemwidth', 85}*" />)
|
637
|
+
|
638
|
+
# Open the table body:
|
639
|
+
result << %(<tbody>)
|
640
|
+
|
641
|
+
# Process individual list items:
|
642
|
+
node.items.each do |terms, description|
|
643
|
+
# Open the table row:
|
644
|
+
result << %(<row>)
|
645
|
+
|
646
|
+
# Check the number of terms to process:
|
647
|
+
if terms.count == 1
|
648
|
+
result << %(<entry><b>#{terms[0].text}</b></entry>)
|
649
|
+
else
|
650
|
+
# Process individual terms:
|
651
|
+
result << %(<entry>)
|
652
|
+
terms.each do |item|
|
653
|
+
result << %(<p><b>#{item.text}</b></p>)
|
654
|
+
end
|
655
|
+
result << %(</entry>)
|
656
|
+
end
|
657
|
+
|
658
|
+
# Check if the term description is specified:
|
659
|
+
if description
|
660
|
+
# Check if the description contains multiple block elements:
|
661
|
+
if description.blocks?
|
662
|
+
result << %(<entry>)
|
663
|
+
result << %(<p>#{description.text}</p>) if description.text?
|
664
|
+
result << description.content
|
665
|
+
result << %(</entry>)
|
666
|
+
else
|
667
|
+
result << %(<entry>#{description.text}</entry>) if description.text?
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
# Close the table row:
|
672
|
+
result << %(</row>)
|
673
|
+
end
|
674
|
+
|
675
|
+
# Close the table:
|
676
|
+
result << %(</tbody>)
|
677
|
+
result << %(</tgroup>)
|
678
|
+
result << %(</table>)
|
679
|
+
|
680
|
+
# Return the XML output:
|
681
|
+
result.join LF
|
682
|
+
end
|
683
|
+
|
684
|
+
def compose_floating_title title, section_level=false
|
685
|
+
# NOTE: Unlike AsciiDoc, DITA does not support floating titles or
|
686
|
+
# titles assigned to certain block elements. As a workaround, I decided
|
687
|
+
# to use a paragraph with the outputclass attribute.
|
688
|
+
|
689
|
+
# Check whether the section level is defined:
|
690
|
+
level = section_level ? %( sect#{section_level}) : ''
|
691
|
+
|
692
|
+
# Return the XML output:
|
693
|
+
title ? %(<p outputclass="title#{level}"><b>#{title}</b></p>\n) : ''
|
694
|
+
end
|
695
|
+
|
696
|
+
def compose_id id
|
697
|
+
id ? %( id="#{id}") : ''
|
698
|
+
end
|
699
|
+
|
700
|
+
def compose_title title
|
701
|
+
title ? %(<title>#{title}</title>\n) : ''
|
702
|
+
end
|
703
|
+
end
|
704
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asciidoctor-dita-topic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jaromir Hradilek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-06-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: asciidoctor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.0
|
33
|
+
description: An extension for AsciiDoctor that converts a single AsciiDoc file to
|
34
|
+
a DITA topic.
|
35
|
+
email: jhradilek@gmail.com
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- lib/dita-topic.rb
|
41
|
+
homepage: https://github.com/jhradilek/asciidoctor-dita-topic
|
42
|
+
licenses:
|
43
|
+
- MIT
|
44
|
+
metadata:
|
45
|
+
homepage_uri: https://github.com/jhradilek/asciidoctor-dita-topic
|
46
|
+
bug_tracker_uri: https://github.com/jhradilek/asciidoctor-dita-topic/issues
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubygems_version: 3.5.9
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: A custom AsciiDoc converter that generates individual DITA topics
|
66
|
+
test_files: []
|