isodoc 3.4.7 → 3.4.8
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/lib/isodoc/base_style/reset.scss +1 -1
- data/lib/isodoc/css.rb +6 -8
- data/lib/isodoc/css_border_parser.rb +13 -5
- data/lib/isodoc/function/blocks.rb +9 -3
- data/lib/isodoc/function/cleanup.rb +8 -5
- data/lib/isodoc/function/lists.rb +13 -3
- data/lib/isodoc/function/section_titles.rb +3 -1
- data/lib/isodoc/function/utils.rb +35 -51
- data/lib/isodoc/function/utils_img.rb +55 -0
- data/lib/isodoc/gem_tasks.rb +9 -9
- data/lib/isodoc/html_function/postprocess.rb +2 -2
- data/lib/isodoc/html_function/postprocess_cover.rb +12 -9
- data/lib/isodoc/presentation_function/annex.rb +97 -0
- data/lib/isodoc/presentation_function/autonum.rb +7 -6
- data/lib/isodoc/presentation_function/block.rb +26 -11
- data/lib/isodoc/presentation_function/footnotes.rb +1 -1
- data/lib/isodoc/presentation_function/image.rb +1 -1
- data/lib/isodoc/presentation_function/list_to_table.rb +250 -0
- data/lib/isodoc/presentation_function/math.rb +10 -32
- data/lib/isodoc/presentation_function/section.rb +7 -32
- data/lib/isodoc/presentation_function/xrefs.rb +1 -1
- data/lib/isodoc/presentation_xml_convert.rb +7 -4
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/table.rb +7 -4
- data/lib/isodoc/xref/xref_counter.rb +36 -3
- data/lib/isodoc/xref/xref_gen.rb +23 -14
- data/lib/isodoc/xref/xref_sect_gen.rb +21 -7
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0934e0c0ea24dd7c91fe682c72855d5cd95c0dbf13bdedf43af86412c304885
|
|
4
|
+
data.tar.gz: 16ee08583e192dafd2d30ec886ef9eefd1703cefbeeefec2a22f042485721d2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2cfd83b6f9acc5496e2155cb52b4a4fc9e55d11ef8ba7b54405ed741de74e88b21cfd67b90def1e4515f397291c4eb6b3d7c133a8ff9b647c97b9246be041dd1
|
|
7
|
+
data.tar.gz: b873292c72723ae4359bf3aee7dafaf039f1d6bdc60df110c179b8150274e41c737122a6980a02819b7ca3b332a2e2d9d997e875822dc0ba4b90dd61f1d109e8
|
data/lib/isodoc/css.rb
CHANGED
|
@@ -75,31 +75,29 @@ module IsoDoc
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def convert_scss(filename, stylesheet, stripwordcss)
|
|
78
|
-
|
|
78
|
+
load_paths = scss_load_paths(filename)
|
|
79
79
|
Dir.mktmpdir do |dir|
|
|
80
80
|
variables_file_path = File.join(dir, "variables.scss")
|
|
81
81
|
File.write(variables_file_path, scss_fontheader(stripwordcss))
|
|
82
|
-
SassC.load_paths << dir
|
|
83
82
|
modified_stylesheet = %( @use "variables" as *;\n#{stylesheet})
|
|
84
|
-
compile_scss(modified_stylesheet)
|
|
83
|
+
compile_scss(modified_stylesheet, load_paths + [dir])
|
|
85
84
|
end
|
|
86
85
|
end
|
|
87
86
|
|
|
88
|
-
def compile_scss(modified_stylesheet)
|
|
87
|
+
def compile_scss(modified_stylesheet, load_paths = [])
|
|
89
88
|
SassC::Engine
|
|
90
89
|
.new(modified_stylesheet, quiet_deps: true, syntax: :scss,
|
|
90
|
+
load_paths: load_paths,
|
|
91
91
|
importer: SasscImporter)
|
|
92
92
|
.render.gsub(/__WORD__/, "")
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
def
|
|
95
|
+
def scss_load_paths(filename)
|
|
96
96
|
require "sassc-embedded"
|
|
97
97
|
require "isodoc/sassc_importer"
|
|
98
98
|
[File.join(Gem.loaded_specs["isodoc"].full_gem_path,
|
|
99
99
|
"lib", "isodoc"),
|
|
100
|
-
File.dirname(filename)]
|
|
101
|
-
SassC.load_paths << name
|
|
102
|
-
end
|
|
100
|
+
File.dirname(filename)]
|
|
103
101
|
end
|
|
104
102
|
|
|
105
103
|
# stripwordcss if HTML stylesheet, !stripwordcss if DOC stylesheet
|
|
@@ -90,11 +90,17 @@ module IsoDoc
|
|
|
90
90
|
# Extract rule sets from CSS string
|
|
91
91
|
def extract_rule_sets(css_string)
|
|
92
92
|
rule_sets = {}
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
# Safe C-style comment removal without polynomial backtracking:
|
|
94
|
+
# /\*[^*]*(?:\*+[^*/][^*]*)*\*+\/ matches /* ... */ in linear time
|
|
95
|
+
# by keeping the "star runs not followed by /" separate from non-star
|
|
96
|
+
# content, so no position can be matched by multiple paths.
|
|
97
|
+
css_string = css_string.gsub(%r{/\*[^*]*(?:\*+[^*/][^*]*)*\*+/}, "")
|
|
98
|
+
# [^{}]+ for selector and [^{}]* for declarations: both exclude braces,
|
|
99
|
+
# making the grouping unambiguous without the m flag.
|
|
100
|
+
css_string.scan(/([^{}]+)\{([^{}]*)\}/) do |selector, declarations|
|
|
95
101
|
selector = selector.strip
|
|
96
102
|
declarations_hash = {} # Extract declarations
|
|
97
|
-
declarations.scan(/([^:;]+):([^;]
|
|
103
|
+
declarations.scan(/([^:;]+):([^;]*);?/) do |property, value|
|
|
98
104
|
declarations_hash[property.strip] = value.strip
|
|
99
105
|
end
|
|
100
106
|
rule_sets[selector] = declarations_hash
|
|
@@ -149,8 +155,10 @@ module IsoDoc
|
|
|
149
155
|
"color" => DEFAULT_VALUES["color"],
|
|
150
156
|
}
|
|
151
157
|
value.split(/\s+/).each do |part|
|
|
152
|
-
if width?(part)
|
|
153
|
-
|
|
158
|
+
if width?(part)
|
|
159
|
+
components["width"] = part
|
|
160
|
+
elsif style?(part)
|
|
161
|
+
components["style"] = part
|
|
154
162
|
elsif color?(part)
|
|
155
163
|
components["color"] = convert_color_to_rgb(part)
|
|
156
164
|
end
|
|
@@ -150,7 +150,7 @@ module IsoDoc
|
|
|
150
150
|
classtype = nil
|
|
151
151
|
classtype = "MsoCommentText" if in_comment
|
|
152
152
|
node["type"] == "floating-title" and
|
|
153
|
-
classtype = "h#{node['depth']}"
|
|
153
|
+
classtype = "h#{node['depth'] || '1'}"
|
|
154
154
|
classtype ||= node["class"]
|
|
155
155
|
classtype
|
|
156
156
|
end
|
|
@@ -180,13 +180,19 @@ module IsoDoc
|
|
|
180
180
|
end
|
|
181
181
|
|
|
182
182
|
def quote_parse(node, out)
|
|
183
|
-
attrs =
|
|
184
|
-
attrs[:class] = "Quote"
|
|
183
|
+
attrs = quote_attrs(node)
|
|
185
184
|
out.div(**attr_code(attrs)) do |p|
|
|
186
185
|
node.children.each { |n| parse(n, p) unless n.name == "source" }
|
|
187
186
|
end
|
|
188
187
|
end
|
|
189
188
|
|
|
189
|
+
def quote_attrs(node)
|
|
190
|
+
ret = para_attrs(node).merge(class: "Quote")
|
|
191
|
+
node["type"] == "newcontent" and
|
|
192
|
+
ret[:class] += " AmendNewcontent"
|
|
193
|
+
ret
|
|
194
|
+
end
|
|
195
|
+
|
|
190
196
|
def passthrough_parse(node, out)
|
|
191
197
|
node["formats"] &&
|
|
192
198
|
!(node["formats"].split.include? @format.to_s) and return
|
|
@@ -8,8 +8,8 @@ module IsoDoc
|
|
|
8
8
|
def passthrough_cleanup(docxml)
|
|
9
9
|
docxml.split(%r{(<passthrough>|</passthrough>)}).each_slice(4)
|
|
10
10
|
.map do |a|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
a.size > 2 and a[2] = HTMLEntities.new.decode(a[2])
|
|
12
|
+
[a[0], a[2]]
|
|
13
13
|
end.join
|
|
14
14
|
end
|
|
15
15
|
|
|
@@ -84,8 +84,11 @@ module IsoDoc
|
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def remove_bottom_border(cell)
|
|
87
|
+
# [^;]* (not +): the preceding property name is the unambiguous
|
|
88
|
+
# delimiter, so zero-or-more is equivalent and avoids polynomial
|
|
89
|
+
# backtracking on the value portion.
|
|
87
90
|
cell["style"] =
|
|
88
|
-
cell["style"].gsub(/border-bottom:[^;]
|
|
91
|
+
cell["style"].gsub(/border-bottom:[^;]*;/, "border-bottom:0pt;")
|
|
89
92
|
end
|
|
90
93
|
|
|
91
94
|
def table_get_or_make_tfoot(table)
|
|
@@ -112,7 +115,7 @@ module IsoDoc
|
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
TABLENOTE_CSS = "div[@class = 'Note' or @class = 'BlockSource' " \
|
|
115
|
-
|
|
118
|
+
"or @class = 'TableFootnote' or @class = 'figdl' or @class = 'key']"
|
|
116
119
|
.freeze
|
|
117
120
|
|
|
118
121
|
def table_note_cleanup(docxml)
|
|
@@ -121,7 +124,7 @@ module IsoDoc
|
|
|
121
124
|
insert_here = new_fullcolspan_row(t, tfoot)
|
|
122
125
|
t.xpath("dl | p[@class = 'ListTitle'] | #{TABLENOTE_CSS}")
|
|
123
126
|
.each do |d|
|
|
124
|
-
|
|
127
|
+
d.parent = insert_here
|
|
125
128
|
end
|
|
126
129
|
end
|
|
127
130
|
end
|
|
@@ -14,6 +14,7 @@ module IsoDoc
|
|
|
14
14
|
|
|
15
15
|
def ul_parse(node, out)
|
|
16
16
|
out.div(**attr_code(class: "ul_wrap")) do |div|
|
|
17
|
+
n = node.at(ns("./fmt-ul")) and return fmt_ul_parse(node, n, out)
|
|
17
18
|
list_title_parse(node, div)
|
|
18
19
|
div.ul(**attr_code(ul_attrs(node))) do |ul|
|
|
19
20
|
node.children.each { |n| n.name == "fmt-name" or parse(n, ul) }
|
|
@@ -21,6 +22,13 @@ module IsoDoc
|
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
|
|
25
|
+
def fmt_ul_parse(elem, fmt_ul, out)
|
|
26
|
+
children_parse(fmt_ul, out)
|
|
27
|
+
output_elem = out.parent.elements.last
|
|
28
|
+
output_elem.parent["id"] = elem["id"]
|
|
29
|
+
s = keep_style(elem) and output_elem.parent["style"] = s
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
OL_STYLE = {
|
|
25
33
|
arabic: "1",
|
|
26
34
|
roman: "i",
|
|
@@ -38,11 +46,13 @@ module IsoDoc
|
|
|
38
46
|
{ # type: node["type"] ? ol_style(node["type"].to_sym) : ol_depth(node),
|
|
39
47
|
type: ol_style(node["type"]&.to_sym),
|
|
40
48
|
start: node["start"],
|
|
41
|
-
id: node["id"], style: keep_style(node)
|
|
49
|
+
id: node["id"], style: keep_style(node)
|
|
50
|
+
}
|
|
42
51
|
end
|
|
43
52
|
|
|
44
53
|
def ol_parse(node, out)
|
|
45
54
|
out.div(**attr_code(class: "ol_wrap")) do |div|
|
|
55
|
+
n = node.at(ns("./fmt-ol")) and return fmt_ul_parse(node, n, out)
|
|
46
56
|
list_title_parse(node, div)
|
|
47
57
|
div.ol(**attr_code(ol_attrs(node))) do |ol|
|
|
48
58
|
node.children.each { |n| n.name == "fmt-name" or parse(n, ol) }
|
|
@@ -53,10 +63,10 @@ module IsoDoc
|
|
|
53
63
|
def li_checkbox(node)
|
|
54
64
|
if node["uncheckedcheckbox"] == "true"
|
|
55
65
|
'<span class="zzMoveToFollowing">' \
|
|
56
|
-
|
|
66
|
+
'<input type="checkbox" checked="checked"/></span>'
|
|
57
67
|
elsif node["checkedcheckbox"] == "true"
|
|
58
68
|
'<span class="zzMoveToFollowing">' \
|
|
59
|
-
|
|
69
|
+
'<input type="checkbox"/></span>'
|
|
60
70
|
else ""
|
|
61
71
|
end
|
|
62
72
|
end
|
|
@@ -70,7 +70,8 @@ module IsoDoc
|
|
|
70
70
|
def clause_name(_node, title, div, header_class)
|
|
71
71
|
header_class = {} if header_class.nil?
|
|
72
72
|
div.h1(**attr_code(header_class)) do |h1|
|
|
73
|
-
if title.is_a?(String)
|
|
73
|
+
if title.is_a?(String)
|
|
74
|
+
h1 << title
|
|
74
75
|
elsif title
|
|
75
76
|
children_parse(title, h1)
|
|
76
77
|
clause_parse_subtitle(title, h1)
|
|
@@ -88,6 +89,7 @@ module IsoDoc
|
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
def variant_title(node, out)
|
|
92
|
+
# node["type"] == "toc" and return # used only for ToC!
|
|
91
93
|
out.p(**attr_code(style: "display:none;",
|
|
92
94
|
class: "variant-title-#{node['type']}")) do |p|
|
|
93
95
|
children_parse(node, p)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "metanorma-utils"
|
|
2
|
+
require_relative "utils_img"
|
|
2
3
|
|
|
3
4
|
module IsoDoc
|
|
4
5
|
module Function
|
|
@@ -61,7 +62,7 @@ module IsoDoc
|
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
def to_xhtml_prep(xml)
|
|
64
|
-
xml.gsub!(
|
|
65
|
+
xml.gsub!(/\A<\?xml[^<>]*>\n?/, "")
|
|
65
66
|
xml.include?("<!DOCTYPE ") || (xml = DOCTYPE_HDR + xml)
|
|
66
67
|
numeric_escapes(xml)
|
|
67
68
|
end
|
|
@@ -117,9 +118,12 @@ module IsoDoc
|
|
|
117
118
|
end
|
|
118
119
|
|
|
119
120
|
def header_strip(hdr)
|
|
121
|
+
# \s[^<>]* rather than \s[^<>]+: \s already guarantees one whitespace
|
|
122
|
+
# char after <p, so [^<>]* (zero or more) suffices for any attributes,
|
|
123
|
+
# and removes the polynomial interaction between \s and [^<>]+.
|
|
120
124
|
h1 = to_xhtml_fragment(hdr.to_s.gsub(%r{<br\s*/>}, " ")
|
|
121
|
-
.gsub(%r{</?p(\s[^<>]
|
|
122
|
-
.gsub(/<\/?h[123456][^<>]*>/, "").
|
|
125
|
+
.gsub(%r{</?p(\s[^<>]*)?>}, "")
|
|
126
|
+
.gsub(/<\/?h[123456][^<>]*>/, "").dup)
|
|
123
127
|
h1.traverse do |x|
|
|
124
128
|
if x.name == "span" && x["style"]&.include?("mso-tab-count")
|
|
125
129
|
x.replace(" ")
|
|
@@ -162,41 +166,6 @@ module IsoDoc
|
|
|
162
166
|
.gsub("<", "<").gsub(">", ">").gsub("&", "&")
|
|
163
167
|
end
|
|
164
168
|
|
|
165
|
-
def save_dataimage(uri, _relative_dir = true)
|
|
166
|
-
%r{^data:(?<imgclass>image|application)/(?<imgtype>[^;]+);(?:charset=[^;]+;)?base64,(?<imgdata>.+)$} =~ uri
|
|
167
|
-
imgtype = "emf" if emf?("#{imgclass}/#{imgtype}")
|
|
168
|
-
imgtype = imgtype.sub(/\+[a-z0-9]+$/, "") # svg+xml
|
|
169
|
-
imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
|
|
170
|
-
imgtype == "postscript" and imgtype = "eps"
|
|
171
|
-
Tempfile.open(["image", ".#{imgtype}"],
|
|
172
|
-
mode: File::BINARY | File::SHARE_DELETE) do |f|
|
|
173
|
-
f.binmode
|
|
174
|
-
f.write(Base64.strict_decode64(imgdata))
|
|
175
|
-
@tempfile_cache << f # persist to the end
|
|
176
|
-
f.path
|
|
177
|
-
end
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def save_svg(img)
|
|
181
|
-
Tempfile.open(["image", ".svg"],
|
|
182
|
-
mode: File::BINARY | File::SHARE_DELETE) do |f|
|
|
183
|
-
f.write(img.to_xml)
|
|
184
|
-
@tempfile_cache << f # persist to the end
|
|
185
|
-
f.path
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def image_localfile(img)
|
|
190
|
-
img.name == "svg" && !img["src"] and
|
|
191
|
-
return save_svg(img)
|
|
192
|
-
case img["src"]
|
|
193
|
-
when /^data:/ then save_dataimage(img["src"], false)
|
|
194
|
-
when %r{^([A-Z]:)?/} then img["src"]
|
|
195
|
-
when nil then nil
|
|
196
|
-
else File.join(@localdir, img["src"])
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
169
|
LABELLED_ANCESTOR_ELEMENTS =
|
|
201
170
|
%w(example requirement recommendation permission
|
|
202
171
|
note table figure sourcecode).freeze
|
|
@@ -206,15 +175,6 @@ module IsoDoc
|
|
|
206
175
|
.intersection(LABELLED_ANCESTOR_ELEMENTS - exceptions).empty?
|
|
207
176
|
end
|
|
208
177
|
|
|
209
|
-
def emf?(type)
|
|
210
|
-
%w(application/emf application/x-emf image/x-emf image/x-mgx-emf
|
|
211
|
-
application/x-msmetafile image/x-xbitmap image/emf).include? type
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def eps?(type)
|
|
215
|
-
%w(application/postscript image/x-eps).include? type
|
|
216
|
-
end
|
|
217
|
-
|
|
218
178
|
def cleanup_entities(text, is_xml: true)
|
|
219
179
|
c = HTMLEntities.new
|
|
220
180
|
if is_xml
|
|
@@ -234,10 +194,6 @@ module IsoDoc
|
|
|
234
194
|
path[/\s/] ? "\"#{path}\"" : path
|
|
235
195
|
end
|
|
236
196
|
|
|
237
|
-
def imgfile_suffix(uri, suffix)
|
|
238
|
-
"#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.#{suffix}"
|
|
239
|
-
end
|
|
240
|
-
|
|
241
197
|
# Unescape & to & in href attributes only
|
|
242
198
|
# This ensures URLs work correctly while preserving & in text content
|
|
243
199
|
# This operates on the final string output after all Nokogiri processing
|
|
@@ -254,6 +210,34 @@ module IsoDoc
|
|
|
254
210
|
end
|
|
255
211
|
end
|
|
256
212
|
end
|
|
213
|
+
|
|
214
|
+
# parse CSV-encoded key=value attribute
|
|
215
|
+
COMMA_PLACEHOLDER = "##COMMA##".freeze
|
|
216
|
+
|
|
217
|
+
# Temporarily replace commas inside quotes with a placeholder
|
|
218
|
+
def comma_placeholder(options)
|
|
219
|
+
processed = ""
|
|
220
|
+
in_quotes = false
|
|
221
|
+
options.each_char do |c|
|
|
222
|
+
c == "'" and in_quotes = !in_quotes
|
|
223
|
+
processed << if c == "," && in_quotes
|
|
224
|
+
COMMA_PLACEHOLDER
|
|
225
|
+
else c
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
processed
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def csv_attribute_extract(options)
|
|
232
|
+
options.gsub!(/([a-z_]+)='/, %('\\1=))
|
|
233
|
+
processed = comma_placeholder(options)
|
|
234
|
+
CSV.parse_line(processed, quote_char: "'")
|
|
235
|
+
.each_with_object({}) do |x, acc|
|
|
236
|
+
x.gsub!(COMMA_PLACEHOLDER, ",")
|
|
237
|
+
m = /^(.+?)=(.+)?$/.match(x) or next
|
|
238
|
+
acc[m[1].to_sym] = m[2].sub(/^(["'])(.+)\1$/, "\\2")
|
|
239
|
+
end
|
|
240
|
+
end
|
|
257
241
|
end
|
|
258
242
|
end
|
|
259
243
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require "metanorma-utils"
|
|
2
|
+
|
|
3
|
+
module IsoDoc
|
|
4
|
+
module Function
|
|
5
|
+
module Utils
|
|
6
|
+
def save_dataimage(uri, _relative_dir = true)
|
|
7
|
+
%r{^data:(?<imgclass>image|application)/(?<imgtype>[^;]+);(?:charset=[^;]+;)?base64,(?<imgdata>.+)$} =~ uri
|
|
8
|
+
imgtype = "emf" if emf?("#{imgclass}/#{imgtype}")
|
|
9
|
+
imgtype = imgtype.sub(/\+[a-z0-9]+$/, "") # svg+xml
|
|
10
|
+
imgtype = "png" unless /^[a-z0-9]+$/.match? imgtype
|
|
11
|
+
imgtype == "postscript" and imgtype = "eps"
|
|
12
|
+
Tempfile.open(["image", ".#{imgtype}"],
|
|
13
|
+
mode: File::BINARY | File::SHARE_DELETE) do |f|
|
|
14
|
+
f.binmode
|
|
15
|
+
f.write(Base64.strict_decode64(imgdata))
|
|
16
|
+
@tempfile_cache << f # persist to the end
|
|
17
|
+
f.path
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def save_svg(img)
|
|
22
|
+
Tempfile.open(["image", ".svg"],
|
|
23
|
+
mode: File::BINARY | File::SHARE_DELETE) do |f|
|
|
24
|
+
f.write(img.to_xml)
|
|
25
|
+
@tempfile_cache << f # persist to the end
|
|
26
|
+
f.path
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def image_localfile(img)
|
|
31
|
+
img.name == "svg" && !img["src"] and
|
|
32
|
+
return save_svg(img)
|
|
33
|
+
case img["src"]
|
|
34
|
+
when /^data:/ then save_dataimage(img["src"], false)
|
|
35
|
+
when %r{^([A-Z]:)?/} then img["src"]
|
|
36
|
+
when nil then nil
|
|
37
|
+
else File.join(@localdir, img["src"])
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def emf?(type)
|
|
42
|
+
%w(application/emf application/x-emf image/x-emf image/x-mgx-emf
|
|
43
|
+
application/x-msmetafile image/x-xbitmap image/emf).include? type
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def eps?(type)
|
|
47
|
+
%w(application/postscript image/x-eps).include? type
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def imgfile_suffix(uri, suffix)
|
|
51
|
+
"#{File.join(File.dirname(uri), File.basename(uri, '.*'))}.#{suffix}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/isodoc/gem_tasks.rb
CHANGED
|
@@ -111,15 +111,18 @@ module IsoDoc
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def compile_scss(filename)
|
|
114
|
-
load_scss_paths(filename)
|
|
114
|
+
load_paths = load_scss_paths(filename)
|
|
115
115
|
Dir.mktmpdir do |dir|
|
|
116
116
|
File.write(File.join(dir, "variables.scss"), fonts_placeholder)
|
|
117
|
-
SassC.load_paths << dir
|
|
118
117
|
sheet_content = File.read(filename, encoding: "UTF-8")
|
|
119
|
-
|
|
118
|
+
# Drop the m flag and use [^{}\n]* so the lookahead is bounded to
|
|
119
|
+
# one line, preventing O(n^2) scanning across multi-line inputs.
|
|
120
|
+
.gsub(/([a-z])\.([0-9])(?=[^{}\n]*{)/, "\\1.__WORD__\\2")
|
|
120
121
|
SassC::Engine.new(%<@use "variables" as *;\n#{sheet_content}>,
|
|
121
|
-
syntax: :scss, quiet_deps: true,
|
|
122
|
-
|
|
122
|
+
syntax: :scss, quiet_deps: true,
|
|
123
|
+
load_paths: load_paths + [dir],
|
|
124
|
+
importer: SasscImporter)
|
|
125
|
+
.render.gsub("__WORD__", "")
|
|
123
126
|
end
|
|
124
127
|
end
|
|
125
128
|
|
|
@@ -131,10 +134,7 @@ module IsoDoc
|
|
|
131
134
|
"lib", "isodoc")
|
|
132
135
|
else File.join("lib", "isodoc")
|
|
133
136
|
end
|
|
134
|
-
[isodoc_path,
|
|
135
|
-
File.dirname(filename)].each do |name|
|
|
136
|
-
SassC.load_paths << name
|
|
137
|
-
end
|
|
137
|
+
[isodoc_path, File.dirname(filename)]
|
|
138
138
|
end
|
|
139
139
|
|
|
140
140
|
def compile_scss_task(current_task)
|
|
@@ -24,8 +24,8 @@ module IsoDoc
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def html5(doc)
|
|
27
|
-
doc.sub(%r{<!DOCTYPE html [^<>]+>}, "<!DOCTYPE html>")
|
|
28
|
-
.sub(%r{<\?xml[^<>]+>}, "")
|
|
27
|
+
doc.sub(%r{\A<!DOCTYPE html [^<>]+>}, "<!DOCTYPE html>")
|
|
28
|
+
.sub(%r{\A<\?xml[^<>]+>}, "")
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def html_cleanup(html)
|
|
@@ -6,14 +6,17 @@ module IsoDoc
|
|
|
6
6
|
module HtmlFunction
|
|
7
7
|
module Html
|
|
8
8
|
def script_cdata(result)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.gsub(%r{
|
|
14
|
-
.gsub(%r{\
|
|
15
|
-
.gsub(%r{
|
|
16
|
-
.gsub(%r{
|
|
9
|
+
# Use explicit [ \t\n\r]* rather than \s* with the m flag:
|
|
10
|
+
# [^<>]* and [ \t\n\r]* are disjoint character classes (whitespace
|
|
11
|
+
# chars are not < or >), preventing polynomial backtracking.
|
|
12
|
+
result.gsub(%r{<script([^<>]*)>[ \t\n\r]*<!\[CDATA\[}, "<script\\1>")
|
|
13
|
+
.gsub(%r{\]\]>[ \t\n\r]*</script>}, "</script>")
|
|
14
|
+
.gsub(%r{<!\[CDATA\[[ \t\n\r]*<script([^<>]*)>}, "<script\\1>")
|
|
15
|
+
.gsub(%r{</script>[ \t\n\r]*\]\]>}, "</script>")
|
|
16
|
+
.gsub(%r{<style([^<>]*)>[ \t\n\r]*<!\[CDATA\[}, "<style\\1>")
|
|
17
|
+
.gsub(%r{\]\]>[ \t\n\r]*</style>}, "</style>")
|
|
18
|
+
.gsub(%r{<!\[CDATA\[[ \t\n\r]*<style([^<>]*)>}, "<style\\1>")
|
|
19
|
+
.gsub(%r{</style>[ \t\n\r]*\]\]>}, "</style>")
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def htmlstylesheet(file)
|
|
@@ -31,7 +34,7 @@ module IsoDoc
|
|
|
31
34
|
head << Nokogiri::HTML.fragment("<style>#{htmlstylesheet(@htmlstylesheet)}</style>")
|
|
32
35
|
s = htmlstylesheet(@htmlstylesheet_override) and head << Nokogiri::HTML.fragment("<style>#{s}</style>")
|
|
33
36
|
s = @meta.get[:code_css] and
|
|
34
|
-
head << Nokogiri::HTML.fragment("<style>#{s.gsub(
|
|
37
|
+
head << Nokogiri::HTML.fragment("<style>#{s.gsub('sourcecode',
|
|
35
38
|
'pre.sourcecode')}</style>")
|
|
36
39
|
@bare and
|
|
37
40
|
head << "<style>body {margin-left: 2em; margin-right: 2em;}</style>"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module IsoDoc
|
|
2
|
+
class PresentationXMLConvert < ::IsoDoc::Convert
|
|
3
|
+
def annex(docxml)
|
|
4
|
+
docxml.xpath(ns("//annex")).each do |f|
|
|
5
|
+
@xrefs.klass.single_term_clause?(f) and single_term_clause_retitle(f)
|
|
6
|
+
annex1(f)
|
|
7
|
+
@xrefs.klass.single_term_clause?(f) and single_term_clause_unnest(f)
|
|
8
|
+
end
|
|
9
|
+
@xrefs.parse_inclusions(clauses: true).parse(docxml)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def annex1(elem)
|
|
13
|
+
lbl = @xrefs.anchor(elem["id"], :label, false)
|
|
14
|
+
orig_title = annex1_title_fmt(elem)
|
|
15
|
+
%w(title variant-title).each do |k|
|
|
16
|
+
k == "variant-title" && (t = elem.at(ns("./variant-title"))) &&
|
|
17
|
+
t["type"] != "_toc_temp" and next
|
|
18
|
+
# we only prefix variant-title we have just copied from title
|
|
19
|
+
annex1_title_prefix(elem, lbl, k)
|
|
20
|
+
end
|
|
21
|
+
annex1_title_postprocess(elem, orig_title)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def annex1_title_fmt(elem)
|
|
25
|
+
t = elem.at(ns("./title")) or return nil
|
|
26
|
+
unless elem.at(ns("./variant-title[@type='toc']"))
|
|
27
|
+
t.next = to_xml(t)
|
|
28
|
+
v = t.next
|
|
29
|
+
v.name = "variant-title"
|
|
30
|
+
v["type"] = "_toc_temp"
|
|
31
|
+
end
|
|
32
|
+
orig_title = to_xml(t.children)
|
|
33
|
+
t.children = annex1_title_fmt_inline(t)
|
|
34
|
+
orig_title
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def annex1_title_fmt_inline(title)
|
|
38
|
+
"<strong>#{to_xml(title.children)}</strong>"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def annex1_title_prefix(elem, lbl, tag)
|
|
42
|
+
delim, lbl = annex1_title_prefix_prep(elem, lbl, tag)
|
|
43
|
+
if unnumbered_clause?(elem)
|
|
44
|
+
prefix_name(elem, {}, nil, tag)
|
|
45
|
+
else
|
|
46
|
+
prefix_name(elem, { caption: delim }, lbl, tag,
|
|
47
|
+
fmt_xref_label: tag == "title")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def annex1_title_prefix_prep(elem, lbl, tag)
|
|
52
|
+
delim = annex_delim_override(elem)
|
|
53
|
+
if tag == "variant-title" # strip obligation, boldface
|
|
54
|
+
lbl &&= lbl.gsub("<strong>", "").gsub("</strong>", "")
|
|
55
|
+
# Use (?:<br/>)* (non-capturing) and [^<]* instead of .+? so the
|
|
56
|
+
# obligation-span content is matched without polynomial backtracking.
|
|
57
|
+
# fmt-obligation spans contain plain text, so [^<]* is equivalent.
|
|
58
|
+
.sub(%r{(?:<br/>)*<span class=.fmt-obligation.>[^<]*</span>}, "")
|
|
59
|
+
delim = "<tab/>"
|
|
60
|
+
end
|
|
61
|
+
[delim, lbl]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# only accept variant-title we have just copied from title and prefixed
|
|
65
|
+
# into fmt-variant-title: that replaces the variant-title we have inserted
|
|
66
|
+
def annex1_title_postprocess(elem, orig_title)
|
|
67
|
+
v, t, v1 = annex1_variant_title_postprocess_prep(elem)
|
|
68
|
+
t&.children = orig_title
|
|
69
|
+
v1&.name == "fmt-variant-title" or return
|
|
70
|
+
v&.remove
|
|
71
|
+
v1.name = "variant-title"
|
|
72
|
+
v1["type"] = "toc"
|
|
73
|
+
s = v1.at(ns(".//semx[@element = 'variant-title']")) or return
|
|
74
|
+
s["element"] = "title"
|
|
75
|
+
t and s["source"] = t["id"]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def annex1_variant_title_postprocess_prep(elem)
|
|
79
|
+
v = elem.at(ns("./variant-title[@type='_toc_temp']"))
|
|
80
|
+
t = elem.at(ns("./title"))
|
|
81
|
+
# fmt-variant-title generated from variant-title
|
|
82
|
+
v1 = v&.next_element ||
|
|
83
|
+
# fmt-variant-title generated only from lbl
|
|
84
|
+
elem.at(ns("./fmt-variant-title"))
|
|
85
|
+
[v, t, v1]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def annex_delim_override(elem)
|
|
89
|
+
m = elem.document.root.at(ns("//presentation-metadata/annex-delim"))
|
|
90
|
+
m ? to_xml(m.children) : annex_delim(elem)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def annex_delim(_elem)
|
|
94
|
+
"<br/><br/>"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module IsoDoc
|
|
2
2
|
class PresentationXMLConvert < ::IsoDoc::Convert
|
|
3
|
-
def prefix_name(node, delims, label, elem)
|
|
3
|
+
def prefix_name(node, delims, label, elem, fmt_xref_label: true)
|
|
4
4
|
sem_xml_descendant?(node) and return
|
|
5
5
|
label, delims = prefix_name_defaults(node, delims, label, elem)
|
|
6
6
|
name, ins, ids, number = prefix_name_prep(node, elem)
|
|
7
|
-
ins.next = fmt_xref_label(label, number, ids)
|
|
7
|
+
fmt_xref_label and ins.next = fmt_xref_label(label, number, ids)
|
|
8
8
|
# autonum can be empty, e.g single note in clause: "NOTE []"
|
|
9
9
|
number and node["autonum"] = number.gsub(/<[^>]+>/, "")
|
|
10
10
|
!node.at(ns("./fmt-#{elem}")) &&
|
|
@@ -40,6 +40,7 @@ module IsoDoc
|
|
|
40
40
|
node.at(ns("./sentinel"))&.remove
|
|
41
41
|
strip_duplicate_ids(node, node.at(ns("./#{elem}")),
|
|
42
42
|
node.at(ns("./fmt-#{elem}")))
|
|
43
|
+
node.at(ns("./fmt-#{elem}"))
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
def transfer_id(old, new)
|
|
@@ -67,7 +68,7 @@ module IsoDoc
|
|
|
67
68
|
# remove ids duplicated between sem_title and pres_title
|
|
68
69
|
# index terms are assumed transferred to pres_title from sem_title
|
|
69
70
|
def strip_duplicate_ids(_node, sem_title, pres_title)
|
|
70
|
-
sem_title && pres_title or return
|
|
71
|
+
(sem_title && pres_title) or return
|
|
71
72
|
ids = gather_all_ids(pres_title)
|
|
72
73
|
sem_title.xpath(".//*[@id]").each do |x|
|
|
73
74
|
ids.include?(x["id"]) or next
|
|
@@ -78,7 +79,7 @@ module IsoDoc
|
|
|
78
79
|
end
|
|
79
80
|
|
|
80
81
|
def semx(node, label, element = "autonum")
|
|
81
|
-
id = node["id"] || node[:id] ||
|
|
82
|
+
id = node["id"] || node[:id] || node["original-id"]
|
|
82
83
|
/<semx element='[^']+' source='#{id}'/.match?(label) and return label
|
|
83
84
|
l = stripsemx(label)
|
|
84
85
|
%(<semx element='#{element}' source='#{id}'>#{l}</semx>)
|
|
@@ -202,7 +203,7 @@ module IsoDoc
|
|
|
202
203
|
def sem_xml_descendant_inline?(_node, ancestor_names)
|
|
203
204
|
%w[xref eref origin link name title newcontent]
|
|
204
205
|
.any? do |name|
|
|
205
|
-
|
|
206
|
+
ancestor_names.include?(name)
|
|
206
207
|
end and return true
|
|
207
208
|
end
|
|
208
209
|
|
|
@@ -213,7 +214,7 @@ module IsoDoc
|
|
|
213
214
|
block?(node) and return false
|
|
214
215
|
%w[preferred admitted deprecated related definition source]
|
|
215
216
|
.any? do |name|
|
|
216
|
-
|
|
217
|
+
ancestor_names.include?(name)
|
|
217
218
|
end
|
|
218
219
|
end
|
|
219
220
|
|