isodoc 1.0.25 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +12 -2
  3. data/.github/workflows/ubuntu.yml +15 -3
  4. data/.github/workflows/windows.yml +12 -2
  5. data/isodoc.gemspec +2 -2
  6. data/lib/isodoc.rb +2 -0
  7. data/lib/isodoc/common.rb +0 -4
  8. data/lib/isodoc/convert.rb +18 -8
  9. data/lib/isodoc/function/blocks.rb +46 -52
  10. data/lib/isodoc/function/blocks_example_note.rb +108 -0
  11. data/lib/isodoc/function/cleanup.rb +14 -2
  12. data/lib/isodoc/function/i18n.rb +1 -0
  13. data/lib/isodoc/function/inline.rb +76 -82
  14. data/lib/isodoc/function/inline_simple.rb +72 -0
  15. data/lib/isodoc/function/lists.rb +12 -6
  16. data/lib/isodoc/function/references.rb +49 -53
  17. data/lib/isodoc/function/reqt.rb +14 -5
  18. data/lib/isodoc/function/section.rb +10 -12
  19. data/lib/isodoc/function/table.rb +4 -5
  20. data/lib/isodoc/function/terms.rb +3 -3
  21. data/lib/isodoc/function/to_word_html.rb +22 -12
  22. data/lib/isodoc/function/utils.rb +9 -3
  23. data/lib/isodoc/headlesshtml_convert.rb +12 -6
  24. data/lib/isodoc/html_convert.rb +7 -1
  25. data/lib/isodoc/html_function/footnotes.rb +1 -1
  26. data/lib/isodoc/html_function/html.rb +16 -1
  27. data/lib/isodoc/html_function/postprocess.rb +6 -5
  28. data/lib/isodoc/metadata.rb +6 -0
  29. data/lib/isodoc/metadata_date.rb +19 -7
  30. data/lib/isodoc/pdf_convert.rb +13 -6
  31. data/lib/isodoc/presentation_xml_convert.rb +29 -0
  32. data/lib/isodoc/version.rb +1 -1
  33. data/lib/isodoc/word_convert.rb +7 -1
  34. data/lib/isodoc/word_function/body.rb +14 -48
  35. data/lib/isodoc/word_function/footnotes.rb +1 -1
  36. data/lib/isodoc/word_function/inline.rb +75 -0
  37. data/lib/isodoc/word_function/postprocess.rb +1 -0
  38. data/lib/isodoc/word_function/table.rb +3 -3
  39. data/lib/isodoc/xref.rb +59 -0
  40. data/lib/isodoc/{function → xref}/xref_anchor.rb +10 -21
  41. data/lib/isodoc/xref/xref_counter.rb +74 -0
  42. data/lib/isodoc/{function → xref}/xref_gen.rb +11 -23
  43. data/lib/isodoc/{function → xref}/xref_gen_seq.rb +41 -32
  44. data/lib/isodoc/{function → xref}/xref_sect_gen.rb +54 -40
  45. data/lib/isodoc/xslfo_convert.rb +21 -4
  46. data/spec/assets/i18n.yaml +4 -1
  47. data/spec/assets/odf.emf +0 -0
  48. data/spec/assets/odf.svg +4 -0
  49. data/spec/assets/odf1.svg +4 -0
  50. data/spec/isodoc/blocks_spec.rb +271 -48
  51. data/spec/isodoc/cleanup_spec.rb +139 -17
  52. data/spec/isodoc/footnotes_spec.rb +20 -5
  53. data/spec/isodoc/i18n_spec.rb +8 -8
  54. data/spec/isodoc/inline_spec.rb +299 -4
  55. data/spec/isodoc/lists_spec.rb +8 -8
  56. data/spec/isodoc/metadata_spec.rb +110 -3
  57. data/spec/isodoc/postproc_spec.rb +10 -14
  58. data/spec/isodoc/presentation_xml_spec.rb +20 -0
  59. data/spec/isodoc/ref_spec.rb +121 -52
  60. data/spec/isodoc/section_spec.rb +232 -208
  61. data/spec/isodoc/table_spec.rb +28 -28
  62. data/spec/isodoc/terms_spec.rb +7 -7
  63. data/spec/isodoc/xref_spec.rb +206 -59
  64. metadata +24 -17
  65. data/lib/isodoc/function/blocks_example.rb +0 -53
  66. data/lib/isodoc/function/xref_counter.rb +0 -50
