isodoc 1.6.0 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +2 -12
  3. data/.hound.yml +3 -1
  4. data/.rubocop.yml +4 -8
  5. data/Rakefile +2 -2
  6. data/bin/rspec +1 -2
  7. data/isodoc.gemspec +4 -3
  8. data/lib/isodoc-yaml/i18n-ar.yaml +152 -0
  9. data/lib/isodoc-yaml/i18n-de.yaml +149 -0
  10. data/lib/isodoc-yaml/i18n-en.yaml +1 -0
  11. data/lib/isodoc-yaml/i18n-es.yaml +151 -0
  12. data/lib/isodoc-yaml/i18n-fr.yaml +1 -0
  13. data/lib/isodoc-yaml/i18n-ru.yaml +154 -0
  14. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
  15. data/lib/isodoc.rb +0 -2
  16. data/lib/isodoc/common.rb +2 -0
  17. data/lib/isodoc/convert.rb +10 -4
  18. data/lib/isodoc/css.rb +30 -26
  19. data/lib/isodoc/function/blocks.rb +26 -8
  20. data/lib/isodoc/function/blocks_example_note.rb +2 -2
  21. data/lib/isodoc/function/cleanup.rb +53 -45
  22. data/lib/isodoc/function/form.rb +51 -0
  23. data/lib/isodoc/function/inline.rb +8 -7
  24. data/lib/isodoc/function/references.rb +71 -77
  25. data/lib/isodoc/function/section.rb +28 -16
  26. data/lib/isodoc/function/table.rb +22 -22
  27. data/lib/isodoc/function/terms.rb +6 -7
  28. data/lib/isodoc/function/to_word_html.rb +19 -25
  29. data/lib/isodoc/function/utils.rb +180 -160
  30. data/lib/isodoc/gem_tasks.rb +36 -38
  31. data/lib/isodoc/headlesshtml_convert.rb +8 -7
  32. data/lib/isodoc/html_convert.rb +10 -4
  33. data/lib/isodoc/html_function/comments.rb +14 -12
  34. data/lib/isodoc/html_function/footnotes.rb +14 -7
  35. data/lib/isodoc/html_function/form.rb +62 -0
  36. data/lib/isodoc/html_function/html.rb +30 -26
  37. data/lib/isodoc/html_function/postprocess.rb +191 -226
  38. data/lib/isodoc/html_function/postprocess_footnotes.rb +59 -0
  39. data/lib/isodoc/html_function/sectionsplit.rb +230 -0
  40. data/lib/isodoc/i18n.rb +33 -31
  41. data/lib/isodoc/metadata.rb +22 -20
  42. data/lib/isodoc/metadata_contributor.rb +31 -28
  43. data/lib/isodoc/pdf_convert.rb +11 -13
  44. data/lib/isodoc/presentation_function/bibdata.rb +54 -30
  45. data/lib/isodoc/presentation_function/block.rb +17 -8
  46. data/lib/isodoc/presentation_function/inline.rb +72 -120
  47. data/lib/isodoc/presentation_function/math.rb +84 -0
  48. data/lib/isodoc/presentation_function/section.rb +55 -19
  49. data/lib/isodoc/presentation_xml_convert.rb +2 -0
  50. data/lib/isodoc/sassc_importer.rb +1 -1
  51. data/lib/isodoc/version.rb +1 -1
  52. data/lib/isodoc/word_function/body.rb +28 -24
  53. data/lib/isodoc/word_function/footnotes.rb +22 -15
  54. data/lib/isodoc/word_function/postprocess.rb +50 -36
  55. data/lib/isodoc/xref.rb +11 -10
  56. data/lib/isodoc/xref/xref_counter.rb +32 -17
  57. data/lib/isodoc/xref/xref_gen.rb +33 -21
  58. data/lib/isodoc/xref/xref_gen_seq.rb +60 -35
  59. data/lib/isodoc/xref/xref_sect_gen.rb +37 -35
  60. data/spec/assets/scripts_override.html +3 -0
  61. data/spec/isodoc/blocks_spec.rb +2258 -2622
  62. data/spec/isodoc/cleanup_spec.rb +1103 -1107
  63. data/spec/isodoc/form_spec.rb +156 -0
  64. data/spec/isodoc/i18n_spec.rb +802 -917
  65. data/spec/isodoc/inline_spec.rb +1105 -921
  66. data/spec/isodoc/lists_spec.rb +316 -315
  67. data/spec/isodoc/metadata_spec.rb +384 -379
  68. data/spec/isodoc/postproc_spec.rb +1783 -1549
  69. data/spec/isodoc/presentation_xml_spec.rb +355 -278
  70. data/spec/isodoc/ref_spec.rb +718 -723
  71. data/spec/isodoc/section_spec.rb +216 -199
  72. data/spec/isodoc/sectionsplit_spec.rb +190 -0
  73. data/spec/isodoc/table_spec.rb +41 -42
  74. data/spec/isodoc/terms_spec.rb +84 -84
  75. data/spec/isodoc/xref_spec.rb +1024 -930
  76. metadata +33 -7
