coradoc-html 1.1.7
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/LICENSE.txt +21 -0
- data/lib/coradoc/html/base.rb +157 -0
- data/lib/coradoc/html/config.rb +467 -0
- data/lib/coradoc/html/converter_base.rb +177 -0
- data/lib/coradoc/html/converters/admonition.rb +180 -0
- data/lib/coradoc/html/converters/attribute.rb +68 -0
- data/lib/coradoc/html/converters/attribute_reference.rb +60 -0
- data/lib/coradoc/html/converters/audio.rb +165 -0
- data/lib/coradoc/html/converters/base.rb +615 -0
- data/lib/coradoc/html/converters/bibliography.rb +82 -0
- data/lib/coradoc/html/converters/bibliography_entry.rb +108 -0
- data/lib/coradoc/html/converters/block_image.rb +72 -0
- data/lib/coradoc/html/converters/bold.rb +34 -0
- data/lib/coradoc/html/converters/break.rb +32 -0
- data/lib/coradoc/html/converters/comment_block.rb +42 -0
- data/lib/coradoc/html/converters/comment_line.rb +54 -0
- data/lib/coradoc/html/converters/cross_reference.rb +59 -0
- data/lib/coradoc/html/converters/document.rb +108 -0
- data/lib/coradoc/html/converters/example.rb +114 -0
- data/lib/coradoc/html/converters/highlight.rb +34 -0
- data/lib/coradoc/html/converters/include.rb +68 -0
- data/lib/coradoc/html/converters/inline_image.rb +41 -0
- data/lib/coradoc/html/converters/italic.rb +34 -0
- data/lib/coradoc/html/converters/line_break.rb +31 -0
- data/lib/coradoc/html/converters/link.rb +46 -0
- data/lib/coradoc/html/converters/list_item.rb +75 -0
- data/lib/coradoc/html/converters/listing.rb +99 -0
- data/lib/coradoc/html/converters/literal.rb +102 -0
- data/lib/coradoc/html/converters/monospace.rb +34 -0
- data/lib/coradoc/html/converters/open.rb +78 -0
- data/lib/coradoc/html/converters/ordered.rb +53 -0
- data/lib/coradoc/html/converters/paragraph.rb +46 -0
- data/lib/coradoc/html/converters/quote.rb +113 -0
- data/lib/coradoc/html/converters/reviewer_comment.rb +74 -0
- data/lib/coradoc/html/converters/reviewer_note.rb +134 -0
- data/lib/coradoc/html/converters/section.rb +90 -0
- data/lib/coradoc/html/converters/sidebar.rb +113 -0
- data/lib/coradoc/html/converters/source.rb +137 -0
- data/lib/coradoc/html/converters/source_code.rb +16 -0
- data/lib/coradoc/html/converters/span.rb +61 -0
- data/lib/coradoc/html/converters/strikethrough.rb +34 -0
- data/lib/coradoc/html/converters/subscript.rb +34 -0
- data/lib/coradoc/html/converters/superscript.rb +34 -0
- data/lib/coradoc/html/converters/table.rb +85 -0
- data/lib/coradoc/html/converters/table_cell.rb +203 -0
- data/lib/coradoc/html/converters/table_row.rb +45 -0
- data/lib/coradoc/html/converters/template_html_converter.rb +105 -0
- data/lib/coradoc/html/converters/term.rb +58 -0
- data/lib/coradoc/html/converters/text_element.rb +44 -0
- data/lib/coradoc/html/converters/underline.rb +34 -0
- data/lib/coradoc/html/converters/unordered.rb +47 -0
- data/lib/coradoc/html/converters/verse.rb +105 -0
- data/lib/coradoc/html/converters/video.rb +179 -0
- data/lib/coradoc/html/element_mapping.rb +210 -0
- data/lib/coradoc/html/entity.rb +137 -0
- data/lib/coradoc/html/input/cleaner.rb +163 -0
- data/lib/coradoc/html/input/config.rb +79 -0
- data/lib/coradoc/html/input/converters/a.rb +90 -0
- data/lib/coradoc/html/input/converters/aside.rb +23 -0
- data/lib/coradoc/html/input/converters/audio.rb +50 -0
- data/lib/coradoc/html/input/converters/base.rb +116 -0
- data/lib/coradoc/html/input/converters/blockquote.rb +25 -0
- data/lib/coradoc/html/input/converters/br.rb +19 -0
- data/lib/coradoc/html/input/converters/bypass.rb +83 -0
- data/lib/coradoc/html/input/converters/code.rb +25 -0
- data/lib/coradoc/html/input/converters/div.rb +25 -0
- data/lib/coradoc/html/input/converters/dl.rb +106 -0
- data/lib/coradoc/html/input/converters/drop.rb +28 -0
- data/lib/coradoc/html/input/converters/em.rb +23 -0
- data/lib/coradoc/html/input/converters/figure.rb +58 -0
- data/lib/coradoc/html/input/converters/h.rb +76 -0
- data/lib/coradoc/html/input/converters/head.rb +30 -0
- data/lib/coradoc/html/input/converters/hr.rb +20 -0
- data/lib/coradoc/html/input/converters/ignore.rb +22 -0
- data/lib/coradoc/html/input/converters/img.rb +110 -0
- data/lib/coradoc/html/input/converters/li.rb +35 -0
- data/lib/coradoc/html/input/converters/mark.rb +21 -0
- data/lib/coradoc/html/input/converters/markup.rb +107 -0
- data/lib/coradoc/html/input/converters/math.rb +46 -0
- data/lib/coradoc/html/input/converters/ol.rb +46 -0
- data/lib/coradoc/html/input/converters/p.rb +81 -0
- data/lib/coradoc/html/input/converters/pass_through.rb +19 -0
- data/lib/coradoc/html/input/converters/pre.rb +59 -0
- data/lib/coradoc/html/input/converters/q.rb +24 -0
- data/lib/coradoc/html/input/converters/strong.rb +22 -0
- data/lib/coradoc/html/input/converters/sub.rb +40 -0
- data/lib/coradoc/html/input/converters/sup.rb +40 -0
- data/lib/coradoc/html/input/converters/table.rb +64 -0
- data/lib/coradoc/html/input/converters/td.rb +70 -0
- data/lib/coradoc/html/input/converters/text.rb +67 -0
- data/lib/coradoc/html/input/converters/th.rb +20 -0
- data/lib/coradoc/html/input/converters/tr.rb +28 -0
- data/lib/coradoc/html/input/converters/video.rb +53 -0
- data/lib/coradoc/html/input/converters.rb +122 -0
- data/lib/coradoc/html/input/errors.rb +22 -0
- data/lib/coradoc/html/input/html_converter.rb +170 -0
- data/lib/coradoc/html/input/plugin.rb +169 -0
- data/lib/coradoc/html/input/plugins/plateau.rb +229 -0
- data/lib/coradoc/html/input/postprocessor.rb +31 -0
- data/lib/coradoc/html/input.rb +68 -0
- data/lib/coradoc/html/output.rb +95 -0
- data/lib/coradoc/html/renderer.rb +409 -0
- data/lib/coradoc/html/spa.rb +309 -0
- data/lib/coradoc/html/static.rb +293 -0
- data/lib/coradoc/html/template_config.rb +151 -0
- data/lib/coradoc/html/template_helpers.rb +58 -0
- data/lib/coradoc/html/template_locator.rb +114 -0
- data/lib/coradoc/html/theme/base.rb +231 -0
- data/lib/coradoc/html/theme/classic_renderer.rb +390 -0
- data/lib/coradoc/html/theme/modern/components/ui_components.rb +344 -0
- data/lib/coradoc/html/theme/modern/css_generator.rb +311 -0
- data/lib/coradoc/html/theme/modern/javascript_generator.rb +314 -0
- data/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +382 -0
- data/lib/coradoc/html/theme/modern/tailwind_config_builder.rb +164 -0
- data/lib/coradoc/html/theme/modern/vue_template_generator.rb +374 -0
- data/lib/coradoc/html/theme/modern_renderer.rb +250 -0
- data/lib/coradoc/html/theme/registry.rb +153 -0
- data/lib/coradoc/html/theme.rb +13 -0
- data/lib/coradoc/html/transform/from_core_model.rb +32 -0
- data/lib/coradoc/html/transform/to_core_model.rb +39 -0
- data/lib/coradoc/html/version.rb +7 -0
- data/lib/coradoc/html.rb +255 -0
- metadata +264 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Hr < Base
|
|
8
|
+
def to_coradoc(_node, _state = {})
|
|
9
|
+
Coradoc::CoreModel::Block.new(
|
|
10
|
+
element_type: 'thematic_break',
|
|
11
|
+
block_semantic_type: :horizontal_rule
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
register :hr, Hr.new
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Ignore < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
convert(node, state)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def convert(_node, _state = {})
|
|
13
|
+
'' # noop
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
register :colgroup, Ignore.new
|
|
18
|
+
register :col, Ignore.new
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'tempfile'
|
|
6
|
+
require 'base64'
|
|
7
|
+
require 'marcel'
|
|
8
|
+
|
|
9
|
+
module Coradoc
|
|
10
|
+
module Input
|
|
11
|
+
module Html
|
|
12
|
+
module Converters
|
|
13
|
+
class Img < Base
|
|
14
|
+
def image_number
|
|
15
|
+
format(
|
|
16
|
+
Coradoc::Html::Input.config.image_counter_pattern,
|
|
17
|
+
Coradoc::Html::Input.config.image_counter
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def image_number_increment
|
|
22
|
+
Coradoc::Html::Input.config.image_counter += 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def datauri2file(src)
|
|
26
|
+
return unless src
|
|
27
|
+
|
|
28
|
+
%r{^data:image/(?:[^;]+);base64,(?<imgdata>.+)$} =~ src
|
|
29
|
+
|
|
30
|
+
dest_dir = Pathname.new(Coradoc::Html::Input.config.destination).dirname
|
|
31
|
+
images_dir = dest_dir.join('images')
|
|
32
|
+
FileUtils.mkdir_p(images_dir)
|
|
33
|
+
|
|
34
|
+
ext, image_src_path, tempfile = determine_image_src_path(
|
|
35
|
+
src,
|
|
36
|
+
imgdata
|
|
37
|
+
)
|
|
38
|
+
image_dest_path = images_dir + "#{image_number}.#{ext}"
|
|
39
|
+
|
|
40
|
+
# puts "image_dest_path: #{image_dest_path.to_s}"
|
|
41
|
+
# puts "image_src_path: #{image_src_path.to_s}"
|
|
42
|
+
|
|
43
|
+
if File.exist?(image_src_path)
|
|
44
|
+
FileUtils.cp(image_src_path, image_dest_path)
|
|
45
|
+
else
|
|
46
|
+
@annotate_missing = image_src_path
|
|
47
|
+
Kernel.warn "Image #{image_src_path} does not exist"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
image_number_increment
|
|
51
|
+
|
|
52
|
+
image_dest_path.relative_path_from(dest_dir)
|
|
53
|
+
ensure
|
|
54
|
+
tempfile&.close!
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def determine_image_src_path(src, imgdata)
|
|
58
|
+
return copy_temp_file(imgdata) if imgdata
|
|
59
|
+
|
|
60
|
+
ext = File.extname(src).strip.downcase[1..]
|
|
61
|
+
[ext, Pathname.new(Coradoc::Html::Input.config.sourcedir).join(src)]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def copy_temp_file(imgdata)
|
|
65
|
+
f = Tempfile.open(['radoc', '.jpg'])
|
|
66
|
+
f.binmode
|
|
67
|
+
f.write(Base64.strict_decode64(imgdata))
|
|
68
|
+
f.rewind
|
|
69
|
+
ext = Marcel::MimeType.for(f).sub(%r{^[^/]+/}, '')
|
|
70
|
+
ext = 'svg' if ext == 'svg+xml'
|
|
71
|
+
[ext, f.path, f]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_coradoc(node, _state = {})
|
|
75
|
+
id = node['id']
|
|
76
|
+
alt = node['alt']
|
|
77
|
+
src = node['src']
|
|
78
|
+
width = node['width']
|
|
79
|
+
height = node['height']
|
|
80
|
+
|
|
81
|
+
# Convert width/height to integers if they are numeric strings
|
|
82
|
+
width = width.to_i if width&.match?(/\A\d+\z/)
|
|
83
|
+
height = height.to_i if height&.match?(/\A\d+\z/)
|
|
84
|
+
|
|
85
|
+
title = extract_title(node)
|
|
86
|
+
|
|
87
|
+
if Coradoc::Html::Input.config.external_images
|
|
88
|
+
# puts "external image conversion #{id}, #{src}"
|
|
89
|
+
src = datauri2file(src)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Use CoreModel::Image
|
|
93
|
+
return unless src
|
|
94
|
+
|
|
95
|
+
Coradoc::CoreModel::Image.new(
|
|
96
|
+
src: src,
|
|
97
|
+
alt: alt,
|
|
98
|
+
caption: title,
|
|
99
|
+
width: width&.to_s,
|
|
100
|
+
height: height&.to_s,
|
|
101
|
+
id: id
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
register :img, Img
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Li < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
id = node['id']
|
|
10
|
+
|
|
11
|
+
# Check if all children are <p> tags
|
|
12
|
+
p_children = node.children.select { |child| child.name == 'p' }
|
|
13
|
+
non_empty_children = node.children.reject { |c| c.text? && c.text.strip.empty? }
|
|
14
|
+
|
|
15
|
+
content = if p_children.any? && p_children.size == non_empty_children.size && p_children.size == 1
|
|
16
|
+
# Single <p> tag - extract its content directly as inline content
|
|
17
|
+
treat_children_coradoc(p_children.first, state)
|
|
18
|
+
else
|
|
19
|
+
treat_children_coradoc(node, state)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Use CoreModel::ListItem with children for mixed content
|
|
23
|
+
# content can be an array of inline elements or a single string
|
|
24
|
+
Coradoc::CoreModel::ListItem.new(
|
|
25
|
+
children: content,
|
|
26
|
+
id: id
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
register :li, Li.new
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Mark < Markup
|
|
8
|
+
def coradoc_format_type
|
|
9
|
+
'highlight'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def markup_ancestor_tag_names
|
|
13
|
+
%w[mark]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
register :mark, Mark.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Markup < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
u_before = unconstrained_before?(node)
|
|
10
|
+
u_after = unconstrained_after?(node)
|
|
11
|
+
|
|
12
|
+
leading_ws, trailing_ws =
|
|
13
|
+
extract_leading_trailing_whitespace(node)
|
|
14
|
+
|
|
15
|
+
# Wrap whitespace in InlineElement so it can be processed
|
|
16
|
+
leading_whitespace = if leading_ws
|
|
17
|
+
Coradoc::CoreModel::InlineElement.new(
|
|
18
|
+
format_type: 'text',
|
|
19
|
+
content: leading_ws
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
trailing_whitespace = if trailing_ws
|
|
23
|
+
Coradoc::CoreModel::InlineElement.new(
|
|
24
|
+
format_type: 'text',
|
|
25
|
+
content: trailing_ws
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
content = treat_children_coradoc(node, state)
|
|
30
|
+
|
|
31
|
+
if node_has_ancestor?(node, markup_ancestor_tag_names)
|
|
32
|
+
content
|
|
33
|
+
elsif node.children.empty?
|
|
34
|
+
# Return InlineElement wrapper for whitespace
|
|
35
|
+
if leading_ws
|
|
36
|
+
Coradoc::CoreModel::InlineElement.new(
|
|
37
|
+
format_type: 'text',
|
|
38
|
+
content: leading_ws
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
u = (u_before && leading_whitespace.nil?) ||
|
|
43
|
+
(u_after && trailing_whitespace.nil?)
|
|
44
|
+
|
|
45
|
+
# Separate text strings from InlineElements in content array
|
|
46
|
+
text_content, nested = extract_text_and_elements(content)
|
|
47
|
+
|
|
48
|
+
# Create CoreModel::InlineElement with the appropriate format type
|
|
49
|
+
inline_element = Coradoc::CoreModel::InlineElement.new(
|
|
50
|
+
format_type: coradoc_format_type,
|
|
51
|
+
content: text_content,
|
|
52
|
+
nested_elements: nested.empty? ? nil : nested,
|
|
53
|
+
metadata: { unconstrained: u }
|
|
54
|
+
)
|
|
55
|
+
result = [leading_whitespace, inline_element, trailing_whitespace].compact
|
|
56
|
+
result.length == 1 ? result.first : result
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Extract text content and InlineElements from mixed content array
|
|
61
|
+
def extract_text_and_elements(content)
|
|
62
|
+
return [content, []] unless content.is_a?(Array)
|
|
63
|
+
|
|
64
|
+
text_parts = []
|
|
65
|
+
elements = []
|
|
66
|
+
|
|
67
|
+
content.each do |item|
|
|
68
|
+
case item
|
|
69
|
+
when String
|
|
70
|
+
text_parts << item
|
|
71
|
+
when Coradoc::CoreModel::InlineElement
|
|
72
|
+
elements << item
|
|
73
|
+
when Coradoc::CoreModel::Base
|
|
74
|
+
# For other block types, convert to text
|
|
75
|
+
text_parts << extract_text_from_model(item)
|
|
76
|
+
else
|
|
77
|
+
text_parts << item.to_s
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
[text_parts.join, elements]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Extract text from a CoreModel object
|
|
85
|
+
def extract_text_from_model(model)
|
|
86
|
+
return '' if model.nil?
|
|
87
|
+
|
|
88
|
+
if model.is_a?(Coradoc::CoreModel::Base) && model.content.is_a?(String)
|
|
89
|
+
model.content
|
|
90
|
+
elsif model.is_a?(Coradoc::CoreModel::StructuralElement) && model.children.is_a?(Array)
|
|
91
|
+
model.children.map { |c| extract_text_from_model(c) }.join
|
|
92
|
+
elsif model.is_a?(Coradoc::CoreModel::Base) && model.title.is_a?(String)
|
|
93
|
+
model.title
|
|
94
|
+
else
|
|
95
|
+
model.to_s
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Subclasses should override this to return the format type
|
|
100
|
+
def coradoc_format_type
|
|
101
|
+
'text'
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Unless run with Coradoc::Input::HTML.config.mathml2asciimath,
|
|
4
|
+
# this is cheating: we're injecting MathML into Asciidoctor, but
|
|
5
|
+
# Asciidoctor only understands AsciiMath or LaTeX
|
|
6
|
+
|
|
7
|
+
module Coradoc
|
|
8
|
+
module Input
|
|
9
|
+
module Html
|
|
10
|
+
module Converters
|
|
11
|
+
class Math < Base
|
|
12
|
+
# FIXIT
|
|
13
|
+
def to_coradoc(node, state = {})
|
|
14
|
+
convert(node, state)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def convert(node, _state = {})
|
|
18
|
+
stem = node.to_s.tr("\n", ' ')
|
|
19
|
+
if Coradoc::Html::Input.config.mathml2asciimath
|
|
20
|
+
require 'plurimath'
|
|
21
|
+
stem = Plurimath::Math.parse(stem, :mathml).to_asciimath
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
unless stem.nil?
|
|
25
|
+
stem = stem.gsub('[', '\\[')
|
|
26
|
+
stem = stem.gsub(']', '\\]')
|
|
27
|
+
# Handle ((...)) patterns - iterate to avoid polynomial regex
|
|
28
|
+
loop do
|
|
29
|
+
new_stem = stem.gsub(/\(\(([^)]{1,100})\)\)/, '(\\1)')
|
|
30
|
+
break if new_stem == stem
|
|
31
|
+
|
|
32
|
+
stem = new_stem
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# NOTE: MathML/LaTeX conversion to AsciiDoc stem format
|
|
37
|
+
# This converts HTML math elements to AsciiDoc's stem:[] macro format
|
|
38
|
+
' stem:[' << stem << '] '
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
register :math, Math.new
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Ol < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
id = node['id']
|
|
10
|
+
ol_count = state.fetch(:ol_count, 0) + 1
|
|
11
|
+
items = treat_children_coradoc(
|
|
12
|
+
node,
|
|
13
|
+
state.merge(ol_count: ol_count)
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
marker_type = get_list_type(node, state)
|
|
17
|
+
|
|
18
|
+
Coradoc::CoreModel::ListBlock.new(
|
|
19
|
+
marker_type: marker_type,
|
|
20
|
+
items: items,
|
|
21
|
+
id: id,
|
|
22
|
+
start: node['start']&.to_i
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get_list_type(node, _state)
|
|
27
|
+
case node.name
|
|
28
|
+
when 'ol'
|
|
29
|
+
'ordered'
|
|
30
|
+
when 'ul'
|
|
31
|
+
'unordered'
|
|
32
|
+
when 'dir'
|
|
33
|
+
'unordered'
|
|
34
|
+
else
|
|
35
|
+
'unordered'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
register :ol, Ol.new
|
|
41
|
+
register :ul, Ol.new
|
|
42
|
+
register :dir, Ol.new
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class P < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
id = node['id']
|
|
10
|
+
content = treat_children_coradoc(node, state)
|
|
11
|
+
|
|
12
|
+
# Strip full-width spaces from paragraph content
|
|
13
|
+
content = strip_fullwidth_spaces(content)
|
|
14
|
+
|
|
15
|
+
Coradoc::CoreModel::Block.new(
|
|
16
|
+
block_semantic_type: :paragraph,
|
|
17
|
+
element_type: 'paragraph',
|
|
18
|
+
children: content,
|
|
19
|
+
id: id
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def strip_fullwidth_spaces(content)
|
|
26
|
+
return content unless content.is_a?(Array)
|
|
27
|
+
|
|
28
|
+
# Strip full-width spaces from all inline elements
|
|
29
|
+
content.each do |item|
|
|
30
|
+
if item.is_a?(Coradoc::CoreModel::InlineElement) && item.content.is_a?(String)
|
|
31
|
+
item.content = item.content.gsub(/\A +| +\z/, '')
|
|
32
|
+
elsif item.is_a?(String)
|
|
33
|
+
item.gsub(/\A +| +\z/, '')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Strip leading space from first text element
|
|
38
|
+
first_text = content.find { |item| item.is_a?(Coradoc::CoreModel::InlineElement) || item.is_a?(String) }
|
|
39
|
+
if first_text.is_a?(Coradoc::CoreModel::InlineElement) && first_text.content.is_a?(String)
|
|
40
|
+
first_text.content = first_text.content.lstrip
|
|
41
|
+
elsif first_text.is_a?(String)
|
|
42
|
+
first_text.lstrip
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Strip trailing space from last text element
|
|
46
|
+
last_text = content.reverse.find do |item|
|
|
47
|
+
item.is_a?(Coradoc::CoreModel::InlineElement) || item.is_a?(String)
|
|
48
|
+
end
|
|
49
|
+
if last_text.is_a?(Coradoc::CoreModel::InlineElement) && last_text.content.is_a?(String)
|
|
50
|
+
last_text.content = last_text.content.rstrip
|
|
51
|
+
elsif last_text.is_a?(String)
|
|
52
|
+
last_text.rstrip
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Remove empty text elements after stripping
|
|
56
|
+
# But keep InlineElements that have nested_elements (e.g., bold with nested text)
|
|
57
|
+
content.reject do |item|
|
|
58
|
+
if item.is_a?(Coradoc::CoreModel::InlineElement)
|
|
59
|
+
item.content.to_s.empty? && !item_has_nested_content?(item)
|
|
60
|
+
elsif item.is_a?(String)
|
|
61
|
+
item.empty?
|
|
62
|
+
else
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Check if InlineElement has meaningful nested content
|
|
69
|
+
def item_has_nested_content?(item)
|
|
70
|
+
return false unless item.is_a?(Coradoc::CoreModel::InlineElement)
|
|
71
|
+
return false if item.nested_elements.nil? || item.nested_elements.empty?
|
|
72
|
+
|
|
73
|
+
true
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
register :p, P.new
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class PassThrough < Base
|
|
8
|
+
def to_coradoc(node, _state = {})
|
|
9
|
+
node.to_s
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def convert(node, state = {})
|
|
13
|
+
to_coradoc(node, state)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Pre < Base
|
|
8
|
+
def to_coradoc(node, _state = {})
|
|
9
|
+
id = node['id']
|
|
10
|
+
lang = language(node)
|
|
11
|
+
content = extract_text_content(node)
|
|
12
|
+
|
|
13
|
+
if lang
|
|
14
|
+
Coradoc::CoreModel::SourceBlock.new(
|
|
15
|
+
element_type: 'source',
|
|
16
|
+
content: content,
|
|
17
|
+
id: id,
|
|
18
|
+
language: lang
|
|
19
|
+
)
|
|
20
|
+
else
|
|
21
|
+
Coradoc::CoreModel::LiteralBlock.new(
|
|
22
|
+
element_type: 'literal',
|
|
23
|
+
content: content,
|
|
24
|
+
id: id
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def extract_text_content(node)
|
|
32
|
+
# Get text content from pre node
|
|
33
|
+
node.text
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def language(node)
|
|
37
|
+
lang = language_from_highlight_class(node)
|
|
38
|
+
lang || language_from_confluence_class(node)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def language_from_highlight_class(node)
|
|
42
|
+
node.parent['class'].to_s[/highlight-([a-zA-Z0-9]+)/, 1]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def language_from_confluence_class(node)
|
|
46
|
+
class_str = node['class'].to_s
|
|
47
|
+
return nil unless class_str.include?('brush:')
|
|
48
|
+
|
|
49
|
+
# Extract language from brush: language; pattern
|
|
50
|
+
match = class_str.match(/brush:\s*([^;]+);/)
|
|
51
|
+
match ? match[1].strip : nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
register :pre, Pre.new
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Q < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
content = treat_children_coradoc(node, state)
|
|
10
|
+
cite = node['cite']
|
|
11
|
+
|
|
12
|
+
Coradoc::CoreModel::InlineElement.new(
|
|
13
|
+
format_type: 'quotation',
|
|
14
|
+
content: content,
|
|
15
|
+
metadata: cite ? { cite: cite } : {}
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
register :q, Q.new
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Strong < Markup
|
|
8
|
+
def coradoc_format_type
|
|
9
|
+
'bold'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def markup_ancestor_tag_names
|
|
13
|
+
%w[strong b]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
register :strong, Strong.new
|
|
18
|
+
register :b, Strong.new
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
module Input
|
|
5
|
+
module Html
|
|
6
|
+
module Converters
|
|
7
|
+
class Sub < Base
|
|
8
|
+
def to_coradoc(node, state = {})
|
|
9
|
+
leading_whitespace, trailing_whitespace = extract_leading_trailing_whitespace(node)
|
|
10
|
+
|
|
11
|
+
content = treat_children_coradoc(node, state)
|
|
12
|
+
|
|
13
|
+
# Check if content is empty
|
|
14
|
+
return nil if content_empty?(content)
|
|
15
|
+
|
|
16
|
+
# Create CoreModel::InlineElement with format_type "subscript"
|
|
17
|
+
e = Coradoc::CoreModel::InlineElement.new(
|
|
18
|
+
format_type: 'subscript',
|
|
19
|
+
content: content
|
|
20
|
+
)
|
|
21
|
+
result = [leading_whitespace, e, trailing_whitespace].compact
|
|
22
|
+
result.length == 1 ? result.first : result
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def content_empty?(content)
|
|
28
|
+
return true if content.nil?
|
|
29
|
+
return content.strip.empty? if content.is_a?(String)
|
|
30
|
+
return content.empty? if content.is_a?(Array)
|
|
31
|
+
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
register :sub, Sub.new
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|