@@ -2,7 +2,7 @@ module IsoDoc::Function
2
2
  module Blocks
3
3
  def recommendation_labels(node)
4
4
  [node.at(ns("./label")), node.at(ns("./title")),
5
- anchor(node['id'], :label, false)]
5
+ @xrefs.anchor(node['id'], :label, false)]
6
6
  end
7
7
 
8
8
  def recommendation_name(node, out, type)
@@ -60,8 +60,12 @@ module IsoDoc::Function
60
60
  %w(label title subject classification tag value inherit).include? n.name
61
61
  end
62
62
 
63
+ def reqt_attrs(node, klass)
64
+ attr_code(class: klass, id: node["id"], style: keep_style(node))
65
+ end
66
+
63
67
  def recommendation_parse(node, out)
64
- out.div **{ class: "recommend" } do |t|
68
+ out.div **reqt_attrs(node, "recommend") do |t|
65
69
  recommendation_name(node, t, @recommendation_lbl)
66
70
  recommendation_attributes(node, out)
67
71
  node.children.each do |n|
@@ -71,7 +75,7 @@ module IsoDoc::Function
71
75
  end
72
76
 
73
77
  def requirement_parse(node, out)
74
- out.div **{ class: "require" } do |t|
78
+ out.div **reqt_attrs(node, "require") do |t|
75
79
  recommendation_name(node, t, @requirement_lbl)
76
80
  recommendation_attributes(node, out)
77
81
  node.children.each do |n|
@@ -81,7 +85,7 @@ module IsoDoc::Function
81
85
  end
82
86
 
83
87
  def permission_parse(node, out)
84
- out.div **{ class: "permission" } do |t|
88
+ out.div **reqt_attrs(node, "permission") do |t|
85
89
  recommendation_name(node, t, @permission_lbl)
86
90
  recommendation_attributes(node, out)
87
91
  node.children.each do |n|
@@ -90,9 +94,14 @@ module IsoDoc::Function
90
94
  end
91
95
  end
92
96
 
97
+ def reqt_component_attrs(node)
98
+ attr_code(class: "requirement-" + node.name,
99
+ style: keep_style(node))
100
+ end
101
+
93
102
  def requirement_component_parse(node, out)
94
103
  return if node["exclude"] == "true"
95
- out.div **{ class: "requirement-" + node.name } do |div|
104
+ out.div **reqt_component_attrs(node) do |div|
96
105
  node.children.each do |n|
97
106
  parse(n, div)
98
107
  end
@@ -11,11 +11,12 @@ module IsoDoc::Function
11
11
  def inline_header_title(out, node, c1)
12
12
  out.span **{ class: "zzMoveToFollowing" } do |s|
13
13
  s.b do |b|
14
- if anchor(node['id'], :label, false) && !@suppressheadingnumbers
15
- b << "#{anchor(node['id'], :label)}#{clausedelim}"
14
+ if @xrefs.anchor(node['id'], :label, false) && !@suppressheadingnumbers
15
+ b << "#{@xrefs.anchor(node['id'], :label)}#{clausedelim}"
16
16
  clausedelimspace(out)
17
17
  end
18
18
  c1&.children&.each { |c2| parse(c2, b) }
19
+ clausedelimspace(out) if /\S/.match(c1&.text)
19
20
  end
20
21
  end
21
22
  end
@@ -25,8 +26,8 @@ module IsoDoc::Function
25
26
  if node["inline-header"] == "true"
26
27
  inline_header_title(out, node, c1)
27
28
  else
28
- div.send "h#{anchor(node['id'], :level, false) || '1'}" do |h|
29
- lbl = anchor(node['id'], :label, false)
29
+ div.send "h#{@xrefs.anchor(node['id'], :level, false) || '1'}" do |h|
30
+ lbl = @xrefs.anchor(node['id'], :label, false)
30
31
  h << "#{lbl}#{clausedelim}" if lbl && !@suppressheadingnumbers