@@ -1,268 +1,233 @@
1
1
  require "isodoc/html_function/mathvariant_to_plain"
2
+ require_relative "postprocess_footnotes"
3
+
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
2
12
 
3
- module IsoDoc::HtmlFunction
4
- module Html
5
- def postprocess(result, filename, _dir)
6
- result = from_xhtml(cleanup(to_xhtml(textcleanup(result))))
7
- toHTML(result, filename)
8
- @files_to_delete.each { |f| FileUtils.rm_rf f }
9
- end
10
-
11
- def script_cdata(result)
12
- result.gsub(%r{<script([^>]*)>\s*<!\[CDATA\[}m, "<script\\1>")
13
- .gsub(%r{\]\]>\s*</script>}, "</script>")
14
- .gsub(%r{<!\[CDATA\[\s*<script([^>]*)>}m, "<script\\1>")
15
- .gsub(%r{</script>\s*\]\]>}, "</script>")
16
- end
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
17
19
 
18
- def toHTML(result, filename)
19
- result = from_xhtml(html_cleanup(to_xhtml(result)))
20
- # result = populate_template(result, :html)
21
- result = from_xhtml(move_images(to_xhtml(result)))
22
- result = html5(script_cdata(inject_script(result)))
23
- File.open(filename, "w:UTF-8") { |f| f.write(result) }
24
- end
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
25
27
 
26
- def html5(doc)
27
- doc.sub(%r{<!DOCTYPE html [^>]+>}, "<!DOCTYPE html>")
28
- .sub(%r{<\?xml[^>]+>}, "")
29
- end
28
+ def html5(doc)
29
+ doc.sub(%r{<!DOCTYPE html [^>]+>}, "<!DOCTYPE html>")
30
+ .sub(%r{<\?xml[^>]+>}, "")
31
+ end
30
32
 
31
- def html_cleanup(x)
32
- mathml(
33
- footnote_format(
34
- footnote_backlinks(
35
- html_toc(
36
- term_header(html_footnote_filter(html_preface(htmlstyle(x))))
37
- )
38
- )
39
- )
40
- )
41
- 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
42
38
 
43
- def mathml(docxml)
44
- IsoDoc::HtmlFunction::MathvariantToPlain.new(docxml).convert
45
- end
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
46
47
 
47
- def htmlstylesheet(file)
48
- return if file.nil?
49
- file.open if file.is_a?(Tempfile)
50
- stylesheet = file.read
51
- xml = Nokogiri::XML("<style/>")
52
- xml.children.first << Nokogiri::XML::Comment.new(xml, "\n#{stylesheet}\n")
53
- file.close
54
- file.unlink if file.is_a?(Tempfile)
55
- xml.root.to_s
56
- end
48
+ def mathml(docxml)
49
+ IsoDoc::HtmlFunction::MathvariantToPlain.new(docxml).convert
50
+ end
57
51
 
58
- def htmlstyle(docxml)
59
- return docxml unless @htmlstylesheet
60
- title = docxml.at("//*[local-name() = 'head']/*[local-name() = 'title']")
61
- head = docxml.at("//*[local-name() = 'head']")
62
- head << htmlstylesheet(@htmlstylesheet)
63
- s = htmlstylesheet(@htmlstylesheet_override) and head << s
64
- docxml
65
- end
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
66
64
 
67
- def html_preface(docxml)
68
- html_cover(docxml) if @htmlcoverpage
69
- html_intro(docxml) if @htmlintropage
70
- docxml.at("//body") << mathjax(@openmathdelim, @closemathdelim)
71
- docxml.at("//body") << sourcecode_highlighter
72
- html_main(docxml)
73
- authority_cleanup(docxml)
74
- docxml
75
- end
65
+ def htmlstyle(docxml)
66
+ return docxml unless @htmlstylesheet
76
67
 
77
- def authority_cleanup1(docxml, klass)
78
- dest = docxml.at("//div[@id = 'boilerplate-#{klass}-destination']")
79
- auth = docxml.at("//div[@id = 'boilerplate-#{klass}' or @class = 'boilerplate-#{klass}']")
80
- auth&.xpath(".//h1[not(text())] | .//h2[not(text())]")&.each { |h| h.remove }
81
- auth&.xpath(".//h1 | .//h2")&.each { |h| h["class"] = "IntroTitle" }
82
- dest and auth and dest.replace(auth.remove)
83
- end
68
+ head = docxml.at("//*[local-name() = 'head']")
69
+ head << htmlstylesheet(@htmlstylesheet)
70
+ s = htmlstylesheet(@htmlstylesheet_override) and head << s
71
+ docxml
72
+ end
84
73
 
