asciidoctor-dita-topic 1.0.1
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 +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: []
|