31
32
  clausedelimspace(out) if lbl && !@suppressheadingnumbers
32
33
  c1&.children&.each { |c2| parse(c2, h) }
@@ -57,14 +58,10 @@ module IsoDoc::Function
57
58
  div.parent.at(".//h1")
58
59
  end
59
60
 
60
- MIDDLE_CLAUSE =
61
- "//clause[parent::sections][not(xmlns:title = 'Scope')]"\
62
- "[not(descendant::terms)]".freeze
63
-
64
61
  def clause(isoxml, out)
65
- isoxml.xpath(ns(self.class::MIDDLE_CLAUSE)).each do |c|
62
+ isoxml.xpath(ns(middle_clause)).each do |c|
66
63
  out.div **attr_code(id: c["id"]) do |s|
67
- clause_name(anchor(c['id'], :label),
64
+ clause_name(@xrefs.anchor(c['id'], :label),
68
65
  c&.at(ns("./title")), s, nil)
69
66
  c.elements.reject { |c1| c1.name == "title" }.each do |c1|
70
67
  parse(c1, s)
@@ -75,7 +72,7 @@ module IsoDoc::Function
75
72
 
76
73
  def annex_name(annex, name, div)
77
74
  div.h1 **{ class: "Annex" } do |t|
78
- t << "#{anchor(annex['id'], :label)}<br/><br/>"
75
+ t << "#{@xrefs.anchor(annex['id'], :label)}<br/><br/>"
79
76
  t.b do |b|
80
77
  name&.children&.each { |c2| parse(c2, b) }
81
78
  end
@@ -207,7 +204,8 @@ module IsoDoc::Function
207
204
 
208
205
  def preface(isoxml, out)
209
206
  title_attr = { class: "IntroTitle" }
210
- isoxml.xpath(ns("//preface/clause")).each do |f|
207
+ isoxml.xpath(ns("//preface/clause | //preface/terms | //preface/definitions | "\
208
+ "//preface/references")).each do |f|
211
209
  page_break(out)
212
210
  out.div **{ class: "Section3", id: f["id"] } do |div|
213
211
  clause_name(nil, f&.at(ns("./title")), div, title_attr)
@@ -3,7 +3,7 @@ module IsoDoc::Function
3
3
 
4
4
  def table_title_parse(node, out)
5
5
  name = node.at(ns("./name"))
6
- lbl = anchor(node['id'], :label, false)
6
+ lbl = @xrefs.anchor(node['id'], :label, false)
7
7
  lbl = nil if labelled_ancestor(node)
8
8
  return if name.nil? && lbl.nil?
9
9
  out.p **{ class: "TableTitle", style: "text-align:center;" } do |p|
@@ -44,12 +44,12 @@ module IsoDoc::Function
44
44
  end
45
45
  end
46
46
 
47
- def make_table_attr(node)
47
+ def table_attrs(node)
48
48
  width = node["width"] ? "width:#{node['width']};" : nil
49
49
  attr_code(
50
50
  id: node["id"],
51
51
  class: "MsoISOTable",
52
- style: "border-width:1px;border-spacing:0;#{width}",
52
+ style: "border-width:1px;border-spacing:0;#{width}#{keep_style(node)}",
53
53
  title: node["alt"]
54
54
  )
55
55
  end
@@ -66,7 +66,7 @@ module IsoDoc::Function
66
66
  def table_parse(node, out)
67
67
  @in_table = true
68
68
  table_title_parse(node, out)
69
- out.table **make_table_attr(node) do |t|
69
+ out.table **table_attrs(node) do |t|
70
70
  tcaption(node, t)
71
71
  thead_parse(node, t)
72
72
  tbody_parse(node, t)
@@ -91,7 +91,6 @@ module IsoDoc::Function
91
91
  style += <<~STYLE
92
92
  border-top:#{row.zero? ? "#{SW} 1.5pt;" : 'none;'}
93
93
  border-bottom:#{SW} #{rowmax == totalrows ? '1.5' : '1.0'}pt;
94
- padding:0;
95
94
  STYLE
96
95
  header and scope = (td["colspan"] ? "colgroup" : "col")
97
96
  !header and td.name == "th" and scope =
@@ -40,10 +40,10 @@ module IsoDoc::Function
40
40
  end
41
41
 
42
42
  def termnote_parse(node, out)
43
- out.div **{ class: "Note" } do |div|
43
+ out.div **note_attrs(node) do |div|
44
44
  first = node.first_element_child
45
45
  div.p do |p|
46
- p << "#{anchor(node['id'], :label) || '???'}: "
46
+ p << "#{@xrefs.anchor(node['id'], :label) || '???'}: "
47
47
  para_then_remainder(first, node, p, div)
48
48
  end
49
49
  end
@@ -59,7 +59,7 @@ module IsoDoc::Function
59
59
 
60
60
  def termdef_parse(node, out)
61
61
  out.p **{ class: "TermNum", id: node["id"] } do |p|
62
- p << "#{get_anchors[node["id"]][:label]}#{clausedelim}"
62
+ p << "#{@xrefs.get[node["id"]][:label]}#{clausedelim}"
63
63
  end
64
64
  set_termdomain("")
65
65
  node.children.each { |n| parse(n, out) }
@@ -21,7 +21,7 @@ module IsoDoc::Function
21
21
  filename = filepath.sub_ext('').to_s
22
22
  dir = "#{filename}_files"
23
23
  unless debug
24
- Dir.mkdir(dir) unless File.exists?(dir)
24
+ Dir.mkdir(dir, 0777) unless File.exists?(dir)
25
25
  FileUtils.rm_rf "#{dir}/*"
26
26
  end
27
27
  @filename = filename
@@ -79,7 +79,7 @@ module IsoDoc::Function
79
79
 
80
80
  def make_body3(body, docxml)
81
81
  body.div **{ class: "main-section" } do |div3|
82
- boilerplate docxml, div3
82
+ boilerplate docxml, div3
83
83
  abstract docxml, div3
84
84
  foreword docxml, div3
85
85
  introduction docxml, div3
@@ -102,6 +102,7 @@ module IsoDoc::Function
102
102
  @meta.relations isoxml, out
103
103
  @meta.version isoxml, out
104
104
  @meta.url isoxml, out
105
+ @meta.keywords isoxml, out
105
106
  @meta.get
106
107
  end
107
108
 
@@ -109,8 +110,15 @@ module IsoDoc::Function
109
110
  out.p(**{ class: "zzSTDTitle1" }) { |p| p << @meta.get[:doctitle] }
110
111
  end
111
112
 
113
+ def middle_admonitions(isoxml, out)
114
+ isoxml.xpath(ns("//sections/note | //sections/admonition")).each do |x|
115
+ parse(x, out)
116
+ end
117
+ end
118
+
112
119
  def middle(isoxml, out)
113
120
  middle_title(out)
121
+ middle_admonitions(isoxml, out)
114
122
  i = scope isoxml, out, 0
115
123
  i = norm_ref isoxml, out, i
116
124
  i = terms_defs isoxml, out, i
@@ -120,20 +128,20 @@ module IsoDoc::Function
120
128
  bibliography isoxml, out
121
129
  end
122
130
 
123
- def boilerplate(node, out)
124
- boilerplate = node.at(ns("//boilerplate")) or return
125
- out.div **{class: "authority"} do |s|
126
- boilerplate.children.each do |n|
127
- if n.name == "title"
128
- s.h1 do |h|
129
- n.children.each { |nn| parse(nn, h) }
130
- end
131
- else
132
- parse(n, s)
131
+ def boilerplate(node, out)
132
+ boilerplate = node.at(ns("//boilerplate")) or return
133
+ out.div **{class: "authority"} do |s|
134
+ boilerplate.children.each do |n|
135
+ if n.name == "title"
136
+ s.h1 do |h|
137
+ n.children.each { |nn| parse(nn, h) }
133
138
  end
139
+ else
140
+ parse(n, s)
134
141
  end
135
142
  end
136
143
  end
144
+ end
137
145
 
138
146
  def parse(node, out)
139
147
  if node.text?
@@ -210,6 +218,8 @@ module IsoDoc::Function
210
218
  when "license-statement" then license_parse(node, out)
211
219
  when "legal-statement" then legal_parse(node, out)
212
220
  when "feedback-statement" then feedback_parse(node, out)
221
+ when "passthrough" then passthrough_parse(node, out)
222
+ when "variant" then variant_parse(node, out)
213
223
  else
214
224
  error_parse(node, out)
215
225
  end
@@ -49,7 +49,12 @@ module IsoDoc::Function
49
49
  /^(\&[^ \t\r\n#;]+;)/.match(t) ?
50
50
  HTMLEntities.new.encode(HTMLEntities.new.decode(t), :hexadecimal) : t
51
51
  end.join("")
52
- Nokogiri::XML.parse(xml)
52
+ begin
53
+ Nokogiri::XML.parse(xml) { |config| config.strict }
54
+ rescue Nokogiri::XML::SyntaxError => e
55
+ File.open("#{@filename}.#{@format}.err", "w:UTF-8") { |f| f.write xml }
56
+ abort "Malformed Output XML for #{@format}: #{e} (see #{@filename}.#{@format}.err)"
57
+ end
53
58
  end
54
59
 
55
60
  def to_xhtml_fragment(xml)
@@ -116,7 +121,7 @@ module IsoDoc::Function
116
121
  h1.traverse do |x|
117
122
  x.replace(" ") if x.name == "span" && /mso-tab-count/.match(x["style"])
118
123
  x.remove if x.name == "span" && x["class"] == "MsoCommentReference"
119
- x.remove if x.name == "a" && x["epub:type"] == "footnote"
124
+ x.remove if x.name == "a" && x["class"] == "FootnoteRef"
120
125
  x.remove if x.name == "span" && /mso-bookmark/.match(x["style"])
121
126
  x.replace(x.children) if x.name == "a"
122
127
  end
@@ -142,7 +147,7 @@ module IsoDoc::Function
142
147
  end
143
148
 
144
149
  def populate_template(docxml, _format = nil)
145
- meta = @meta.get.merge(@labels || {})
150
+ meta = @meta.get.merge(@labels || {}).merge(@meta.labels || {})
146
151
  template = liquid(docxml)
147
152
  template.render(meta.map { |k, v| [k.to_s, empty2nil(v)] }.to_h).
148
153
  gsub('&lt;', '&#x3c;').gsub('&gt;', '&#x3e;').gsub('&amp;', '&#x26;')
@@ -150,6 +155,7 @@ module IsoDoc::Function
150
155
 
151
156
  def save_dataimage(uri, relative_dir = true)
152
157
  %r{^data:image/(?<imgtype>[^;]+);base64,(?<imgdata>.+)$} =~ uri
158
+ imgtype.sub!(/\+[a-z0-9]+$/, "") # svg+xml
153
159
  imgtype = "png" unless /^[a-z0-9]+$/.match imgtype
154
160
  Tempfile.open(["image", ".#{imgtype}"]) do |f|
155
161
  f.binmode
@@ -14,15 +14,21 @@ module IsoDoc
14
14
  "_headlessimages"
15
15
  end
16
16
 
17
- def convert(filename, file = nil, debug = false)
18
- file = File.read(filename, encoding: "utf-8") if file.nil?
17
+ def initialize(options)
18
+ @format = :html
19
+ @suffix = "headless.html"
20
+ super
21
+ end
22
+
23
+ def convert(input_filename, file = nil, debug = false, output_filename = nil)
24
+ file = File.read(input_filename, encoding: "utf-8") if file.nil?
19
25
  @openmathdelim, @closemathdelim = extract_delims(file)
20
- docxml, outname_html, dir = convert_init(file, filename, debug)
21
- result = convert1(docxml, outname_html, dir)
26
+ docxml, filename, dir = convert_init(file, input_filename, debug)
27
+ result = convert1(docxml, filename, dir)
22
28
  return result if debug
23
- postprocess(result, filename + ".tmp", dir)
29
+ postprocess(result, filename + ".tmp.html", dir)
24
30
  FileUtils.rm_rf dir
25
- strip_head(filename + ".tmp.html", outname_html + ".headless.html")
31
+ strip_head(filename + ".tmp.html", output_filename || "#{filename}.#{@suffix}")
26
32
  FileUtils.rm_rf ["#{filename}.tmp.html", tmpimagedir]
27
33
  end
28
34
 
@@ -14,7 +14,13 @@ module IsoDoc
14
14
  "_htmlimages"
15
15
  end
16
16
 
17
- def convert(filename, file = nil, debug = false)
17
+ def initialize(options)
18
+ @format = :html
19
+ @suffix = "html"
20
+ super
21
+ end
22
+
23
+ def convert(filename, file = nil, debug = false, output_filename = nil)
18
24
  ret = super
19
25
  Dir.exists?(tmpimagedir) and Dir["#{tmpimagedir}/*"].empty? and
20
26
  FileUtils.rm_r tmpimagedir
@@ -65,7 +65,7 @@ module IsoDoc::HtmlFunction
65
65
  return table_footnote_parse(node, out) if (@in_table || @in_figure) &&
66
66
  !node.ancestors.map {|m| m.name }.include?("name")
67
67
  fn = node["reference"] || UUIDTools::UUID.random_create.to_s
68
- attrs = { "epub:type": "footnote", rel: "footnote", href: "#fn:#{fn}" }
68
+ attrs = { class: "FootnoteRef", href: "#fn:#{fn}" }
69
69
  out.a **attrs do |a|
70
70
  a.sup { |sup| sup << fn }
71
71
  end
@@ -3,6 +3,18 @@ require "base64"
3
3
 
4
4
  module IsoDoc::HtmlFunction
5
5
  module Html
6
+ def convert1(docxml, filename, dir)
7
+ @xrefs.parse docxml
8
+ noko do |xml|
9
+ xml.html **{ lang: "#{@lang}" } do |html|
10
+ info docxml, nil
11
+ populate_css()
12
+ html.head { |head| define_head head, filename, dir }
13
+ make_body(html, docxml)
14
+ end
15
+ end.join("\n")
16
+ end
17
+
6
18
  def make_body1(body, _docxml)
7
19
  body.div **{ class: "title-section" } do |div1|
8
20
  div1.p { |p| p << "&nbsp;" } # placeholder
@@ -90,12 +102,15 @@ module IsoDoc::HtmlFunction
90
102
  def sourcecode_parse(node, out)
91
103
  name = node.at(ns("./name"))
92
104
  class1 = "prettyprint #{sourcecodelang(node&.at(ns('./@lang'))&.value)}"
93
- out.pre **attr_code(id: node["id"], class: class1) do |div|
105
+ out.pre **sourcecode_attrs(node).merge(class: class1) do |div|
94
106
  @sourcecode = true
95
107
  node.children.each { |n| parse(n, div) unless n.name == "name" }
96
108
  @sourcecode = false
97
109
  end
98
110
  sourcecode_name_parse(node, out, name)
99
111
  end
112
+
113
+ def table_long_strings_cleanup(docxml)
114
+ end
100
115
  end
101
116
  end
@@ -18,7 +18,7 @@ module IsoDoc::HtmlFunction
18
18
  #result = populate_template(result, :html)
19
19
  result = from_xhtml(move_images(to_xhtml(result)))
20
20
  result = html5(script_cdata(inject_script(result)))
21
- File.open("#{filename}.html", "w:UTF-8") { |f| f.write(result) }
21
+ File.open(filename, "w:UTF-8") { |f| f.write(result) }
22
22
  end
23
23
 
24
24
  def html5(doc)
@@ -159,7 +159,8 @@ module IsoDoc::HtmlFunction
159
159
  def inject_script(doc)
160
160
  return doc unless @scripts
161
161
  scripts = File.read(@scripts, encoding: "UTF-8")
162
- doc.sub("</body>", scripts + "\n</body>")
162
+ a = doc.split(%r{</body>})
163
+ a[0] + scripts + "</body>" + a[1]
163
164
  end
164
165
 
165
166
  def update_footnote_filter(fn, x, i, seen)
@@ -178,7 +179,7 @@ module IsoDoc::HtmlFunction
178
179
  def html_footnote_filter(docxml)
179
180
  seen = {}
180
181
  i = 1
181
- docxml.xpath('//a[@epub:type = "footnote"]').each do |x|
182
+ docxml.xpath('//a[@class = "FootnoteRef"]').each do |x|
182
183
  fn = docxml.at(%<//*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
183
184
  i, seen = update_footnote_filter(fn, x, i, seen)
184
185
  end
@@ -187,7 +188,7 @@ module IsoDoc::HtmlFunction
187
188
 
188
189
  def footnote_backlinks(docxml)
189
190
  seen = {}
190
- docxml.xpath('//a[@epub:type = "footnote"]').each_with_index do |x, i|
191
+ docxml.xpath('//a[@class = "FootnoteRef"]').each_with_index do |x, i|
191
192
  seen[x["href"]] and next or seen[x["href"]] = true
192
193
  fn = docxml.at(%<//*[@id = '#{x['href'].sub(/^#/, '')}']>) || next
193
194
  xdup = x.dup
@@ -200,7 +201,7 @@ module IsoDoc::HtmlFunction
200
201
  end
201
202
 
202
203
  def footnote_format(docxml)
203
- docxml.xpath("//a[@epub:type = 'footnote']/sup").each do |x|
204
+ docxml.xpath("//a[@class = 'FootnoteRef']/sup").each do |x|
204
205
  footnote_reference_format(x)
205
206
  end
206
207
  docxml.xpath("//a[@class = 'TableFootnoteRef'] | "\
@@ -218,5 +218,11 @@ module IsoDoc
218
218
  a = xml.at(ns("//bibdata/uri[@type = 'pdf']")) and set(:pdf, a.text)
219
219
  a = xml.at(ns("//bibdata/uri[@type = 'doc']")) and set(:doc, a.text)
220
220
  end
221
+
222
+ def keywords(isoxml, _out)
223
+ ret = []
224
+ isoxml.xpath(ns("//bibdata/keyword")).each { |kw| ret << kw.text }
225
+ set(:keywords, ret)
226
+ end
221
227
  end
222
228
  end
@@ -14,14 +14,26 @@ module IsoDoc
14
14
  "10": @labels["month_october"],
15
15
  "11": @labels["month_november"],
16
16
  "12": @labels["month_december"],
17
- }
17
+ }
18
18
  end
19
19
 
20
- def monthyr(isodate)
21
- m = /(?<yr>\d\d\d\d)-(?<mo>\d\d)/.match isodate
22
- return isodate unless m && m[:yr] && m[:mo]
23
- IsoDoc::Function::I18n::l10n("#{months[m[:mo].to_sym]} #{m[:yr]}",
24
- @lang, @script)
25
- end
20
+ def monthyr(isodate)
21
+ m = /(?<yr>\d\d\d\d)-(?<mo>\d\d)/.match isodate
22
+ return isodate unless m && m[:yr] && m[:mo]
23
+ IsoDoc::Function::I18n::l10n("#{months[m[:mo].to_sym]} #{m[:yr]}",
24
+ @lang, @script)
25
+ end
26
+
27
+ def MMMddyyyy(isodate)
28
+ return nil if isodate.nil?
29
+ arr = isodate.split("-")
30
+ date = if arr.size == 1 and (/^\d+$/.match isodate)
31
+ Date.new(*arr.map(&:to_i)).strftime("%Y")
32
+ elsif arr.size == 2
33
+ Date.new(*arr.map(&:to_i)).strftime("%B %Y")
34
+ else
35
+ Date.parse(isodate).strftime("%B %d, %Y")
36
+ end
37
+ end
26
38
  end
27
39
  end