85
- def authority_cleanup(docxml)
86
- %w(copyright license legal feedback).each do |t|
87
- authority_cleanup1(docxml, t)
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
88
82
  end
89
- end
90
83
 
91
- def html_cover(docxml)
92
- doc = to_xhtml_fragment(File.read(@htmlcoverpage, encoding: "UTF-8"))
93
- d = docxml.at('//div[@class="title-section"]')
94
- # d.children.first.add_previous_sibling doc.to_xml(encoding: "US-ASCII")
95
- d.children.first.add_previous_sibling populate_template(doc.to_xml(encoding: "US-ASCII"), :html)
96
- end
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
97
92
 
98
- def html_intro(docxml)
99
- doc = to_xhtml_fragment(File.read(@htmlintropage, encoding: "UTF-8"))
100
- d = docxml.at('//div[@class="prefatory-section"]')
101
- # d.children.first.add_previous_sibling doc.to_xml(encoding: "US-ASCII")
102
- d.children.first.add_previous_sibling populate_template(doc.to_xml(encoding: "US-ASCII"), :html)
103
- end
93
+ def authority_cleanup(docxml)
94
+ %w(copyright license legal feedback).each do |t|
95
+ authority_cleanup1(docxml, t)
96
+ end
97
+ end
104
98
 
