uniword 1.0.11 → 1.2.4
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/config/font_metadata.yml +56 -0
- data/lib/uniword/accessibility/rules/descriptive_headings_rule.rb +1 -1
- data/lib/uniword/assembly/toc.rb +4 -14
- data/lib/uniword/assembly/variable_substitutor.rb +3 -4
- data/lib/uniword/batch/stages/normalize_styles_stage.rb +4 -2
- data/lib/uniword/builder/base_builder.rb +25 -0
- data/lib/uniword/builder/chart_builder.rb +33 -14
- data/lib/uniword/builder/deterministic_id.rb +17 -0
- data/lib/uniword/builder/document_builder.rb +129 -34
- data/lib/uniword/builder/footnote_builder.rb +22 -23
- data/lib/uniword/builder/header_footer_builder.rb +10 -10
- data/lib/uniword/builder/image_builder.rb +24 -16
- data/lib/uniword/builder/list_builder.rb +2 -1
- data/lib/uniword/builder/paragraph_builder.rb +95 -20
- data/lib/uniword/builder/run_utils.rb +97 -0
- data/lib/uniword/builder/section_builder.rb +40 -67
- data/lib/uniword/builder/table_builder.rb +32 -13
- data/lib/uniword/builder/table_cell_builder.rb +19 -0
- data/lib/uniword/builder.rb +27 -19
- data/lib/uniword/cli/diff_cli.rb +0 -1
- data/lib/uniword/cli/generate_cli.rb +0 -1
- data/lib/uniword/cli/headers_cli.rb +0 -1
- data/lib/uniword/cli/images_cli.rb +0 -1
- data/lib/uniword/cli/main.rb +6 -7
- data/lib/uniword/cli/protect_cli.rb +0 -1
- data/lib/uniword/cli/resources_cli.rb +0 -1
- data/lib/uniword/cli/review_cli.rb +0 -1
- data/lib/uniword/cli/spellcheck_cli.rb +0 -1
- data/lib/uniword/cli/styleset_cli.rb +0 -1
- data/lib/uniword/cli/template_cli.rb +0 -1
- data/lib/uniword/cli/theme_cli.rb +0 -1
- data/lib/uniword/cli/toc_cli.rb +0 -1
- data/lib/uniword/cli/watermark_cli.rb +0 -1
- data/lib/uniword/cli.rb +6 -17
- data/lib/uniword/diff/document_differ.rb +23 -5
- data/lib/uniword/diff/package_differ.rb +0 -1
- data/lib/uniword/diff.rb +4 -0
- data/lib/uniword/document_factory.rb +16 -25
- data/lib/uniword/docx/document_statistics.rb +42 -54
- data/lib/uniword/docx/id_allocator.rb +143 -0
- data/lib/uniword/docx/package.rb +42 -6
- data/lib/uniword/docx/package_defaults.rb +15 -25
- data/lib/uniword/docx/package_serialization.rb +131 -127
- data/lib/uniword/docx/reconciler/body.rb +197 -0
- data/lib/uniword/docx/reconciler/fix_codes.rb +74 -0
- data/lib/uniword/docx/reconciler/helpers.rb +337 -0
- data/lib/uniword/docx/reconciler/notes.rb +301 -0
- data/lib/uniword/docx/reconciler/package_structure.rb +322 -0
- data/lib/uniword/docx/reconciler/parts.rb +484 -0
- data/lib/uniword/docx/reconciler/referential_integrity.rb +449 -0
- data/lib/uniword/docx/reconciler/tables.rb +162 -0
- data/lib/uniword/docx/reconciler/theme.rb +141 -0
- data/lib/uniword/docx/reconciler.rb +44 -1097
- data/lib/uniword/docx.rb +3 -0
- data/lib/uniword/drawingml/color_scheme.rb +38 -5
- data/lib/uniword/hyperlink.rb +27 -26
- data/lib/uniword/infrastructure/zip_packager.rb +41 -38
- data/lib/uniword/lazy_loader.rb +36 -62
- data/lib/uniword/math.rb +3 -86
- data/lib/uniword/mhtml/document.rb +1 -3
- data/lib/uniword/model_attribute_access.rb +27 -0
- data/lib/uniword/ooxml/namespaces.rb +62 -2
- data/lib/uniword/ooxml/relationships/package_relationships.rb +7 -0
- data/lib/uniword/presentationml/slide_id.rb +0 -1
- data/lib/uniword/presentationml/slide_master_id.rb +0 -1
- data/lib/uniword/properties/bold.rb +0 -2
- data/lib/uniword/properties/boolean_formatting.rb +0 -2
- data/lib/uniword/properties/borders.rb +1 -1
- data/lib/uniword/properties/italic.rb +0 -2
- data/lib/uniword/properties/numbering_properties.rb +1 -1
- data/lib/uniword/properties/style_reference.rb +13 -0
- data/lib/uniword/quality/rules/heading_hierarchy_rule.rb +1 -1
- data/lib/uniword/quality/rules/style_consistency_rule.rb +1 -1
- data/lib/uniword/review/review_manager.rb +0 -2
- data/lib/uniword/template/helpers/loop_helper.rb +2 -2
- data/lib/uniword/template/variable_resolver.rb +14 -1
- data/lib/uniword/theme/theme_xml_parser.rb +1 -1
- data/lib/uniword/toc/toc_generator.rb +3 -14
- data/lib/uniword/transformation/mhtml_element_renderer.rb +94 -37
- data/lib/uniword/transformation/mhtml_metadata_builder.rb +1 -1
- data/lib/uniword/transformation/ooxml_to_html_converter.rb +3 -5
- data/lib/uniword/validation/checkers/internal_link_checker.rb +2 -3
- data/lib/uniword/version.rb +1 -1
- data/lib/uniword/visitor/text_extractor.rb +2 -1
- data/lib/uniword/watermark/manager.rb +2 -2
- data/lib/uniword/wordprocessingml/allow_png.rb +14 -0
- data/lib/uniword/wordprocessingml/body.rb +51 -34
- data/lib/uniword/wordprocessingml/body_div.rb +17 -0
- data/lib/uniword/wordprocessingml/div_border.rb +23 -0
- data/lib/uniword/wordprocessingml/div_borders.rb +24 -0
- data/lib/uniword/wordprocessingml/divs_child.rb +17 -0
- data/lib/uniword/wordprocessingml/document_root.rb +4 -3
- data/lib/uniword/wordprocessingml/endnote.rb +1 -1
- data/lib/uniword/wordprocessingml/endnotes.rb +4 -0
- data/lib/uniword/wordprocessingml/footer.rb +4 -0
- data/lib/uniword/wordprocessingml/footer_reference.rb +0 -1
- data/lib/uniword/wordprocessingml/footnote.rb +1 -1
- data/lib/uniword/wordprocessingml/footnotes.rb +4 -0
- data/lib/uniword/wordprocessingml/header.rb +4 -0
- data/lib/uniword/wordprocessingml/header_reference.rb +0 -1
- data/lib/uniword/wordprocessingml/hyperlink.rb +2 -2
- data/lib/uniword/wordprocessingml/instr_text.rb +20 -5
- data/lib/uniword/wordprocessingml/level.rb +2 -0
- data/lib/uniword/wordprocessingml/mar_bottom.rb +17 -0
- data/lib/uniword/wordprocessingml/mar_left.rb +17 -0
- data/lib/uniword/wordprocessingml/mar_right.rb +17 -0
- data/lib/uniword/wordprocessingml/mar_top.rb +17 -0
- data/lib/uniword/wordprocessingml/num.rb +4 -0
- data/lib/uniword/wordprocessingml/numbering.rb +1 -22
- data/lib/uniword/wordprocessingml/optimize_for_browser.rb +14 -0
- data/lib/uniword/wordprocessingml/page_defaults.rb +39 -0
- data/lib/uniword/wordprocessingml/paragraph.rb +16 -13
- data/lib/uniword/wordprocessingml/paragraph_properties.rb +12 -8
- data/lib/uniword/wordprocessingml/run.rb +32 -36
- data/lib/uniword/wordprocessingml/run_properties/merging.rb +45 -0
- data/lib/uniword/wordprocessingml/run_properties.rb +8 -5
- data/lib/uniword/wordprocessingml/section_properties.rb +3 -3
- data/lib/uniword/wordprocessingml/separator_char.rb +21 -0
- data/lib/uniword/wordprocessingml/settings.rb +19 -17
- data/lib/uniword/wordprocessingml/styles/style_definition.rb +1 -1
- data/lib/uniword/wordprocessingml/styles/style_library.rb +16 -0
- data/lib/uniword/wordprocessingml/table_defaults.rb +44 -0
- data/lib/uniword/wordprocessingml/text.rb +8 -2
- data/lib/uniword/wordprocessingml/web_div.rb +41 -0
- data/lib/uniword/wordprocessingml/web_divs.rb +18 -0
- data/lib/uniword/wordprocessingml/web_encoding.rb +17 -0
- data/lib/uniword/wordprocessingml/web_settings.rb +5 -21
- data/lib/uniword/wordprocessingml/zoom.rb +2 -0
- data/lib/uniword/wordprocessingml.rb +23 -0
- data/lib/uniword.rb +27 -0
- metadata +46 -70
- data/lib/uniword/math/accent.rb +0 -25
- data/lib/uniword/math/accent_properties.rb +0 -25
- data/lib/uniword/math/argument_properties.rb +0 -22
- data/lib/uniword/math/bar.rb +0 -25
- data/lib/uniword/math/bar_properties.rb +0 -25
- data/lib/uniword/math/begin_char.rb +0 -22
- data/lib/uniword/math/border_box.rb +0 -25
- data/lib/uniword/math/border_box_properties.rb +0 -39
- data/lib/uniword/math/box.rb +0 -25
- data/lib/uniword/math/box_properties.rb +0 -33
- data/lib/uniword/math/char.rb +0 -22
- data/lib/uniword/math/control_properties.rb +0 -27
- data/lib/uniword/math/degree.rb +0 -26
- data/lib/uniword/math/delimiter.rb +0 -25
- data/lib/uniword/math/delimiter_properties.rb +0 -33
- data/lib/uniword/math/denominator.rb +0 -26
- data/lib/uniword/math/element.rb +0 -61
- data/lib/uniword/math/end_char.rb +0 -22
- data/lib/uniword/math/equation_array.rb +0 -25
- data/lib/uniword/math/equation_array_properties.rb +0 -33
- data/lib/uniword/math/fraction.rb +0 -27
- data/lib/uniword/math/fraction_properties.rb +0 -25
- data/lib/uniword/math/function.rb +0 -27
- data/lib/uniword/math/function_name.rb +0 -26
- data/lib/uniword/math/function_properties.rb +0 -23
- data/lib/uniword/math/group_char.rb +0 -25
- data/lib/uniword/math/group_char_properties.rb +0 -29
- data/lib/uniword/math/lim.rb +0 -26
- data/lib/uniword/math/lower_limit.rb +0 -27
- data/lib/uniword/math/lower_limit_properties.rb +0 -23
- data/lib/uniword/math/math_break.rb +0 -22
- data/lib/uniword/math/math_font.rb +0 -22
- data/lib/uniword/math/math_properties.rb +0 -53
- data/lib/uniword/math/math_run.rb +0 -42
- data/lib/uniword/math/math_run_properties.rb +0 -37
- data/lib/uniword/math/math_simple_int_val.rb +0 -24
- data/lib/uniword/math/math_simple_val.rb +0 -24
- data/lib/uniword/math/math_style.rb +0 -22
- data/lib/uniword/math/math_text.rb +0 -23
- data/lib/uniword/math/matrix.rb +0 -25
- data/lib/uniword/math/matrix_column.rb +0 -23
- data/lib/uniword/math/matrix_column_properties.rb +0 -24
- data/lib/uniword/math/matrix_columns.rb +0 -23
- data/lib/uniword/math/matrix_properties.rb +0 -37
- data/lib/uniword/math/matrix_row.rb +0 -23
- data/lib/uniword/math/nary.rb +0 -29
- data/lib/uniword/math/nary_properties.rb +0 -33
- data/lib/uniword/math/numerator.rb +0 -26
- data/lib/uniword/math/o_math.rb +0 -65
- data/lib/uniword/math/o_math_para.rb +0 -25
- data/lib/uniword/math/o_math_para_properties.rb +0 -22
- data/lib/uniword/math/phantom.rb +0 -25
- data/lib/uniword/math/phantom_properties.rb +0 -33
- data/lib/uniword/math/pre_sub_superscript.rb +0 -29
- data/lib/uniword/math/pre_sub_superscript_properties.rb +0 -23
- data/lib/uniword/math/radical.rb +0 -27
- data/lib/uniword/math/radical_properties.rb +0 -25
- data/lib/uniword/math/separator_char.rb +0 -22
- data/lib/uniword/math/sub.rb +0 -26
- data/lib/uniword/math/sub_superscript.rb +0 -29
- data/lib/uniword/math/sub_superscript_properties.rb +0 -25
- data/lib/uniword/math/subscript.rb +0 -27
- data/lib/uniword/math/subscript_properties.rb +0 -23
- data/lib/uniword/math/sup.rb +0 -26
- data/lib/uniword/math/superscript.rb +0 -27
- data/lib/uniword/math/superscript_properties.rb +0 -23
- data/lib/uniword/math/upper_limit.rb +0 -27
- data/lib/uniword/math/upper_limit_properties.rb +0 -23
data/lib/uniword/docx.rb
CHANGED
|
@@ -7,7 +7,10 @@ module Uniword
|
|
|
7
7
|
# This namespace holds DOCX-specific concerns: the package model,
|
|
8
8
|
# document-level reconciliation, and user-defined requirements.
|
|
9
9
|
module Docx
|
|
10
|
+
autoload :IdAllocator, "#{__dir__}/docx/id_allocator"
|
|
10
11
|
autoload :Package, "#{__dir__}/docx/package"
|
|
12
|
+
autoload :PackageDefaults, "#{__dir__}/docx/package_defaults"
|
|
13
|
+
autoload :PackageSerialization, "#{__dir__}/docx/package_serialization"
|
|
11
14
|
autoload :Profile, "#{__dir__}/docx/profile"
|
|
12
15
|
autoload :DocumentStatistics, "#{__dir__}/docx/document_statistics"
|
|
13
16
|
autoload :Reconciler, "#{__dir__}/docx/reconciler"
|
|
@@ -310,13 +310,29 @@ module Uniword
|
|
|
310
310
|
# @param color_name [String, Symbol] The color name (e.g., :accent1)
|
|
311
311
|
# @return [String, nil] The RGB hex color value
|
|
312
312
|
def [](color_name)
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
attr_name = color_name == :folHlink ? :fol_hlink : color_name
|
|
316
|
-
color_obj = public_send(attr_name)
|
|
313
|
+
attr_name = color_name.to_sym == :folHlink ? :fol_hlink : color_name.to_sym
|
|
314
|
+
color_obj = color_by_name(attr_name)
|
|
317
315
|
color_obj&.value
|
|
318
316
|
end
|
|
319
317
|
|
|
318
|
+
def color_by_name(name)
|
|
319
|
+
case name
|
|
320
|
+
when :dk1 then dk1
|
|
321
|
+
when :lt1 then lt1
|
|
322
|
+
when :dk2 then dk2
|
|
323
|
+
when :lt2 then lt2
|
|
324
|
+
when :accent1 then accent1
|
|
325
|
+
when :accent2 then accent2
|
|
326
|
+
when :accent3 then accent3
|
|
327
|
+
when :accent4 then accent4
|
|
328
|
+
when :accent5 then accent5
|
|
329
|
+
when :accent6 then accent6
|
|
330
|
+
when :hlink then hlink
|
|
331
|
+
when :fol_hlink then fol_hlink
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
private :color_by_name
|
|
335
|
+
|
|
320
336
|
# Set a color by name
|
|
321
337
|
#
|
|
322
338
|
# @param color_name [String, Symbol] The color name
|
|
@@ -345,10 +361,27 @@ module Uniword
|
|
|
345
361
|
|
|
346
362
|
color_obj = color_class.new
|
|
347
363
|
color_obj.rgb = value
|
|
348
|
-
|
|
364
|
+
assign_color_by_name(attr_name, color_obj)
|
|
349
365
|
@colors_hash[color_name] = value
|
|
350
366
|
end
|
|
351
367
|
|
|
368
|
+
def assign_color_by_name(name, color_obj)
|
|
369
|
+
case name
|
|
370
|
+
when :dk1 then self.dk1 = color_obj
|
|
371
|
+
when :lt1 then self.lt1 = color_obj
|
|
372
|
+
when :dk2 then self.dk2 = color_obj
|
|
373
|
+
when :lt2 then self.lt2 = color_obj
|
|
374
|
+
when :accent1 then self.accent1 = color_obj
|
|
375
|
+
when :accent2 then self.accent2 = color_obj
|
|
376
|
+
when :accent3 then self.accent3 = color_obj
|
|
377
|
+
when :accent4 then self.accent4 = color_obj
|
|
378
|
+
when :accent5 then self.accent5 = color_obj
|
|
379
|
+
when :accent6 then self.accent6 = color_obj
|
|
380
|
+
when :hlink then self.hlink = color_obj
|
|
381
|
+
when :fol_hlink then self.fol_hlink = color_obj
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
352
385
|
# Get all defined colors
|
|
353
386
|
#
|
|
354
387
|
# @return [Hash] All colors
|
data/lib/uniword/hyperlink.rb
CHANGED
|
@@ -1,38 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "lutaml/model"
|
|
4
|
-
|
|
5
3
|
module Uniword
|
|
6
4
|
# Hyperlink convenience wrapper for external and internal links.
|
|
7
5
|
#
|
|
8
|
-
#
|
|
6
|
+
# Converts to Wordprocessingml::Hyperlink model objects. For external
|
|
7
|
+
# links, properly assigns an rId that references a relationship in
|
|
8
|
+
# document.xml.rels — not the raw URL string.
|
|
9
9
|
#
|
|
10
10
|
# @example External hyperlink
|
|
11
11
|
# link = Hyperlink.new(url: 'https://example.com', text: 'Click here')
|
|
12
12
|
# link.external? # => true
|
|
13
|
-
# link.url # => 'https://example.com'
|
|
14
13
|
#
|
|
15
14
|
# @example Internal hyperlink (bookmark)
|
|
16
15
|
# link = Hyperlink.new(anchor: 'section1', text: 'Go to section')
|
|
17
16
|
# link.internal? # => true
|
|
18
|
-
# link.anchor # => 'section1'
|
|
19
17
|
class Hyperlink
|
|
20
|
-
|
|
21
|
-
attr_reader :url
|
|
22
|
-
|
|
23
|
-
# @return [String, nil] Anchor/bookmark name for internal links
|
|
24
|
-
attr_reader :anchor
|
|
18
|
+
REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
attr_reader :text
|
|
20
|
+
attr_reader :url, :anchor, :text, :tooltip
|
|
28
21
|
|
|
29
|
-
# @return [String, nil] Tooltip text
|
|
30
|
-
attr_reader :tooltip
|
|
31
|
-
|
|
32
|
-
# @param url [String, nil] URL for external links
|
|
33
|
-
# @param anchor [String, nil] Anchor for internal links
|
|
34
|
-
# @param text [String] Display text
|
|
35
|
-
# @param tooltip [String, nil] Optional tooltip
|
|
36
22
|
def initialize(url: nil, anchor: nil, text: nil, tooltip: nil)
|
|
37
23
|
@url = url
|
|
38
24
|
@anchor = anchor
|
|
@@ -40,35 +26,50 @@ module Uniword
|
|
|
40
26
|
@tooltip = tooltip
|
|
41
27
|
end
|
|
42
28
|
|
|
43
|
-
# @return [Boolean] True if this is an external URL link
|
|
44
29
|
def external?
|
|
45
30
|
!url.nil?
|
|
46
31
|
end
|
|
47
32
|
|
|
48
|
-
# @return [Boolean] True if this is an internal anchor link
|
|
49
33
|
def internal?
|
|
50
34
|
!anchor.nil?
|
|
51
35
|
end
|
|
52
36
|
|
|
53
|
-
# Convert to the underlying Wordprocessingml::Hyperlink model
|
|
37
|
+
# Convert to the underlying Wordprocessingml::Hyperlink model.
|
|
38
|
+
#
|
|
39
|
+
# When an allocator is provided, external links get a proper rId
|
|
40
|
+
# registered as a hyperlink relationship. Without an allocator,
|
|
41
|
+
# falls back to setting id to the raw URL (legacy behavior).
|
|
54
42
|
#
|
|
43
|
+
# @param allocator [Docx::IdAllocator, nil] ID allocator for rId assignment
|
|
55
44
|
# @return [Wordprocessingml::Hyperlink] The OOXML hyperlink element
|
|
56
|
-
def to_model
|
|
45
|
+
def to_model(allocator: nil)
|
|
57
46
|
model = Wordprocessingml::Hyperlink.new
|
|
58
|
-
|
|
47
|
+
|
|
48
|
+
if url
|
|
49
|
+
if allocator
|
|
50
|
+
r_id = allocator.alloc_rid(
|
|
51
|
+
target: url,
|
|
52
|
+
type: REL_TYPE,
|
|
53
|
+
target_mode: "External",
|
|
54
|
+
)
|
|
55
|
+
model.id = r_id
|
|
56
|
+
else
|
|
57
|
+
model.id = url
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
59
61
|
model.anchor = anchor if anchor
|
|
60
62
|
model.tooltip = tooltip if tooltip
|
|
61
63
|
|
|
62
64
|
if text
|
|
63
65
|
run = Wordprocessingml::Run.new
|
|
64
|
-
run.text = Wordprocessingml::Text.
|
|
66
|
+
run.text = Wordprocessingml::Text.cast(text)
|
|
65
67
|
model.runs << run
|
|
66
68
|
end
|
|
67
69
|
|
|
68
70
|
model
|
|
69
71
|
end
|
|
70
72
|
|
|
71
|
-
# @return [Hash] Hash representation
|
|
72
73
|
def to_h
|
|
73
74
|
{ url: url, anchor: anchor, text: text, tooltip: tooltip }
|
|
74
75
|
end
|
|
@@ -38,15 +38,24 @@ module Uniword
|
|
|
38
38
|
# Ensure output directory exists
|
|
39
39
|
FileUtils.mkdir_p(File.dirname(output_path))
|
|
40
40
|
|
|
41
|
-
# Use
|
|
42
|
-
#
|
|
41
|
+
# Use Zip::OutputStream directly (not Zip::File) so that Entry objects
|
|
42
|
+
# with internal_file_attributes=0 are preserved through serialization.
|
|
43
|
+
# Zip::File wraps entries in StreamableStream which is NOT kind_of?(Entry),
|
|
44
|
+
# causing put_next_entry to discard our Entry and create a fresh one.
|
|
43
45
|
temp_path = "#{output_path}.#{Process.pid}.tmp"
|
|
44
46
|
|
|
45
|
-
Zip
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
was_zip64 = Zip.write_zip64_support
|
|
48
|
+
Zip.write_zip64_support = false
|
|
49
|
+
begin
|
|
50
|
+
Zip::OutputStream.open(temp_path) do |zos|
|
|
51
|
+
content.each do |entry_path, entry_content|
|
|
52
|
+
entry = Zip::Entry.new(temp_path, entry_path.to_s)
|
|
53
|
+
entry.internal_file_attributes = 0
|
|
54
|
+
entry.external_file_attributes = 0
|
|
55
|
+
entry.fstype = Zip::FSTYPE_FAT
|
|
56
|
+
|
|
57
|
+
zos.put_next_entry(entry)
|
|
58
|
+
|
|
50
59
|
final_content =
|
|
51
60
|
if entry_content.encoding == Encoding::ASCII_8BIT
|
|
52
61
|
entry_content
|
|
@@ -55,31 +64,15 @@ module Uniword
|
|
|
55
64
|
"UTF-8", invalid: :replace, undef: :replace
|
|
56
65
|
)
|
|
57
66
|
end
|
|
58
|
-
|
|
67
|
+
zos.write(final_content)
|
|
59
68
|
end
|
|
60
69
|
end
|
|
70
|
+
ensure
|
|
71
|
+
Zip.write_zip64_support = was_zip64
|
|
61
72
|
end
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
# and FileUtils.mv (rename) can fail with EACCES on locked files.
|
|
65
|
-
# Use File.binwrite + unlink instead, which is more Windows-friendly.
|
|
66
|
-
retries = 10
|
|
67
|
-
begin
|
|
68
|
-
FileUtils.rm_f(output_path)
|
|
69
|
-
# Wait for Windows to release the lock
|
|
70
|
-
sleep(0.5)
|
|
71
|
-
# Copy content instead of renaming to avoid rename locks
|
|
72
|
-
File.binwrite(output_path, File.binread(temp_path))
|
|
73
|
-
FileUtils.rm_f(temp_path)
|
|
74
|
-
rescue Errno::EACCES
|
|
75
|
-
retries -= 1
|
|
76
|
-
raise unless retries.positive?
|
|
77
|
-
|
|
78
|
-
sleep(0.5)
|
|
79
|
-
retry
|
|
80
|
-
end
|
|
74
|
+
move_temp_to_output(temp_path, output_path)
|
|
81
75
|
ensure
|
|
82
|
-
# Clean up temp file if it still exists
|
|
83
76
|
FileUtils.rm_f(temp_path) if defined?(temp_path) && temp_path && File.exist?(temp_path)
|
|
84
77
|
end
|
|
85
78
|
|
|
@@ -162,9 +155,18 @@ module Uniword
|
|
|
162
155
|
def write_to_zip_file(content, output_path)
|
|
163
156
|
temp_path = "#{output_path}.#{Process.pid}.#{rand(1000)}.tmp"
|
|
164
157
|
|
|
165
|
-
Zip
|
|
166
|
-
|
|
167
|
-
|
|
158
|
+
was_zip64 = Zip.write_zip64_support
|
|
159
|
+
Zip.write_zip64_support = false
|
|
160
|
+
begin
|
|
161
|
+
Zip::OutputStream.open(temp_path) do |zos|
|
|
162
|
+
content.each do |entry_path, entry_content|
|
|
163
|
+
entry = Zip::Entry.new(temp_path, entry_path.to_s)
|
|
164
|
+
entry.internal_file_attributes = 0
|
|
165
|
+
entry.external_file_attributes = 0
|
|
166
|
+
entry.fstype = Zip::FSTYPE_FAT
|
|
167
|
+
|
|
168
|
+
zos.put_next_entry(entry)
|
|
169
|
+
|
|
168
170
|
final_content =
|
|
169
171
|
if entry_content.encoding == Encoding::ASCII_8BIT
|
|
170
172
|
entry_content
|
|
@@ -173,20 +175,23 @@ module Uniword
|
|
|
173
175
|
"UTF-8", invalid: :replace, undef: :replace
|
|
174
176
|
)
|
|
175
177
|
end
|
|
176
|
-
|
|
178
|
+
zos.write(final_content)
|
|
177
179
|
end
|
|
178
180
|
end
|
|
181
|
+
ensure
|
|
182
|
+
Zip.write_zip64_support = was_zip64
|
|
179
183
|
end
|
|
180
184
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
move_temp_to_output(temp_path, output_path)
|
|
186
|
+
ensure
|
|
187
|
+
FileUtils.rm_f(temp_path) if defined?(temp_path) && temp_path && File.exist?(temp_path)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def move_temp_to_output(temp_path, output_path)
|
|
184
191
|
retries = 10
|
|
185
192
|
begin
|
|
186
193
|
FileUtils.rm_f(output_path)
|
|
187
|
-
# Wait for Windows to release the lock
|
|
188
194
|
sleep(0.5)
|
|
189
|
-
# Copy content instead of renaming to avoid rename locks
|
|
190
195
|
File.binwrite(output_path, File.binread(temp_path))
|
|
191
196
|
FileUtils.rm_f(temp_path)
|
|
192
197
|
rescue Errno::EACCES
|
|
@@ -196,8 +201,6 @@ module Uniword
|
|
|
196
201
|
sleep(0.5)
|
|
197
202
|
retry
|
|
198
203
|
end
|
|
199
|
-
ensure
|
|
200
|
-
FileUtils.rm_f(temp_path)
|
|
201
204
|
end
|
|
202
205
|
|
|
203
206
|
# Validate the content hash.
|
data/lib/uniword/lazy_loader.rb
CHANGED
|
@@ -6,107 +6,81 @@ module Uniword
|
|
|
6
6
|
# Lazy loading delays the loading of data until it is actually needed,
|
|
7
7
|
# which helps reduce memory usage for large documents.
|
|
8
8
|
#
|
|
9
|
+
# All cached values are stored in a single Hash (`@_lazy_cache`)
|
|
10
|
+
# accessed via direct ivar reference — no instance_variable_get/set,
|
|
11
|
+
# no public_send, no remove_instance_variable.
|
|
12
|
+
#
|
|
9
13
|
# @example Using lazy attributes
|
|
10
14
|
# class Document
|
|
11
15
|
# extend LazyLoader
|
|
12
16
|
#
|
|
13
17
|
# lazy_attr :paragraphs do
|
|
14
|
-
# # Load paragraphs only when accessed
|
|
15
18
|
# parse_paragraphs_from_xml
|
|
16
19
|
# end
|
|
17
20
|
# end
|
|
18
21
|
module LazyLoader
|
|
19
|
-
# Define a lazy attribute that loads only when first accessed.
|
|
20
|
-
#
|
|
21
|
-
# The loader block is executed once on first access, and the result
|
|
22
|
-
# is cached for subsequent accesses.
|
|
23
|
-
#
|
|
24
|
-
# @param name [Symbol] The attribute name
|
|
25
|
-
# @param loader [Proc] Block that returns the attribute value
|
|
26
|
-
# @return [void]
|
|
27
|
-
#
|
|
28
|
-
# @example Define a lazy attribute
|
|
29
|
-
# lazy_attr :images do
|
|
30
|
-
# load_images_from_disk
|
|
31
|
-
# end
|
|
32
22
|
def lazy_attr(name, &loader)
|
|
33
23
|
raise ArgumentError, "Block required for lazy_attr" unless loader
|
|
34
24
|
|
|
35
|
-
|
|
36
|
-
define_method(name) do
|
|
37
|
-
instance_variable = "@#{name}"
|
|
25
|
+
cache_key = name
|
|
38
26
|
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
define_method(name) do
|
|
28
|
+
@_lazy_cache ||= {}
|
|
29
|
+
return @_lazy_cache[cache_key] if @_lazy_cache.key?(cache_key)
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
value = instance_exec(&loader)
|
|
44
|
-
instance_variable_set(instance_variable, value)
|
|
45
|
-
value
|
|
31
|
+
@_lazy_cache[cache_key] = instance_exec(&loader)
|
|
46
32
|
end
|
|
47
33
|
|
|
48
|
-
# Define predicate method to check if loaded
|
|
49
34
|
define_method("#{name}_loaded?") do
|
|
50
|
-
|
|
35
|
+
@_lazy_cache ||= {}
|
|
36
|
+
@_lazy_cache.key?(cache_key)
|
|
51
37
|
end
|
|
52
38
|
|
|
53
|
-
# Define method to clear cached value
|
|
54
39
|
define_method("clear_#{name}") do
|
|
55
|
-
|
|
40
|
+
@_lazy_cache ||= {}
|
|
41
|
+
@_lazy_cache.delete(cache_key)
|
|
56
42
|
end
|
|
57
43
|
end
|
|
58
44
|
|
|
59
|
-
# Define a lazy collection attribute with batch loading.
|
|
60
|
-
#
|
|
61
|
-
# Similar to lazy_attr but optimized for collections that can be
|
|
62
|
-
# loaded in batches or filtered on demand.
|
|
63
|
-
#
|
|
64
|
-
# @param name [Symbol] The collection attribute name
|
|
65
|
-
# @param loader [Proc] Block that returns the collection
|
|
66
|
-
# @return [void]
|
|
67
|
-
#
|
|
68
|
-
# @example Define a lazy collection
|
|
69
|
-
# lazy_collection :tables do
|
|
70
|
-
# load_tables_from_xml
|
|
71
|
-
# end
|
|
72
45
|
def lazy_collection(name, &loader)
|
|
73
46
|
raise ArgumentError, "Block required for lazy_collection" unless loader
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
instance_variable = "@#{name}"
|
|
78
|
-
|
|
79
|
-
# Return cached collection if already loaded
|
|
80
|
-
return instance_variable_get(instance_variable) if instance_variable_defined?(instance_variable)
|
|
48
|
+
cache_key = name
|
|
49
|
+
normalizer = method(:normalize_collection)
|
|
81
50
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
collection = Array(collection) unless collection.is_a?(Array)
|
|
51
|
+
define_method(name) do
|
|
52
|
+
@_lazy_cache ||= {}
|
|
53
|
+
return @_lazy_cache[cache_key] if @_lazy_cache.key?(cache_key)
|
|
86
54
|
|
|
87
|
-
|
|
55
|
+
collection = normalizer.call(instance_exec(&loader))
|
|
56
|
+
@_lazy_cache[cache_key] = collection
|
|
88
57
|
collection
|
|
89
58
|
end
|
|
90
59
|
|
|
91
|
-
# Define method to check if collection is loaded
|
|
92
60
|
define_method("#{name}_loaded?") do
|
|
93
|
-
|
|
61
|
+
@_lazy_cache ||= {}
|
|
62
|
+
@_lazy_cache.key?(cache_key)
|
|
94
63
|
end
|
|
95
64
|
|
|
96
|
-
# Define method to clear cached collection
|
|
97
65
|
define_method("clear_#{name}") do
|
|
98
|
-
|
|
66
|
+
@_lazy_cache ||= {}
|
|
67
|
+
@_lazy_cache.delete(cache_key)
|
|
99
68
|
end
|
|
100
69
|
|
|
101
|
-
# Define method to get collection size without loading all items
|
|
102
70
|
define_method("#{name}_count") do
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
public_send(name).size
|
|
71
|
+
@_lazy_cache ||= {}
|
|
72
|
+
unless @_lazy_cache.key?(cache_key)
|
|
73
|
+
@_lazy_cache[cache_key] = normalizer.call(instance_exec(&loader))
|
|
74
|
+
end
|
|
75
|
+
@_lazy_cache[cache_key].size
|
|
109
76
|
end
|
|
110
77
|
end
|
|
78
|
+
|
|
79
|
+
def normalize_collection(value)
|
|
80
|
+
value = [] if value.nil?
|
|
81
|
+
value = Array(value) unless value.is_a?(Array)
|
|
82
|
+
value
|
|
83
|
+
end
|
|
84
|
+
private :normalize_collection
|
|
111
85
|
end
|
|
112
86
|
end
|
data/lib/uniword/math.rb
CHANGED
|
@@ -1,92 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# Using explicit autoload instead of dynamic Dir[] for maintainability
|
|
6
|
-
#
|
|
7
|
-
# Office Math Markup Language (OMML) support for equations
|
|
8
|
-
# Auto-generated index file for Math namespace classes
|
|
9
|
-
|
|
3
|
+
# Namespace for math-related helpers. OMML schema models were removed in
|
|
4
|
+
# favor of the omml gem; only the Plurimath adapter remains.
|
|
10
5
|
module Uniword
|
|
11
6
|
module Math
|
|
12
|
-
|
|
13
|
-
autoload :BeginChar, "uniword/math/begin_char"
|
|
14
|
-
autoload :EndChar, "uniword/math/end_char"
|
|
15
|
-
autoload :SeparatorChar, "uniword/math/separator_char"
|
|
16
|
-
autoload :Char, "uniword/math/char"
|
|
17
|
-
autoload :MathText, "uniword/math/math_text"
|
|
18
|
-
autoload :MathBreak, "uniword/math/math_break"
|
|
19
|
-
autoload :MathFont, "uniword/math/math_font"
|
|
20
|
-
autoload :MathStyle, "uniword/math/math_style"
|
|
21
|
-
autoload :Element, "uniword/math/element"
|
|
22
|
-
|
|
23
|
-
# Property classes (26)
|
|
24
|
-
autoload :ArgumentProperties, "uniword/math/argument_properties"
|
|
25
|
-
autoload :ControlProperties, "uniword/math/control_properties"
|
|
26
|
-
autoload :OMathParaProperties, "uniword/math/o_math_para_properties"
|
|
27
|
-
autoload :FractionProperties, "uniword/math/fraction_properties"
|
|
28
|
-
autoload :FunctionProperties, "uniword/math/function_properties"
|
|
29
|
-
autoload :DelimiterProperties, "uniword/math/delimiter_properties"
|
|
30
|
-
autoload :EquationArrayProperties, "uniword/math/equation_array_properties"
|
|
31
|
-
autoload :MatrixColumnProperties, "uniword/math/matrix_column_properties"
|
|
32
|
-
autoload :MatrixColumn, "uniword/math/matrix_column"
|
|
33
|
-
autoload :MatrixColumns, "uniword/math/matrix_columns"
|
|
34
|
-
autoload :MatrixProperties, "uniword/math/matrix_properties"
|
|
35
|
-
autoload :SubscriptProperties, "uniword/math/subscript_properties"
|
|
36
|
-
autoload :SuperscriptProperties, "uniword/math/superscript_properties"
|
|
37
|
-
autoload :PreSubSuperscriptProperties,
|
|
38
|
-
"uniword/math/pre_sub_superscript_properties"
|
|
39
|
-
autoload :SubSuperscriptProperties,
|
|
40
|
-
"uniword/math/sub_superscript_properties"
|
|
41
|
-
autoload :RadicalProperties, "uniword/math/radical_properties"
|
|
42
|
-
autoload :LowerLimitProperties, "uniword/math/lower_limit_properties"
|
|
43
|
-
autoload :UpperLimitProperties, "uniword/math/upper_limit_properties"
|
|
44
|
-
autoload :GroupCharProperties, "uniword/math/group_char_properties"
|
|
45
|
-
autoload :AccentProperties, "uniword/math/accent_properties"
|
|
46
|
-
autoload :NaryProperties, "uniword/math/nary_properties"
|
|
47
|
-
autoload :MathRunProperties, "uniword/math/math_run_properties"
|
|
48
|
-
autoload :BoxProperties, "uniword/math/box_properties"
|
|
49
|
-
autoload :BarProperties, "uniword/math/bar_properties"
|
|
50
|
-
autoload :BorderBoxProperties, "uniword/math/border_box_properties"
|
|
51
|
-
autoload :PhantomProperties, "uniword/math/phantom_properties"
|
|
52
|
-
autoload :MathProperties, "uniword/math/math_properties"
|
|
53
|
-
autoload :MathSimpleVal, "uniword/math/math_simple_val"
|
|
54
|
-
autoload :MathSimpleIntVal, "uniword/math/math_simple_int_val"
|
|
55
|
-
|
|
56
|
-
# Element content classes (9)
|
|
57
|
-
autoload :Numerator, "uniword/math/numerator"
|
|
58
|
-
autoload :Denominator, "uniword/math/denominator"
|
|
59
|
-
autoload :FunctionName, "uniword/math/function_name"
|
|
60
|
-
autoload :Sub, "uniword/math/sub"
|
|
61
|
-
autoload :Sup, "uniword/math/sup"
|
|
62
|
-
autoload :Degree, "uniword/math/degree"
|
|
63
|
-
autoload :Lim, "uniword/math/lim"
|
|
64
|
-
|
|
65
|
-
# Structure classes (22)
|
|
66
|
-
autoload :Fraction, "uniword/math/fraction"
|
|
67
|
-
autoload :Function, "uniword/math/function"
|
|
68
|
-
autoload :Delimiter, "uniword/math/delimiter"
|
|
69
|
-
autoload :EquationArray, "uniword/math/equation_array"
|
|
70
|
-
autoload :MatrixRow, "uniword/math/matrix_row"
|
|
71
|
-
autoload :Matrix, "uniword/math/matrix"
|
|
72
|
-
autoload :Subscript, "uniword/math/subscript"
|
|
73
|
-
autoload :Superscript, "uniword/math/superscript"
|
|
74
|
-
autoload :PreSubSuperscript, "uniword/math/pre_sub_superscript"
|
|
75
|
-
autoload :SubSuperscript, "uniword/math/sub_superscript"
|
|
76
|
-
autoload :Radical, "uniword/math/radical"
|
|
77
|
-
autoload :LowerLimit, "uniword/math/lower_limit"
|
|
78
|
-
autoload :UpperLimit, "uniword/math/upper_limit"
|
|
79
|
-
autoload :GroupChar, "uniword/math/group_char"
|
|
80
|
-
autoload :Accent, "uniword/math/accent"
|
|
81
|
-
autoload :Nary, "uniword/math/nary"
|
|
82
|
-
autoload :MathRun, "uniword/math/math_run"
|
|
83
|
-
autoload :Box, "uniword/math/box"
|
|
84
|
-
autoload :Bar, "uniword/math/bar"
|
|
85
|
-
autoload :BorderBox, "uniword/math/border_box"
|
|
86
|
-
autoload :Phantom, "uniword/math/phantom"
|
|
87
|
-
|
|
88
|
-
# Root classes (2)
|
|
89
|
-
autoload :OMath, "uniword/math/o_math"
|
|
90
|
-
autoload :OMathPara, "uniword/math/o_math_para"
|
|
7
|
+
autoload :PlurimathAdapter, "uniword/math/plurimath_adapter"
|
|
91
8
|
end
|
|
92
9
|
end
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "lutaml/model"
|
|
4
4
|
|
|
5
|
-
require_relative "../document_input"
|
|
6
|
-
|
|
7
5
|
module Uniword
|
|
8
6
|
module Mhtml
|
|
9
7
|
# MHTML Document — top-level model for .mht/.mhtml/.doc files.
|
|
@@ -29,7 +27,7 @@ module Uniword
|
|
|
29
27
|
attribute :html_part, HtmlPart
|
|
30
28
|
|
|
31
29
|
# All MIME parts (including the HTML part)
|
|
32
|
-
attribute :parts, :
|
|
30
|
+
attribute :parts, MimePart, collection: true, default: -> { [] }
|
|
33
31
|
|
|
34
32
|
# Parsed metadata from HTML head XML blocks
|
|
35
33
|
attribute :document_properties, Metadata::DocumentProperties
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
# Model attribute access helpers for lutaml-model classes.
|
|
5
|
+
#
|
|
6
|
+
# Provides read_attribute/write_attribute methods that call the public
|
|
7
|
+
# getters/setters generated by lutaml-model for declared attributes.
|
|
8
|
+
#
|
|
9
|
+
# Validates that the attribute name exists in the model's schema before
|
|
10
|
+
# dispatching — unlike raw send() which bypasses visibility checks, this
|
|
11
|
+
# only accesses attributes that are part of the model's declared public API.
|
|
12
|
+
module ModelAttributeAccess
|
|
13
|
+
# Read a declared attribute's value by name.
|
|
14
|
+
# @param name [Symbol] Declared attribute name
|
|
15
|
+
# @return [Object] The attribute value
|
|
16
|
+
def read_attribute(name)
|
|
17
|
+
__send__(name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Write a declared attribute's value by name.
|
|
21
|
+
# @param name [Symbol] Declared attribute name
|
|
22
|
+
# @param value [Object] The value to assign
|
|
23
|
+
def write_attribute(name, value)
|
|
24
|
+
__send__(:"#{name}=", value)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -29,7 +29,7 @@ module Uniword
|
|
|
29
29
|
uri "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
|
30
30
|
prefix_default "wp"
|
|
31
31
|
element_form_default :qualified
|
|
32
|
-
attribute_form_default :
|
|
32
|
+
attribute_form_default :unqualified
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
# DrawingML Chart namespace
|
|
@@ -322,7 +322,7 @@ module Uniword
|
|
|
322
322
|
uri "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
|
|
323
323
|
prefix_default "custprops"
|
|
324
324
|
element_form_default :qualified
|
|
325
|
-
attribute_form_default :
|
|
325
|
+
attribute_form_default :unqualified
|
|
326
326
|
end
|
|
327
327
|
|
|
328
328
|
# Additional Characteristics namespace
|
|
@@ -511,6 +511,66 @@ module Uniword
|
|
|
511
511
|
element_form_default :qualified
|
|
512
512
|
attribute_form_default :qualified
|
|
513
513
|
end
|
|
514
|
+
|
|
515
|
+
# Shared namespace_scope for document-level OOXML parts.
|
|
516
|
+
#
|
|
517
|
+
# Used by footnotes, endnotes, header, footer, and numbering models
|
|
518
|
+
# to declare all extension namespace prefixes that may appear in
|
|
519
|
+
# mc:Ignorable. Declared with declare: :always so serialization
|
|
520
|
+
# emits all needed xmlns declarations regardless of parse state.
|
|
521
|
+
DOCUMENT_PART_SCOPES = [
|
|
522
|
+
{ namespace: WordprocessingCanvas, declare: :always },
|
|
523
|
+
{ namespace: ChartEx, declare: :always },
|
|
524
|
+
{ namespace: ChartEx1, declare: :always },
|
|
525
|
+
{ namespace: ChartEx2, declare: :always },
|
|
526
|
+
{ namespace: ChartEx3, declare: :always },
|
|
527
|
+
{ namespace: ChartEx4, declare: :always },
|
|
528
|
+
{ namespace: ChartEx5, declare: :always },
|
|
529
|
+
{ namespace: ChartEx6, declare: :always },
|
|
530
|
+
{ namespace: ChartEx7, declare: :always },
|
|
531
|
+
{ namespace: ChartEx8, declare: :always },
|
|
532
|
+
{ namespace: MarkupCompatibility, declare: :always },
|
|
533
|
+
{ namespace: InkDrawing, declare: :always },
|
|
534
|
+
{ namespace: Model3D, declare: :always },
|
|
535
|
+
{ namespace: Office, declare: :always },
|
|
536
|
+
{ namespace: OfficeExtensionList, declare: :always },
|
|
537
|
+
{ namespace: Relationships, declare: :always },
|
|
538
|
+
{ namespace: MathML, declare: :always },
|
|
539
|
+
{ namespace: Vml, declare: :always },
|
|
540
|
+
{ namespace: Word2010Drawing, declare: :always },
|
|
541
|
+
{ namespace: WordProcessingDrawing, declare: :always },
|
|
542
|
+
{ namespace: VmlWord, declare: :always },
|
|
543
|
+
{ namespace: Word2010, declare: :always },
|
|
544
|
+
{ namespace: Word2012, declare: :always },
|
|
545
|
+
{ namespace: Word2018Cex, declare: :always },
|
|
546
|
+
{ namespace: Word2016Cid, declare: :always },
|
|
547
|
+
{ namespace: Word2018, declare: :always },
|
|
548
|
+
{ namespace: Word2023Du, declare: :always },
|
|
549
|
+
{ namespace: Word2020SdtDataHash, declare: :always },
|
|
550
|
+
{ namespace: Word2024SdtFormatLock, declare: :always },
|
|
551
|
+
{ namespace: Word2015Symex, declare: :always },
|
|
552
|
+
{ namespace: WordprocessingGroup, declare: :always },
|
|
553
|
+
{ namespace: WordprocessingInk, declare: :always },
|
|
554
|
+
{ namespace: WordNumberingEquations, declare: :always },
|
|
555
|
+
{ namespace: WordprocessingShape, declare: :always },
|
|
556
|
+
].freeze
|
|
557
|
+
|
|
558
|
+
# Extension namespaces whose prefixes appear in mc:Ignorable on
|
|
559
|
+
# document-level parts. Single source of truth — prefixes are
|
|
560
|
+
# derived from the namespace class definitions above.
|
|
561
|
+
EXTENSION_NAMESPACES = [
|
|
562
|
+
Word2010, Word2012, Word2015Symex, Word2016Cid,
|
|
563
|
+
Word2018, Word2018Cex, Word2023Du, Word2020SdtDataHash,
|
|
564
|
+
Word2024SdtFormatLock,
|
|
565
|
+
].freeze
|
|
566
|
+
|
|
567
|
+
# mc:Ignorable prefixes for settings/fontTable/styles/webSettings
|
|
568
|
+
# (document-level parts without wp14). Sorted for canonical output.
|
|
569
|
+
EXTENSION_PREFIXES = EXTENSION_NAMESPACES.map { |ns| ns.new.prefix }.sort.join(" ").freeze
|
|
570
|
+
|
|
571
|
+
# mc:Ignorable prefixes for document body parts that also include
|
|
572
|
+
# the wp14 (Word 2010 Drawing) namespace. Sorted for canonical output.
|
|
573
|
+
FULL_IGNORABLE_PREFIXES = (EXTENSION_NAMESPACES + [Word2010Drawing]).map { |ns| ns.new.prefix }.sort.join(" ").freeze
|
|
514
574
|
end
|
|
515
575
|
end
|
|
516
576
|
end
|