isodoc 1.6.1 → 1.6.6
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/.github/workflows/rake.yml +2 -12
- data/.hound.yml +3 -1
- data/.rubocop.yml +4 -8
- data/Rakefile +2 -2
- data/isodoc.gemspec +4 -3
- data/lib/isodoc-yaml/i18n-ar.yaml +152 -0
- data/lib/isodoc-yaml/i18n-de.yaml +149 -0
- data/lib/isodoc-yaml/i18n-en.yaml +1 -0
- data/lib/isodoc-yaml/i18n-es.yaml +151 -0
- data/lib/isodoc-yaml/i18n-fr.yaml +1 -0
- data/lib/isodoc-yaml/i18n-ru.yaml +154 -0
- data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
- data/lib/isodoc.rb +0 -2
- data/lib/isodoc/common.rb +2 -0
- data/lib/isodoc/convert.rb +8 -2
- data/lib/isodoc/function/blocks.rb +15 -4
- data/lib/isodoc/function/cleanup.rb +52 -43
- data/lib/isodoc/function/form.rb +51 -0
- data/lib/isodoc/function/inline.rb +8 -7
- data/lib/isodoc/function/references.rb +71 -77
- data/lib/isodoc/function/section.rb +28 -16
- data/lib/isodoc/function/table.rb +22 -22
- data/lib/isodoc/function/terms.rb +6 -7
- data/lib/isodoc/function/to_word_html.rb +19 -25
- data/lib/isodoc/function/utils.rb +181 -163
- data/lib/isodoc/gem_tasks.rb +8 -9
- data/lib/isodoc/headlesshtml_convert.rb +8 -7
- data/lib/isodoc/html_convert.rb +6 -0
- data/lib/isodoc/html_function/comments.rb +14 -12
- data/lib/isodoc/html_function/footnotes.rb +14 -7
- data/lib/isodoc/html_function/form.rb +62 -0
- data/lib/isodoc/html_function/html.rb +30 -26
- data/lib/isodoc/html_function/postprocess.rb +191 -182
- data/lib/isodoc/html_function/sectionsplit.rb +230 -0
- data/lib/isodoc/i18n.rb +13 -11
- data/lib/isodoc/metadata.rb +22 -20
- data/lib/isodoc/metadata_contributor.rb +31 -28
- data/lib/isodoc/pdf_convert.rb +11 -13
- data/lib/isodoc/presentation_function/bibdata.rb +54 -30
- data/lib/isodoc/presentation_function/inline.rb +70 -120
- data/lib/isodoc/presentation_function/math.rb +84 -0
- data/lib/isodoc/presentation_function/section.rb +55 -19
- data/lib/isodoc/presentation_xml_convert.rb +3 -0
- data/lib/isodoc/sassc_importer.rb +1 -1
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/body.rb +28 -24
- data/lib/isodoc/word_function/postprocess.rb +50 -36
- data/lib/isodoc/xref.rb +2 -0
- data/lib/isodoc/xref/xref_counter.rb +1 -2
- data/lib/isodoc/xref/xref_gen.rb +21 -14
- data/lib/isodoc/xref/xref_gen_seq.rb +60 -35
- data/lib/isodoc/xref/xref_sect_gen.rb +15 -15
- data/spec/assets/scripts_override.html +3 -0
- data/spec/isodoc/blocks_spec.rb +624 -997
- data/spec/isodoc/cleanup_spec.rb +40 -42
- data/spec/isodoc/form_spec.rb +156 -0
- data/spec/isodoc/i18n_spec.rb +694 -821
- data/spec/isodoc/inline_spec.rb +1105 -921
- data/spec/isodoc/metadata_spec.rb +384 -379
- data/spec/isodoc/postproc_spec.rb +461 -333
- data/spec/isodoc/presentation_xml_spec.rb +355 -278
- data/spec/isodoc/ref_spec.rb +5 -5
- data/spec/isodoc/section_spec.rb +216 -199
- data/spec/isodoc/sectionsplit_spec.rb +190 -0
- data/spec/isodoc/table_spec.rb +41 -42
- data/spec/isodoc/terms_spec.rb +84 -84
- data/spec/isodoc/xref_spec.rb +974 -932
- metadata +32 -7
data/lib/isodoc/gem_tasks.rb
CHANGED
@@ -12,12 +12,10 @@ module IsoDoc
|
|
12
12
|
|
13
13
|
def install
|
14
14
|
rule ".css" => [proc { |tn| tn.sub(/\.css$/, ".scss") }] do |current_task|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
notify_borken_compilation(e, current_task)
|
20
|
-
end
|
15
|
+
puts(current_task)
|
16
|
+
compile_scss_task(current_task)
|
17
|
+
rescue StandardError => e
|
18
|
+
notify_borken_compilation(e, current_task)
|
21
19
|
end
|
22
20
|
|
23
21
|
scss_files = Rake::FileList["lib/**/*.scss"]
|
@@ -88,7 +86,7 @@ module IsoDoc
|
|
88
86
|
text
|
89
87
|
.gsub("/* LIQUID_COMMENT", "")
|
90
88
|
.gsub("LIQUID_COMMENT */", "")
|
91
|
-
.gsub('"{{',
|
89
|
+
.gsub('"{{', "{{").gsub('}}"', "}}")
|
92
90
|
end
|
93
91
|
|
94
92
|
def fonts_placeholder
|
@@ -107,7 +105,8 @@ module IsoDoc
|
|
107
105
|
require "sassc"
|
108
106
|
|
109
107
|
isodoc_path = if Gem.loaded_specs["isodoc"]
|
110
|
-
File.join(Gem.loaded_specs["isodoc"].full_gem_path,
|
108
|
+
File.join(Gem.loaded_specs["isodoc"].full_gem_path,
|
109
|
+
"lib", "isodoc")
|
111
110
|
else
|
112
111
|
File.join("lib", "isodoc")
|
113
112
|
end
|
@@ -119,7 +118,7 @@ module IsoDoc
|
|
119
118
|
SassC::Engine.new(fonts_placeholder + sheet_content,
|
120
119
|
syntax: :scss,
|
121
120
|
importer: SasscImporter)
|
122
|
-
|
121
|
+
.render
|
123
122
|
end
|
124
123
|
|
125
124
|
def compile_scss_task(current_task)
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require_relative "html_function/comments
|
2
|
-
require_relative "html_function/footnotes
|
3
|
-
require_relative "html_function/html
|
1
|
+
require_relative "html_function/comments"
|
2
|
+
require_relative "html_function/footnotes"
|
3
|
+
require_relative "html_function/html"
|
4
4
|
require "fileutils"
|
5
5
|
|
6
6
|
module IsoDoc
|
7
7
|
class HeadlessHtmlConvert < ::IsoDoc::Convert
|
8
|
-
|
9
8
|
include HtmlFunction::Comments
|
10
9
|
include HtmlFunction::Footnotes
|
11
10
|
include HtmlFunction::Html
|
@@ -26,16 +25,18 @@ module IsoDoc
|
|
26
25
|
docxml, filename, dir = convert_init(file, input_filename, debug)
|
27
26
|
result = convert1(docxml, filename, dir)
|
28
27
|
return result if debug
|
29
|
-
|
28
|
+
|
29
|
+
postprocess(result, "#{filename}.tmp.html", dir)
|
30
30
|
FileUtils.rm_rf dir
|
31
|
-
strip_head(filename
|
31
|
+
strip_head("#{filename}.tmp.html",
|
32
|
+
output_filename || "#{filename}.#{@suffix}")
|
32
33
|
FileUtils.rm_rf ["#{filename}.tmp.html", tmpimagedir]
|
33
34
|
end
|
34
35
|
|
35
36
|
def strip_head(input, output)
|
36
37
|
file = File.read(input, encoding: "utf-8")
|
37
38
|
doc = Nokogiri::XML(file)
|
38
|
-
doc.xpath("//head").each
|
39
|
+
doc.xpath("//head").each(&:remove)
|
39
40
|
doc.xpath("//html").each { |x| x.name = "div" }
|
40
41
|
body = doc.at("//body")
|
41
42
|
body.replace(body.children)
|
data/lib/isodoc/html_convert.rb
CHANGED
@@ -2,12 +2,15 @@ require_relative "html_function/comments"
|
|
2
2
|
require_relative "html_function/footnotes"
|
3
3
|
require_relative "html_function/html"
|
4
4
|
require_relative "html_function/postprocess"
|
5
|
+
require_relative "html_function/sectionsplit"
|
6
|
+
require_relative "html_function/form"
|
5
7
|
|
6
8
|
module IsoDoc
|
7
9
|
class HtmlConvert < ::IsoDoc::Convert
|
8
10
|
|
9
11
|
include HtmlFunction::Comments
|
10
12
|
include HtmlFunction::Footnotes
|
13
|
+
include HtmlFunction::Form
|
11
14
|
include HtmlFunction::Html
|
12
15
|
|
13
16
|
def tmpimagedir_suffix
|
@@ -21,6 +24,9 @@ module IsoDoc
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def convert(filename, file = nil, debug = false, output_filename = nil)
|
27
|
+
@sectionsplit and
|
28
|
+
return sectionsplit_convert(filename, file, debug, output_filename)
|
29
|
+
|
24
30
|
ret = super
|
25
31
|
Dir.exists?(tmpimagedir) and Dir["#{tmpimagedir}/*"].empty? and
|
26
32
|
FileUtils.rm_r tmpimagedir
|
@@ -24,16 +24,16 @@ module IsoDoc::HtmlFunction
|
|
24
24
|
=end
|
25
25
|
end
|
26
26
|
|
27
|
-
def comment_link_attrs(
|
28
|
-
{ style: "MsoCommentReference", target:
|
27
|
+
def comment_link_attrs(fnote, node)
|
28
|
+
{ style: "MsoCommentReference", target: fnote,
|
29
29
|
class: "commentLink", from: node["from"],
|
30
30
|
to: node["to"] }
|
31
31
|
end
|
32
32
|
|
33
33
|
# add in from and to links to move the comment into place
|
34
|
-
def make_comment_link(out,
|
35
|
-
out.span(**comment_link_attrs(
|
36
|
-
s1.a **{ style: "mso-comment-reference:SMC_#{
|
34
|
+
def make_comment_link(out, fnote, node)
|
35
|
+
out.span(**comment_link_attrs(fnote, node)) do |s1|
|
36
|
+
s1.a **{ style: "mso-comment-reference:SMC_#{fnote};"\
|
37
37
|
"mso-comment-date:#{node['date'].gsub(/[-:Z]/, '')}" }
|
38
38
|
end
|
39
39
|
end
|
@@ -44,9 +44,9 @@ module IsoDoc::HtmlFunction
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
def make_comment_text(node,
|
47
|
+
def make_comment_text(node, fnote)
|
48
48
|
noko do |xml|
|
49
|
-
xml.div **{ style: "mso-element:comment", id:
|
49
|
+
xml.div **{ style: "mso-element:comment", id: fnote } do |div|
|
50
50
|
div.span **{ style: %{mso-comment-author:"#{node['reviewer']}"} }
|
51
51
|
make_comment_target(div)
|
52
52
|
node.children.each { |n| parse(n, div) }
|
@@ -84,6 +84,7 @@ module IsoDoc::HtmlFunction
|
|
84
84
|
def comment_attributes(docxml, x)
|
85
85
|
fromlink = docxml.at("//*[@id='#{x['from']}']")
|
86
86
|
return(nil) if fromlink.nil?
|
87
|
+
|
87
88
|
tolink = docxml.at("//*[@id='#{x['to']}']") || fromlink
|
88
89
|
target = docxml.at("//*[@id='#{x['target']}']")
|
89
90
|
{ from: fromlink, to: tolink, target: target }
|
@@ -98,13 +99,13 @@ module IsoDoc::HtmlFunction
|
|
98
99
|
from["style"] != "mso-special-character:comment"
|
99
100
|
end
|
100
101
|
|
101
|
-
def insert_comment_cont(from,
|
102
|
-
# includes_to = from.at(".//*[@id='#{
|
103
|
-
while !from.nil? && from["id"] !=
|
102
|
+
def insert_comment_cont(from, upto, target)
|
103
|
+
# includes_to = from.at(".//*[@id='#{upto}']")
|
104
|
+
while !from.nil? && from["id"] != upto
|
104
105
|
following = from.xpath("./following::*")
|
105
|
-
(from = following.shift) && incl_to = from.at(".//*[@id='#{
|
106
|
+
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
106
107
|
while !incl_to.nil? && !from.nil? && skip_comment_wrap(from)
|
107
|
-
(from = following.shift) && incl_to = from.at(".//*[@id='#{
|
108
|
+
(from = following.shift) && incl_to = from.at(".//*[@id='#{upto}']")
|
108
109
|
end
|
109
110
|
wrap_comment_cont(from, target) if !from.nil?
|
110
111
|
end
|
@@ -122,6 +123,7 @@ module IsoDoc::HtmlFunction
|
|
122
123
|
comments = []
|
123
124
|
docxml.xpath("//div[@style='mso-element:comment']").each do |c|
|
124
125
|
next unless c["id"] && !link_order[c["id"]].nil?
|
126
|
+
|
125
127
|
comments << { text: c.remove.to_s, id: c["id"] }
|
126
128
|
end
|
127
129
|
comments.sort! { |a, b| link_order[a[:id]] <=> link_order[b[:id]] }
|
@@ -3,6 +3,7 @@ module IsoDoc::HtmlFunction
|
|
3
3
|
|
4
4
|
def footnotes(div)
|
5
5
|
return if @footnotes.empty?
|
6
|
+
|
6
7
|
@footnotes.each { |fn| div.parent << fn }
|
7
8
|
end
|
8
9
|
|
@@ -44,15 +45,19 @@ module IsoDoc::HtmlFunction
|
|
44
45
|
def get_table_ancestor_id(node)
|
45
46
|
table = node.ancestors("table") || node.ancestors("figure")
|
46
47
|
return UUIDTools::UUID.random_create.to_s if table.empty?
|
48
|
+
|
47
49
|
table.last["id"]
|
48
50
|
end
|
49
51
|
|
52
|
+
# @seen_footnote:
|
53
|
+
# do not output footnote text if we have already seen it for this table
|
54
|
+
|
50
55
|
def table_footnote_parse(node, out)
|
51
56
|
fn = node["reference"] || UUIDTools::UUID.random_create.to_s
|
52
57
|
tid = get_table_ancestor_id(node)
|
53
58
|
make_table_footnote_link(out, tid + fn, fn)
|
54
|
-
# do not output footnote text if we have already seen it for this table
|
55
59
|
return if @seen_footnote.include?(tid + fn)
|
60
|
+
|
56
61
|
@in_footnote = true
|
57
62
|
out.aside **{ class: "footnote" } do |a|
|
58
63
|
a << make_table_footnote_text(node, tid + fn, fn)
|
@@ -62,8 +67,9 @@ module IsoDoc::HtmlFunction
|
|
62
67
|
end
|
63
68
|
|
64
69
|
def footnote_parse(node, out)
|
65
|
-
|
66
|
-
!node.ancestors.map
|
70
|
+
return table_footnote_parse(node, out) if (@in_table || @in_figure) &&
|
71
|
+
!node.ancestors.map(&:name).include?("name")
|
72
|
+
|
67
73
|
fn = node["reference"] || UUIDTools::UUID.random_create.to_s
|
68
74
|
attrs = { class: "FootnoteRef", href: "#fn:#{fn}" }
|
69
75
|
out.a **attrs do |a|
|
@@ -72,12 +78,13 @@ module IsoDoc::HtmlFunction
|
|
72
78
|
make_footnote(node, fn)
|
73
79
|
end
|
74
80
|
|
75
|
-
def make_footnote(node,
|
76
|
-
return if @seen_footnote.include?(
|
81
|
+
def make_footnote(node, fnote)
|
82
|
+
return if @seen_footnote.include?(fnote)
|
83
|
+
|
77
84
|
@in_footnote = true
|
78
|
-
@footnotes << make_generic_footnote_text(node,
|
85
|
+
@footnotes << make_generic_footnote_text(node, fnote)
|
79
86
|
@in_footnote = false
|
80
|
-
@seen_footnote <<
|
87
|
+
@seen_footnote << fnote
|
81
88
|
end
|
82
89
|
end
|
83
90
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module IsoDoc::HtmlFunction
|
2
|
+
module Form
|
3
|
+
def form_parse(node, out)
|
4
|
+
out.form **attr_code(id: node["id"], name: node["name"],
|
5
|
+
action: node["action"]) do |div|
|
6
|
+
node.children.each do |n|
|
7
|
+
parse(n, div)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def input_parse(node, out)
|
13
|
+
out.input nil, **attr_code(
|
14
|
+
id: node["id"], name: node["name"], type: node["type"],
|
15
|
+
value: node["value"], disabled: node["disabled"],
|
16
|
+
readonly: node["readonly"], checked: node["checked"],
|
17
|
+
maxlength: node["maxlength"], minlength: node["minlength"]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def select_parse(node, out)
|
22
|
+
selected = node.at(ns("./option[@value = '#{node['value']}']"))
|
23
|
+
selected and selected["selected"] = true
|
24
|
+
out.select **attr_code(
|
25
|
+
id: node["id"], name: node["name"], size: node["size"],
|
26
|
+
disabled: node["disabled"], multiple: node["multiple"]
|
27
|
+
) do |div|
|
28
|
+
node.children.each do |n|
|
29
|
+
parse(n, div)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def label_parse(node, out)
|
35
|
+
out.label **attr_code(for: node["for"]) do |div|
|
36
|
+
node.children.each do |n|
|
37
|
+
parse(n, div)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def option_parse(node, out)
|
43
|
+
out.option **attr_code(
|
44
|
+
disabled: node["disabled"], selected: node["selected"],
|
45
|
+
value: node["value"]
|
46
|
+
) do |o|
|
47
|
+
node.children.each do |n|
|
48
|
+
parse(n, o)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def textarea_parse(node, out)
|
54
|
+
out.textarea **attr_code(
|
55
|
+
id: node["id"], name: node["name"], rows: node["rows"],
|
56
|
+
cols: node["cols"]
|
57
|
+
) do |div|
|
58
|
+
node["value"] and div << node["value"]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -5,9 +5,9 @@ module IsoDoc::HtmlFunction
|
|
5
5
|
module Html
|
6
6
|
def convert1(docxml, filename, dir)
|
7
7
|
noko do |xml|
|
8
|
-
xml.html **{ lang:
|
8
|
+
xml.html **{ lang: @lang.to_s } do |html|
|
9
9
|
info docxml, nil
|
10
|
-
populate_css
|
10
|
+
populate_css
|
11
11
|
html.head { |head| define_head head, filename, dir }
|
12
12
|
make_body(html, docxml)
|
13
13
|
end
|
@@ -15,13 +15,17 @@ module IsoDoc::HtmlFunction
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def make_body1(body, _docxml)
|
18
|
+
return if @bare
|
19
|
+
|
18
20
|
body.div **{ class: "title-section" } do |div1|
|
19
21
|
div1.p { |p| p << " " } # placeholder
|
20
22
|
end
|
21
23
|
section_break(body)
|
22
24
|
end
|
23
25
|
|
24
|
-
def make_body2(body,
|
26
|
+
def make_body2(body, _docxml)
|
27
|
+
return if @bare
|
28
|
+
|
25
29
|
body.div **{ class: "prefatory-section" } do |div2|
|
26
30
|
div2.p { |p| p << " " } # placeholder
|
27
31
|
end
|
@@ -43,46 +47,47 @@ module IsoDoc::HtmlFunction
|
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
46
|
-
def googlefonts
|
50
|
+
def googlefonts
|
47
51
|
<<~HEAD.freeze
|
48
|
-
|
49
|
-
|
52
|
+
<link href="https://fonts.googleapis.com/css?family=Overpass:300,300i,600,900" rel="stylesheet">
|
53
|
+
<link href="https://fonts.googleapis.com/css?family=Lato:400,400i,700,900" rel="stylesheet">
|
50
54
|
HEAD
|
51
55
|
end
|
52
56
|
|
53
|
-
def html_head
|
57
|
+
def html_head
|
54
58
|
<<~HEAD.freeze
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
59
|
+
<title>#{@meta&.get&.dig(:doctitle)}</title>
|
60
|
+
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
61
|
+
|
62
|
+
<!--TOC script import-->
|
63
|
+
<script type="text/javascript" src="https://cdn.rawgit.com/jgallen23/toc/0.3.2/dist/toc.min.js"></script>
|
64
|
+
<script type="text/javascript">#{toclevel}</script>
|
65
|
+
|
66
|
+
<!--Google fonts-->
|
67
|
+
<link rel="preconnect" href="https://fonts.gstatic.com">#{' '}
|
68
|
+
#{googlefonts}
|
69
|
+
<!--Font awesome import for the link icon-->
|
70
|
+
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/solid.css" integrity="sha384-v2Tw72dyUXeU3y4aM2Y0tBJQkGfplr39mxZqlTBDUZAb9BGoC40+rdFCG0m10lXk" crossorigin="anonymous">
|
71
|
+
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/fontawesome.css" integrity="sha384-q3jl8XQu1OpdLgGFvNRnPdj5VIlCvgsDQTQB6owSOHWlAurxul7f+JpUOVdAiJ5P" crossorigin="anonymous">
|
72
|
+
<style class="anchorjs"></style>
|
69
73
|
HEAD
|
70
74
|
end
|
71
75
|
|
72
|
-
def html_button
|
76
|
+
def html_button
|
73
77
|
'<button onclick="topFunction()" id="myBtn" '\
|
74
78
|
'title="Go to top">Top</button>'.freeze
|
75
79
|
end
|
76
80
|
|
77
81
|
def html_main(docxml)
|
78
|
-
docxml.at("//head").add_child(html_head
|
82
|
+
docxml.at("//head").add_child(html_head)
|
79
83
|
d = docxml.at('//div[@class="main-section"]')
|
80
84
|
d.name = "main"
|
81
|
-
d.children.empty? or d.children.first.previous = html_button
|
85
|
+
d.children.empty? or d.children.first.previous = html_button
|
82
86
|
end
|
83
87
|
|
84
88
|
def sourcecodelang(lang)
|
85
89
|
return unless lang
|
90
|
+
|
86
91
|
case lang.downcase
|
87
92
|
when "javascript" then "lang-js"
|
88
93
|
when "c" then "lang-c"
|
@@ -117,7 +122,6 @@ module IsoDoc::HtmlFunction
|
|
117
122
|
end
|
118
123
|
end
|
119
124
|
|
120
|
-
def table_long_strings_cleanup(docxml)
|
121
|
-
end
|
125
|
+
def table_long_strings_cleanup(docxml); end
|
122
126
|
end
|
123
127
|
end
|
@@ -1,224 +1,233 @@
|
|
1
1
|
require "isodoc/html_function/mathvariant_to_plain"
|
2
2
|
require_relative "postprocess_footnotes"
|
3
3
|
|
4
|
-
module IsoDoc
|
5
|
-
module
|
6
|
-
|
7
|
-
result
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
module IsoDoc
|
5
|
+
module HtmlFunction
|
6
|
+
module Html
|
7
|
+
def postprocess(result, filename, _dir)
|
8
|
+
result = from_xhtml(cleanup(to_xhtml(textcleanup(result))))
|
9
|
+
toHTML(result, filename)
|
10
|
+
@files_to_delete.each { |f| FileUtils.rm_rf f }
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
def script_cdata(result)
|
14
|
+
result.gsub(%r{<script([^>]*)>\s*<!\[CDATA\[}m, "<script\\1>")
|
15
|
+
.gsub(%r{\]\]>\s*</script>}, "</script>")
|
16
|
+
.gsub(%r{<!\[CDATA\[\s*<script([^>]*)>}m, "<script\\1>")
|
17
|
+
.gsub(%r{</script>\s*\]\]>}, "</script>")
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
def toHTML(result, filename)
|
21
|
+
result = from_xhtml(html_cleanup(to_xhtml(result)))
|
22
|
+
# result = populate_template(result, :html)
|
23
|
+
result = from_xhtml(move_images(to_xhtml(result)))
|
24
|
+
result = html5(script_cdata(inject_script(result)))
|
25
|
+
File.open(filename, "w:UTF-8") { |f| f.write(result) }
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
def html5(doc)
|
29
|
+
doc.sub(%r{<!DOCTYPE html [^>]+>}, "<!DOCTYPE html>")
|
30
|
+
.sub(%r{<\?xml[^>]+>}, "")
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
footnote_format(
|
35
|
-
|
36
|
-
|
37
|
-
term_header(html_footnote_filter(html_preface(htmlstyle(x))))
|
38
|
-
)
|
39
|
-
)
|
40
|
-
)
|
41
|
-
)
|
42
|
-
end
|
33
|
+
def html_cleanup(html)
|
34
|
+
html = term_header(html_footnote_filter(html_preface(htmlstyle(html))))
|
35
|
+
html = footnote_format(footnote_backlinks(html_toc(html)))
|
36
|
+
mathml(html_list_clean(html))
|
37
|
+
end
|
43
38
|
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
def html_list_clean(html)
|
40
|
+
html.xpath("//ol/div | //ul/div").each do |div|
|
41
|
+
li = div&.xpath("./preceding-sibling::li")&.last ||
|
42
|
+
div.at("./following-sibling::li")
|
43
|
+
div.parent = li
|
44
|
+
end
|
45
|
+
html
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
def mathml(docxml)
|
49
|
+
IsoDoc::HtmlFunction::MathvariantToPlain.new(docxml).convert
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
def htmlstylesheet(file)
|
53
|
+
return if file.nil?
|
54
|
+
|
55
|
+
file.open if file.is_a?(Tempfile)
|
56
|
+
stylesheet = file.read
|
57
|
+
xml = Nokogiri::XML("<style/>")
|
58
|
+
xml.children.first << Nokogiri::XML::Comment
|
59
|
+
.new(xml, "\n#{stylesheet}\n")
|
60
|
+
file.close
|
61
|
+
file.unlink if file.is_a?(Tempfile)
|
62
|
+
xml.root.to_s
|
63
|
+
end
|
59
64
|
|
60
|
-
|
61
|
-
|
65
|
+
def htmlstyle(docxml)
|
66
|
+
return docxml unless @htmlstylesheet
|
62
67
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
68
|
+
head = docxml.at("//*[local-name() = 'head']")
|
69
|
+
head << htmlstylesheet(@htmlstylesheet)
|
70
|
+
s = htmlstylesheet(@htmlstylesheet_override) and head << s
|
71
|
+
docxml
|
72
|
+
end
|
69
73
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
def html_preface(docxml)
|
75
|
+
html_cover(docxml) if @htmlcoverpage && !@bare
|
76
|
+
html_intro(docxml) if @htmlintropage && !@bare
|
77
|
+
docxml.at("//body") << mathjax(@openmathdelim, @closemathdelim)
|
78
|
+
docxml.at("//body") << sourcecode_highlighter
|
79
|
+
html_main(docxml)
|
80
|
+
authority_cleanup(docxml)
|
81
|
+
docxml
|
82
|
+
end
|
79
83
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
def authority_cleanup1(docxml, klass)
|
85
|
+
dest = docxml.at("//div[@id = 'boilerplate-#{klass}-destination']")
|
86
|
+
auth = docxml.at("//div[@id = 'boilerplate-#{klass}' or "\
|
87
|
+
"@class = 'boilerplate-#{klass}']")
|
88
|
+
auth&.xpath(".//h1[not(text())] | .//h2[not(text())]")&.each(&:remove)
|
89
|
+
auth&.xpath(".//h1 | .//h2")&.each { |h| h["class"] = "IntroTitle" }
|
90
|
+
dest and auth and dest.replace(auth.remove)
|
91
|
+
end
|
87
92
|
|
88
|
-
|
89
|
-
|
90
|
-
|
93
|
+
def authority_cleanup(docxml)
|
94
|
+
%w(copyright license legal feedback).each do |t|
|
95
|
+
authority_cleanup1(docxml, t)
|
96
|
+
end
|
91
97
|
end
|
92
|
-
end
|
93
98
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
99
|
+
def html_cover(docxml)
|
100
|
+
doc = to_xhtml_fragment(File.read(@htmlcoverpage, encoding: "UTF-8"))
|
101
|
+
d = docxml.at('//div[@class="title-section"]')
|
102
|
+
# d.children.first.add_previous_sibling doc.to_xml(encoding: "US-ASCII")
|
103
|
+
d.children.first.add_previous_sibling(
|
104
|
+
populate_template(doc.to_xml(encoding: "US-ASCII"), :html),
|
105
|
+
)
|
106
|
+
end
|
102
107
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
def html_intro(docxml)
|
109
|
+
doc = to_xhtml_fragment(File.read(@htmlintropage, encoding: "UTF-8"))
|
110
|
+
d = docxml.at('//div[@class="prefatory-section"]')
|
111
|
+
# d.children.first.add_previous_sibling doc.to_xml(encoding: "US-ASCII")
|
112
|
+
d.children.first.add_previous_sibling(
|
113
|
+
populate_template(doc.to_xml(encoding: "US-ASCII"), :html),
|
114
|
+
)
|
115
|
+
end
|
111
116
|
|
112
|
-
|
113
|
-
|
117
|
+
def html_toc_entry(level, header)
|
118
|
+
%(<li class="#{level}"><a href="##{header['id']}">\
|
114
119
|
#{header_strip(header)}</a></li>)
|
115
|
-
|
116
|
-
|
117
|
-
def toclevel_classes
|
118
|
-
(1..@htmlToClevels).reduce([]) { |m, i| m << "h#{i}" }
|
119
|
-
end
|
120
|
+
end
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
"#{l}:not(:empty):not(.TermNum):not(.noTOC)"
|
122
|
+
def toclevel_classes
|
123
|
+
(1..@htmlToClevels).reduce([]) { |m, i| m << "h#{i}" }
|
124
124
|
end
|
125
|
-
<<~HEAD.freeze
|
126
|
-
function toclevel() { return "#{ret.join(',')}";}
|
127
|
-
HEAD
|
128
|
-
end
|
129
125
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
126
|
+
def toclevel
|
127
|
+
ret = toclevel_classes.map do |l|
|
128
|
+
"#{l}:not(:empty):not(.TermNum):not(.noTOC)"
|
129
|
+
end
|
130
|
+
<<~HEAD.freeze
|
131
|
+
function toclevel() { return "#{ret.join(',')}";}
|
132
|
+
HEAD
|
136
133
|
end
|
137
|
-
|
138
|
-
|
139
|
-
|
134
|
+
|
135
|
+
# needs to be same output as toclevel
|
136
|
+
def html_toc(docxml)
|
137
|
+
idx = docxml.at("//div[@id = 'toc']") or return docxml
|
138
|
+
toc = "<ul>"
|
139
|
+
path = toclevel_classes.map do |l|
|
140
|
+
"//main//#{l}[not(@class = 'TermNum')][not(@class = 'noTOC')][text()]"
|
141
|
+
end
|
142
|
+
docxml.xpath(path.join(" | ")).each_with_index do |h, tocidx|
|
143
|
+
h["id"] ||= "toc#{tocidx}"
|
144
|
+
toc += html_toc_entry(h.name, h)
|
145
|
+
end
|
146
|
+
idx.children = "#{toc}</ul>"
|
147
|
+
docxml
|
140
148
|
end
|
141
|
-
idx.children = "#{toc}</ul>"
|
142
|
-
docxml
|
143
|
-
end
|
144
149
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
150
|
+
# presupposes that the image source is local
|
151
|
+
def move_images(docxml)
|
152
|
+
FileUtils.rm_rf tmpimagedir
|
153
|
+
FileUtils.mkdir tmpimagedir
|
154
|
+
docxml.xpath("//*[local-name() = 'img']").each do |i|
|
155
|
+
i["width"], i["height"] = Html2Doc.image_resize(i, image_localfile(i),
|
156
|
+
@maxheight, @maxwidth)
|
157
|
+
next if /^data:/.match? i["src"]
|
153
158
|
|
154
|
-
|
159
|
+
@datauriimage ? datauri(i) : move_image1(i)
|
160
|
+
end
|
161
|
+
docxml
|
155
162
|
end
|
156
|
-
docxml
|
157
|
-
end
|
158
163
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
164
|
+
def datauri(img)
|
165
|
+
type = img["src"].split(".")[-1]
|
166
|
+
supertype = type == "xml" ? "application" : "image"
|
167
|
+
bin = IO.binread(image_localfile(img))
|
168
|
+
data = Base64.strict_encode64(bin)
|
169
|
+
img["src"] = "data:#{supertype}/#{type};base64,#{data}"
|
170
|
+
end
|
166
171
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
172
|
+
def image_suffix(img)
|
173
|
+
type = img["mimetype"]&.sub(%r{^[^/*]+/}, "")
|
174
|
+
matched = /\.(?<suffix>[^. \r\n\t]+)$/.match img["src"]
|
175
|
+
type and !type.empty? and return type
|
171
176
|
|
172
|
-
|
173
|
-
|
174
|
-
|
177
|
+
!matched.nil? and matched[:suffix] and return matched[:suffix]
|
178
|
+
"png"
|
179
|
+
end
|
175
180
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
def move_image1(img)
|
182
|
+
suffix = image_suffix(img)
|
183
|
+
uuid = UUIDTools::UUID.random_create.to_s
|
184
|
+
fname = "#{uuid}.#{suffix}"
|
185
|
+
new_full_filename = File.join(tmpimagedir, fname)
|
186
|
+
local_filename = image_localfile(img)
|
187
|
+
FileUtils.cp local_filename, new_full_filename
|
188
|
+
img["src"] = File.join(rel_tmpimagedir, fname)
|
189
|
+
end
|
185
190
|
|
186
|
-
|
187
|
-
|
191
|
+
def inject_script(doc)
|
192
|
+
return doc unless @scripts
|
188
193
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
194
|
+
scripts = File.read(@scripts, encoding: "UTF-8")
|
195
|
+
scripts_override = ""
|
196
|
+
@scripts_override and
|
197
|
+
scripts_override = File.read(@scripts_override, encoding: "UTF-8")
|
198
|
+
a = doc.split(%r{</body>})
|
199
|
+
"#{a[0]}#{scripts}#{scripts_override}</body>#{a[1]}"
|
200
|
+
end
|
193
201
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
202
|
+
def sourcecode_highlighter
|
203
|
+
'<script src="https://cdn.rawgit.com/google/code-prettify/master/'\
|
204
|
+
'loader/run_prettify.js"></script>'
|
205
|
+
end
|
198
206
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
207
|
+
MATHJAX_ADDR =
|
208
|
+
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js".freeze
|
209
|
+
MATHJAX = <<~"MATHJAX".freeze
|
210
|
+
<script type="text/x-mathjax-config">
|
211
|
+
MathJax.Hub.Config({
|
212
|
+
"HTML-CSS": { preferredFont: "STIX" },
|
213
|
+
asciimath2jax: { delimiters: [['OPEN', 'CLOSE']] }
|
214
|
+
});
|
215
|
+
</script>
|
216
|
+
<script src="#{MATHJAX_ADDR}?config=MML_HTMLorMML-full" async="async"></script>
|
217
|
+
MATHJAX
|
218
|
+
|
219
|
+
def mathjax(open, close)
|
220
|
+
MATHJAX.gsub("OPEN", open).gsub("CLOSE", close)
|
221
|
+
end
|
214
222
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
223
|
+
def term_header(docxml)
|
224
|
+
%w(h1 h2 h3 h4 h5 h6 h7 h8).each do |h|
|
225
|
+
docxml.xpath("//p[@class = 'TermNum'][../#{h}]").each do |p|
|
226
|
+
p.name = "h#{h[1].to_i + 1}"
|
227
|
+
end
|
219
228
|
end
|
229
|
+
docxml
|
220
230
|
end
|
221
|
-
docxml
|
222
231
|
end
|
223
232
|
end
|
224
233
|
end
|