105
- def html_toc_entry(level, header)
106
- %(<li class="#{level}"><a href="##{header['id']}">\
107
- #{header_strip(header)}</a></li>)
108
- end
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
109
107
 
110
- def toclevel_classes
111
- (1..@htmlToClevels).reduce([]) { |m, i| m << "h#{i}" }
112
- end
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
113
116
 
114
- def toclevel
115
- ret = toclevel_classes.map { |l| "#{l}:not(:empty):not(.TermNum):not(.noTOC)" }
116
- <<~HEAD.freeze
117
- function toclevel() { return "#{ret.join(',')}";}
118
- HEAD
119
- end
117
+ def html_toc_entry(level, header)
118
+ %(<li class="#{level}"><a href="##{header['id']}">\
119
+ #{header_strip(header)}</a></li>)
120
+ end
120
121
 
121
- # needs to be same output as toclevel
122
- def html_toc(docxml)
123
- (idx = docxml.at("//div[@id = 'toc']")) or (return docxml)
124
- toc = "<ul>"
125
- path = toclevel_classes.map do |l|
126
- "//main//#{l}[not(@class = 'TermNum')][not(@class = 'noTOC')][text()]"
122
+ def toclevel_classes
123
+ (1..@htmlToClevels).reduce([]) { |m, i| m << "h#{i}" }
127
124
  end
128
- docxml.xpath(path.join(" | ")).each_with_index do |h, tocidx|
129
- h["id"] ||= "toc#{tocidx}"
130
- toc += html_toc_entry(h.name, h)
125
+
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
131
133
  end
132
- idx.children = "#{toc}</ul>"
133
- docxml
134
- end
135
134
 
136
- # presupposes that the image source is local
137
- def move_images(docxml)
138
- FileUtils.rm_rf tmpimagedir
139
- FileUtils.mkdir tmpimagedir
140
- docxml.xpath("//*[local-name() = 'img']").each do |i|
141
- i["width"], i["height"] = Html2Doc.image_resize(i, image_localfile(i),
142
- @maxheight, @maxwidth)
143
- next if /^data:/.match i["src"]
144
- @datauriimage ? datauri(i) : move_image1(i)
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
145
148
  end
146
- docxml
147
- end
148
149
 
149
- def datauri(i)
150
- type = i["src"].split(".")[-1]
151
- supertype = type == "xml" ? "application" : "image"
152
- bin = IO.binread(image_localfile(i))
153
- data = Base64.strict_encode64(bin)
154
- i["src"] = "data:#{supertype}/#{type};base64,#{data}"
155
- end
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"]
156
158
 
157
- def image_suffix(i)
158
- type = i["mimetype"]&.sub(%r{^[^/*]+/}, "")
159
- matched = /\.(?<suffix>[^. \r\n\t]+)$/.match i["src"]
160
- type and !type.empty? and return type
161
- !matched.nil? and matched[:suffix] and return matched[:suffix]
162
- "png"
163
- end
159
+ @datauriimage ? datauri(i) : move_image1(i)
160
+ end
161
+ docxml
162
+ end
164
163
 
165
- def move_image1(i)
166
- suffix = image_suffix(i)
167
- uuid = UUIDTools::UUID.random_create.to_s
168
- fname = "#{uuid}.#{suffix}"
169
- new_full_filename = File.join(tmpimagedir, fname)
170
- local_filename = image_localfile(i)
171
- FileUtils.cp local_filename, new_full_filename
172
- i["src"] = File.join(rel_tmpimagedir, fname)
173
- end
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
174
171
 
175
- def inject_script(doc)
176
- return doc unless @scripts
177
- scripts = File.read(@scripts, encoding: "UTF-8")
178
- a = doc.split(%r{</body>})
179
- a[0] + scripts + "</body>" + a[1]
180
- end
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
181
176
 
182
- def update_footnote_filter(fn, x, i, seen)
183
- if seen[fn.text]
184
- x.at("./sup").content = seen[fn.text][:num].to_s
185
- fn.remove unless x["href"] == seen[fn.text][:href]
186
- x["href"] = seen[fn.text][:href]
187
- else
188
- seen[fn.text] = { num: i, href: x["href"] }
189
- x.at("./sup").content = i.to_s
190
- i += 1
177
+ !matched.nil? and matched[:suffix] and return matched[:suffix]
178
+ "png"
191
179
  end
192
- [i, seen]
193
- end
194
180
 
195
- def html_footnote_filter(docxml)
196
- seen = {}
197
- i = 1
198
- docxml.xpath('//a[@class = "FootnoteRef"]').each do |x|
199
- fn = docxml.at(%<//*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
200
- i, seen = update_footnote_filter(fn, x, i, seen)
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)
201
189
  end
202
- docxml
203
- end
204
190
 
205
- def footnote_backlinks1(x, fn)
206
- xdup = x.dup
207
- xdup.remove["id"]
208
- if fn.elements.empty?
209
- fn.children.first.previous = xdup
210
- else
211
- fn.elements.first.children.first.previous = xdup
212
- end
213
- end
191
+ def inject_script(doc)
192
+ return doc unless @scripts
214
193
 
215
- def footnote_backlinks(docxml)
216
- seen = {}
217
- docxml.xpath('//a[@class = "FootnoteRef"]').each_with_index do |x, i|
218
- seen[x["href"]] and next or seen[x["href"]] = true
219
- fn = docxml.at(%<//*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
220
- footnote_backlinks1(x, fn)
221
- x["id"] ||= "fnref:#{i + 1}"
222
- fn.add_child "<a href='##{x['id']}'>&#x21A9;</a>"
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]}"
223
200
  end
224
- docxml
225
- end
226
201
 
227
- def footnote_format(docxml)
228
- docxml.xpath("//a[@class = 'FootnoteRef']/sup").each do |x|
229
- footnote_reference_format(x)
230
- end
231
- docxml.xpath("//a[@class = 'TableFootnoteRef'] | "\
232
- "//span[@class = 'TableFootnoteRef']").each do |x|
233
- table_footnote_reference_format(x)
202
+ def sourcecode_highlighter
203
+ '<script src="https://cdn.rawgit.com/google/code-prettify/master/'\
204
+ 'loader/run_prettify.js"></script>'
234
205
  end
235
- docxml
236
- end
237
206
 
238
- def sourcecode_highlighter
239
- '<script src="https://cdn.rawgit.com/google/code-prettify/master/'\
240
- 'loader/run_prettify.js"></script>'
241
- end
242
-
243
- MATHJAX_ADDR =
244
- "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js".freeze
245
- MATHJAX = <<~"MATHJAX".freeze
246
- <script type="text/x-mathjax-config">
247
- MathJax.Hub.Config({
248
- "HTML-CSS": { preferredFont: "STIX" },
249
- asciimath2jax: { delimiters: [['OPEN', 'CLOSE']] }
250
- });
251
- </script>
252
- <script src="#{MATHJAX_ADDR}?config=MML_HTMLorMML-full" async="async"></script>
253
- MATHJAX
254
-
255
- def mathjax(open, close)
256
- MATHJAX.gsub("OPEN", open).gsub("CLOSE", close)
257
- end
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
258
222
 
259
- def term_header(docxml)
260
- %w(h1 h2 h3 h4 h5 h6 h7 h8).each do |h|
261
- docxml.xpath("//p[@class = 'TermNum'][../#{h}]").each do |p|
262
- p.name = "h#{h[1].to_i + 1}"
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
263
228
  end
229
+ docxml
264
230
  end
265
- docxml
266
231
  end
267
232
  end
268
233
  end