uniword 1.2.5 → 1.4.0
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/CHANGELOG.md +313 -0
- data/CONTRIBUTING.md +1 -1
- data/config/ooxml/schemas/shared_types.yml +5 -4
- data/data/schemas/ecma/dc.xsd +118 -0
- data/data/schemas/ecma/dcmitype.xsd +50 -0
- data/data/schemas/ecma/dcterms.xsd +331 -0
- data/data/schemas/ecma/opc-coreProperties.xsd +2 -2
- data/data/schemas/ecma/xml.xsd +117 -0
- data/lib/uniword/builder/bibliography_builder.rb +1 -1
- data/lib/uniword/builder/chart_builder.rb +22 -14
- data/lib/uniword/builder/comment_anchorer.rb +221 -0
- data/lib/uniword/builder/document_builder.rb +97 -6
- data/lib/uniword/builder/image_builder.rb +11 -10
- data/lib/uniword/builder/run_utils.rb +2 -0
- data/lib/uniword/builder.rb +1 -0
- data/lib/uniword/cli/fonts_cli.rb +52 -0
- data/lib/uniword/cli/main.rb +110 -11
- data/lib/uniword/cli/page_cli.rb +85 -0
- data/lib/uniword/cli/styles_cli.rb +204 -0
- data/lib/uniword/cli/theme_cli.rb +88 -0
- data/lib/uniword/cli/toc_cli.rb +22 -2
- data/lib/uniword/comment.rb +20 -15
- data/lib/uniword/comment_range.rb +3 -3
- data/lib/uniword/comments_part.rb +51 -19
- data/lib/uniword/configuration/configuration_loader.rb +5 -3
- data/lib/uniword/configuration.rb +93 -1
- data/lib/uniword/content_types.rb +19 -39
- data/lib/uniword/document_factory.rb +12 -18
- data/lib/uniword/document_writer.rb +16 -5
- data/lib/uniword/docx/chart_part.rb +34 -0
- data/lib/uniword/docx/custom_xml_item.rb +91 -0
- data/lib/uniword/docx/header_footer_part.rb +140 -0
- data/lib/uniword/docx/header_footer_part_collection.rb +135 -0
- data/lib/uniword/docx/header_footer_view.rb +225 -0
- data/lib/uniword/docx/id_allocator.rb +130 -36
- data/lib/uniword/docx/image_part.rb +83 -0
- data/lib/uniword/docx/package.rb +141 -333
- data/lib/uniword/docx/package_defaults.rb +83 -99
- data/lib/uniword/docx/package_integrity_checker.rb +312 -0
- data/lib/uniword/docx/package_serialization.rb +144 -233
- data/lib/uniword/docx/part.rb +125 -0
- data/lib/uniword/docx/part_collection.rb +131 -0
- data/lib/uniword/docx/part_loader/chart_loader.rb +50 -0
- data/lib/uniword/docx/part_loader/custom_xml_loader.rb +53 -0
- data/lib/uniword/docx/part_loader/embedding_loader.rb +26 -0
- data/lib/uniword/docx/part_loader/header_footer_loader.rb +101 -0
- data/lib/uniword/docx/part_loader/image_loader.rb +105 -0
- data/lib/uniword/docx/part_loader/load_context.rb +85 -0
- data/lib/uniword/docx/part_loader/raw_part_loader.rb +183 -0
- data/lib/uniword/docx/part_loader/theme_media_loader.rb +39 -0
- data/lib/uniword/docx/part_loader/xml_model_loader.rb +56 -0
- data/lib/uniword/docx/part_loader.rb +92 -0
- data/lib/uniword/docx/raw_part.rb +75 -0
- data/lib/uniword/docx/reconciler/body.rb +59 -68
- data/lib/uniword/docx/reconciler/fix.rb +46 -0
- data/lib/uniword/docx/reconciler/fix_codes.rb +37 -30
- data/lib/uniword/docx/reconciler/helpers.rb +18 -31
- data/lib/uniword/docx/reconciler/notes.rb +17 -8
- data/lib/uniword/docx/reconciler/package_structure.rb +168 -221
- data/lib/uniword/docx/reconciler/parts.rb +36 -13
- data/lib/uniword/docx/reconciler/referential_integrity.rb +222 -123
- data/lib/uniword/docx/reconciler/tables.rb +78 -16
- data/lib/uniword/docx/reconciler/theme.rb +7 -4
- data/lib/uniword/docx/reconciler.rb +36 -14
- data/lib/uniword/docx.rb +13 -0
- data/lib/uniword/drawingml/blip.rb +0 -1
- data/lib/uniword/drawingml/color_scheme.rb +5 -6
- data/lib/uniword/drawingml/font_scheme.rb +4 -8
- data/lib/uniword/drawingml/theme.rb +12 -6
- data/lib/uniword/errors.rb +8 -1
- data/lib/uniword/footer.rb +4 -0
- data/lib/uniword/header.rb +4 -0
- data/lib/uniword/hyperlink.rb +1 -1
- data/lib/uniword/image.rb +6 -6
- data/lib/uniword/images/image_manager.rb +13 -13
- data/lib/uniword/lazy_loader.rb +1 -2
- data/lib/uniword/model_attribute_access.rb +20 -4
- data/lib/uniword/ooxml/dotx_package.rb +42 -2
- data/lib/uniword/ooxml/element_order.rb +94 -0
- data/lib/uniword/ooxml/part_definition.rb +329 -0
- data/lib/uniword/ooxml/part_registry.rb +504 -0
- data/lib/uniword/ooxml/relationships/image_relationship.rb +6 -3
- data/lib/uniword/ooxml/relationships/package_relationships.rb +20 -22
- data/lib/uniword/ooxml/schema/element_serializer.rb +8 -7
- data/lib/uniword/ooxml/types/hex_color_value.rb +38 -0
- data/lib/uniword/ooxml/types/ooxml_boolean.rb +27 -14
- data/lib/uniword/ooxml/types/ooxml_boolean_optional.rb +21 -16
- data/lib/uniword/ooxml/types/theme_color_value.rb +22 -0
- data/lib/uniword/ooxml/types/unsigned_decimal_number.rb +30 -0
- data/lib/uniword/ooxml/types.rb +10 -0
- data/lib/uniword/ooxml.rb +3 -0
- data/lib/uniword/properties/alignment.rb +8 -3
- data/lib/uniword/properties/border.rb +52 -6
- data/lib/uniword/properties/cell_vertical_align.rb +4 -1
- data/lib/uniword/properties/color_value.rb +8 -3
- data/lib/uniword/properties/highlight.rb +9 -5
- data/lib/uniword/properties/shading.rb +4 -3
- data/lib/uniword/properties/tab_stop.rb +6 -1
- data/lib/uniword/properties/table_justification.rb +4 -1
- data/lib/uniword/properties/underline.rb +4 -2
- data/lib/uniword/properties/vertical_align.rb +6 -3
- data/lib/uniword/review/review_manager.rb +23 -9
- data/lib/uniword/revision.rb +9 -9
- data/lib/uniword/schema/model_generator.rb +31 -15
- data/lib/uniword/shared_types/hex_color.rb +4 -1
- data/lib/uniword/shared_types/pixel_measure.rb +4 -1
- data/lib/uniword/shared_types/point_measure.rb +4 -1
- data/lib/uniword/shared_types/text_alignment.rb +6 -1
- data/lib/uniword/shared_types/twips_measure.rb +4 -1
- data/lib/uniword/spreadsheetml/phonetic_pr.rb +1 -1
- data/lib/uniword/spreadsheetml/shared_string_table.rb +2 -2
- data/lib/uniword/spreadsheetml/table_formula.rb +1 -1
- data/lib/uniword/template/variable_resolver.rb +40 -7
- data/lib/uniword/themes/theme_transformation.rb +55 -41
- data/lib/uniword/toc/toc_generator.rb +6 -5
- data/lib/uniword/transformation/mhtml_element_renderer.rb +1 -5
- data/lib/uniword/transformation/mhtml_metadata_builder.rb +6 -6
- data/lib/uniword/validation/engine.rb +35 -0
- data/lib/uniword/validation/link_checker.rb +1 -1
- data/lib/uniword/validation/opc_validator.rb +16 -2
- data/lib/uniword/validation/report/layer_result.rb +0 -1
- data/lib/uniword/validation/report/terminal_formatter.rb +0 -1
- data/lib/uniword/validation/report/verification_report.rb +0 -2
- data/lib/uniword/validation/report.rb +20 -0
- data/lib/uniword/validation/rules/base.rb +10 -2
- data/lib/uniword/validation/rules/bookmark_pairing_rule.rb +38 -0
- data/lib/uniword/validation/rules/bookmark_uniqueness_rule.rb +48 -0
- data/lib/uniword/validation/rules/bookmarks_rule.rb +0 -2
- data/lib/uniword/validation/rules/content_types_coverage_rule.rb +0 -2
- data/lib/uniword/validation/rules/core_properties_namespace_rule.rb +0 -2
- data/lib/uniword/validation/rules/document_body_rule.rb +25 -0
- data/lib/uniword/validation/rules/document_context.rb +7 -0
- data/lib/uniword/validation/rules/empty_paragraphs_rule.rb +27 -0
- data/lib/uniword/validation/rules/font_table_signature_rule.rb +0 -2
- data/lib/uniword/validation/rules/fonts_rule.rb +0 -2
- data/lib/uniword/validation/rules/footnotes_rule.rb +0 -2
- data/lib/uniword/validation/rules/headers_footers_rule.rb +0 -2
- data/lib/uniword/validation/rules/images_rule.rb +0 -2
- data/lib/uniword/validation/rules/mc_ignorable_namespace_rule.rb +0 -2
- data/lib/uniword/validation/rules/model_context.rb +32 -0
- data/lib/uniword/validation/rules/model_rule.rb +34 -0
- data/lib/uniword/validation/rules/numbering_preservation_rule.rb +0 -2
- data/lib/uniword/validation/rules/numbering_rule.rb +0 -2
- data/lib/uniword/validation/rules/relationship_integrity_rule.rb +0 -1
- data/lib/uniword/validation/rules/rsid_rule.rb +0 -2
- data/lib/uniword/validation/rules/section_properties_rule.rb +0 -2
- data/lib/uniword/validation/rules/settings_rule.rb +0 -2
- data/lib/uniword/validation/rules/settings_values_rule.rb +0 -2
- data/lib/uniword/validation/rules/style_references_rule.rb +0 -2
- data/lib/uniword/validation/rules/table_grid_rule.rb +27 -0
- data/lib/uniword/validation/rules/table_properties_rule.rb +27 -0
- data/lib/uniword/validation/rules/tables_rule.rb +0 -2
- data/lib/uniword/validation/rules/theme_completeness_rule.rb +0 -2
- data/lib/uniword/validation/rules/theme_rule.rb +0 -2
- data/lib/uniword/validation/rules.rb +61 -23
- data/lib/uniword/validation/schema_registry.rb +11 -0
- data/lib/uniword/validation/validators/document_semantics_validator.rb +1 -9
- data/lib/uniword/validation/validators/xml_schema_validator.rb +46 -2
- data/lib/uniword/validation/validators.rb +0 -9
- data/lib/uniword/validation/verify_orchestrator.rb +0 -7
- data/lib/uniword/validation.rb +7 -2
- data/lib/uniword/version.rb +1 -1
- data/lib/uniword/vml/imagedata.rb +0 -1
- data/lib/uniword/wordprocessingml/attached_template.rb +0 -1
- data/lib/uniword/wordprocessingml/deleted_text.rb +1 -1
- data/lib/uniword/wordprocessingml/document_root.rb +121 -122
- data/lib/uniword/wordprocessingml/document_styling.rb +246 -0
- data/lib/uniword/wordprocessingml/endnotes.rb +4 -1
- data/lib/uniword/wordprocessingml/font_replacer.rb +147 -0
- data/lib/uniword/wordprocessingml/footnotes.rb +4 -1
- data/lib/uniword/wordprocessingml/hdr_shape_defaults.rb +0 -1
- data/lib/uniword/wordprocessingml/hyperlink.rb +0 -1
- data/lib/uniword/wordprocessingml/level.rb +6 -20
- data/lib/uniword/wordprocessingml/math_pr.rb +0 -11
- data/lib/uniword/wordprocessingml/numbering_definition.rb +16 -8
- data/lib/uniword/wordprocessingml/numbering_elements.rb +0 -15
- data/lib/uniword/wordprocessingml/page_setup.rb +181 -0
- data/lib/uniword/wordprocessingml/paragraph_properties.rb +33 -28
- data/lib/uniword/wordprocessingml/rsids.rb +0 -2
- data/lib/uniword/wordprocessingml/run.rb +3 -0
- data/lib/uniword/wordprocessingml/section_properties.rb +2 -2
- data/lib/uniword/wordprocessingml/settings.rb +8 -34
- data/lib/uniword/wordprocessingml/shape_defaults.rb +0 -1
- data/lib/uniword/wordprocessingml/style.rb +2 -1
- data/lib/uniword/wordprocessingml/style_cleanup.rb +198 -0
- data/lib/uniword/wordprocessingml/table_cell_properties.rb +6 -6
- data/lib/uniword/wordprocessingml/update_fields.rb +27 -0
- data/lib/uniword/wordprocessingml/w14_attributes.rb +30 -2
- data/lib/uniword/wordprocessingml.rb +5 -2
- data/lib/uniword.rb +27 -2
- metadata +52 -19
- data/config/validation_rules.yml +0 -60
- data/config/warning_rules.yml +0 -57
- data/lib/uniword/validation/document_validator.rb +0 -272
- data/lib/uniword/validation/structural_validator.rb +0 -116
- data/lib/uniword/validation/validators/content_type_validator.rb +0 -165
- data/lib/uniword/validation/validators/file_structure_validator.rb +0 -104
- data/lib/uniword/validation/validators/ooxml_part_validator.rb +0 -128
- data/lib/uniword/validation/validators/relationship_validator.rb +0 -147
- data/lib/uniword/validation/validators/zip_integrity_validator.rb +0 -110
- data/lib/uniword/validators/element_validator.rb +0 -93
- data/lib/uniword/validators/paragraph_validator.rb +0 -116
- data/lib/uniword/validators/table_validator.rb +0 -134
- data/lib/uniword/validators.rb +0 -9
- data/lib/uniword/warnings/warning.rb +0 -130
- data/lib/uniword/warnings/warning_collector.rb +0 -234
- data/lib/uniword/warnings/warning_report.rb +0 -159
- data/lib/uniword/warnings.rb +0 -9
|
@@ -2,34 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "lutaml/model"
|
|
4
4
|
require "nokogiri"
|
|
5
|
-
require_relative "../properties/relationship_id"
|
|
6
|
-
require_relative "zoom"
|
|
7
|
-
require_relative "compat"
|
|
8
|
-
require_relative "proof_state"
|
|
9
|
-
require_relative "style_pane_format_filter"
|
|
10
|
-
require_relative "default_tab_stop"
|
|
11
|
-
require_relative "character_spacing_control"
|
|
12
|
-
require_relative "do_not_display_page_boundaries"
|
|
13
|
-
require_relative "rsids"
|
|
14
|
-
require_relative "math_pr"
|
|
15
|
-
require_relative "theme_font_lang"
|
|
16
|
-
require_relative "clr_scheme_mapping"
|
|
17
|
-
require_relative "shape_defaults"
|
|
18
|
-
require_relative "decimal_symbol"
|
|
19
|
-
require_relative "list_separator"
|
|
20
|
-
require_relative "attached_template"
|
|
21
|
-
require_relative "footnote_pr"
|
|
22
|
-
require_relative "endnote_pr"
|
|
23
|
-
require_relative "hdr_shape_defaults"
|
|
24
|
-
require_relative "even_and_odd_headers"
|
|
25
|
-
require_relative "mirror_margins"
|
|
26
|
-
require_relative "do_not_include_subdocs_in_stats"
|
|
27
|
-
require_relative "hyphenation_zone"
|
|
28
|
-
require_relative "style_pane_sort_method"
|
|
29
|
-
require_relative "doc_vars"
|
|
30
|
-
require_relative "w14_doc_id"
|
|
31
|
-
require_relative "w15_chart_tracking_ref_based"
|
|
32
|
-
require_relative "w15_doc_id"
|
|
33
5
|
|
|
34
6
|
module Uniword
|
|
35
7
|
module Wordprocessingml
|
|
@@ -57,6 +29,7 @@ module Uniword
|
|
|
57
29
|
attribute :footnote_pr, FootnotePr
|
|
58
30
|
attribute :endnote_pr, EndnotePr
|
|
59
31
|
attribute :hdr_shape_defaults, HdrShapeDefaults
|
|
32
|
+
attribute :update_fields, UpdateFields
|
|
60
33
|
attribute :even_and_odd_headers, EvenAndOddHeaders
|
|
61
34
|
attribute :mirror_margins, MirrorMargins
|
|
62
35
|
attribute :do_not_include_subdocs_in_stats,
|
|
@@ -112,9 +85,9 @@ module Uniword
|
|
|
112
85
|
map_element "doNotDisplayPageBoundaries",
|
|
113
86
|
to: :do_not_display_page_boundaries, render_nil: false
|
|
114
87
|
map_element "mirrorMargins", to: :mirror_margins, render_nil: false
|
|
88
|
+
map_element "proofState", to: :proof_state, render_nil: false
|
|
115
89
|
map_element "attachedTemplate", to: :attached_template,
|
|
116
90
|
render_nil: false
|
|
117
|
-
map_element "proofState", to: :proof_state, render_nil: false
|
|
118
91
|
map_element "stylePaneFormatFilter", to: :style_pane_format_filter,
|
|
119
92
|
render_nil: false
|
|
120
93
|
map_element "stylePaneSortMethod", to: :style_pane_sort_method,
|
|
@@ -126,6 +99,9 @@ module Uniword
|
|
|
126
99
|
render_nil: false
|
|
127
100
|
map_element "characterSpacingControl", to: :character_spacing_control,
|
|
128
101
|
render_nil: false
|
|
102
|
+
map_element "updateFields", to: :update_fields, render_nil: false
|
|
103
|
+
map_element "hdrShapeDefaults", to: :hdr_shape_defaults,
|
|
104
|
+
render_nil: false
|
|
129
105
|
map_element "footnotePr", to: :footnote_pr, render_nil: false
|
|
130
106
|
map_element "endnotePr", to: :endnote_pr, render_nil: false
|
|
131
107
|
map_element "compat", to: :compat, render_nil: false
|
|
@@ -137,11 +113,6 @@ module Uniword
|
|
|
137
113
|
render_nil: false
|
|
138
114
|
map_element "doNotIncludeSubdocsInStats",
|
|
139
115
|
to: :do_not_include_subdocs_in_stats, render_nil: false
|
|
140
|
-
map_element "hdrShapeDefaults", to: :hdr_shape_defaults,
|
|
141
|
-
render_nil: false
|
|
142
|
-
map_element "shapeDefaults", to: :shape_defaults, render_nil: false
|
|
143
|
-
map_element "decimalSymbol", to: :decimal_symbol, render_nil: false
|
|
144
|
-
map_element "listSeparator", to: :list_separator, render_nil: false
|
|
145
116
|
# Both w14:docId and w15:docId use the same element name 'docId'
|
|
146
117
|
# Separate map_element entries needed for namespace-aware matching
|
|
147
118
|
# The namespace_scope ensures w14 and w15 namespaces are declared on root
|
|
@@ -150,6 +121,9 @@ module Uniword
|
|
|
150
121
|
map_element "docId", to: :w14_doc_id, render_nil: false
|
|
151
122
|
map_element "docId", to: :w15_doc_id, render_nil: false
|
|
152
123
|
map_element "schemaLibrary", to: :schema_library, render_nil: false
|
|
124
|
+
map_element "shapeDefaults", to: :shape_defaults, render_nil: false
|
|
125
|
+
map_element "decimalSymbol", to: :decimal_symbol, render_nil: false
|
|
126
|
+
map_element "listSeparator", to: :list_separator, render_nil: false
|
|
153
127
|
end
|
|
154
128
|
|
|
155
129
|
# Override from_xml to manually deserialize w15:docId which has the same
|
|
@@ -49,7 +49,8 @@ module Uniword
|
|
|
49
49
|
map "run_properties", to: :rPr
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
# YAML transform methods (instance methods
|
|
52
|
+
# YAML transform methods (instance methods called by lutaml-model's
|
|
53
|
+
# `with:` transform mechanism)
|
|
53
54
|
def yaml_name_from(instance, value)
|
|
54
55
|
instance.name = StyleName.new(val: value) if value
|
|
55
56
|
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uniword
|
|
4
|
+
module Wordprocessingml
|
|
5
|
+
# Removes styles from a document's style definitions — Word's
|
|
6
|
+
# Styles-pane management as an API.
|
|
7
|
+
#
|
|
8
|
+
# `#remove_unused` deletes styles that no content references,
|
|
9
|
+
# directly (pStyle/rStyle/tblStyle in body, headers, footers, notes,
|
|
10
|
+
# comments) or transitively (basedOn/link/next chains from a used
|
|
11
|
+
# style, numbering level pStyle). Default styles (w:default="1")
|
|
12
|
+
# are never removed.
|
|
13
|
+
#
|
|
14
|
+
# @example Declutter a document
|
|
15
|
+
# cleanup = StyleCleanup.new(document)
|
|
16
|
+
# removed = cleanup.remove_unused # => ["ObsoleteStyle", ...]
|
|
17
|
+
class StyleCleanup
|
|
18
|
+
# @param document [DocumentRoot] Document to clean (mutated)
|
|
19
|
+
def initialize(document)
|
|
20
|
+
@document = document
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Remove one style by id (unless protected).
|
|
24
|
+
#
|
|
25
|
+
# @param style_id [String] Style id (w:styleId)
|
|
26
|
+
# @return [Boolean] true when the style was removed
|
|
27
|
+
def remove?(style_id)
|
|
28
|
+
return false if protected_id?(style_id)
|
|
29
|
+
|
|
30
|
+
before = styles.size
|
|
31
|
+
styles.delete_if { |style| style.styleId == style_id }
|
|
32
|
+
styles.size < before
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Ids of styles no content references.
|
|
36
|
+
#
|
|
37
|
+
# @return [Array<String>] Unreferenced, unprotected style ids
|
|
38
|
+
def unused_ids
|
|
39
|
+
used = used_ids
|
|
40
|
+
styles.filter_map(&:styleId).uniq - used - protected_ids
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Remove every unreferenced style.
|
|
44
|
+
#
|
|
45
|
+
# @return [Array<String>] Ids of removed styles
|
|
46
|
+
def remove_unused
|
|
47
|
+
ids = unused_ids
|
|
48
|
+
ids.each { |id| remove?(id) }
|
|
49
|
+
ids
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def styles
|
|
55
|
+
@document.styles_configuration.styles
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def protected_ids
|
|
59
|
+
styles.select(&:default).map(&:styleId)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def protected_id?(style_id)
|
|
63
|
+
protected_ids.include?(style_id)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Ids referenced anywhere: content, notes, headers/footers,
|
|
67
|
+
# comments, numbering levels, and style-to-style chains.
|
|
68
|
+
def used_ids
|
|
69
|
+
used = content_style_ids + chain_seed_ids
|
|
70
|
+
expand_chains(used)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def content_style_ids
|
|
74
|
+
ids = []
|
|
75
|
+
walk_all_paragraphs do |paragraph|
|
|
76
|
+
ids.concat(paragraph_style_ids(paragraph))
|
|
77
|
+
ids.concat(run_style_ids(paragraph))
|
|
78
|
+
end
|
|
79
|
+
ids.concat(table_style_ids)
|
|
80
|
+
ids.concat(numbering_style_ids)
|
|
81
|
+
ids
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Styles referenced by other styles (basedOn/link/next) — chains
|
|
85
|
+
# are expanded from these too.
|
|
86
|
+
def chain_seed_ids
|
|
87
|
+
styles.flat_map { |style| chain_links(style) }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def chain_links(style)
|
|
91
|
+
[style.basedOn&.val, style.link&.val, style.nextStyle&.val].compact
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def expand_chains(ids)
|
|
95
|
+
expanded = ids.to_set
|
|
96
|
+
loop do
|
|
97
|
+
additions = chain_additions(expanded)
|
|
98
|
+
break if additions.empty?
|
|
99
|
+
|
|
100
|
+
additions.each { |id| expanded << id }
|
|
101
|
+
end
|
|
102
|
+
expanded.to_a
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def chain_additions(expanded)
|
|
106
|
+
styles.select { |style| expanded.include?(style.styleId) }
|
|
107
|
+
.flat_map { |style| chain_links(style) }
|
|
108
|
+
.reject { |id| expanded.include?(id) }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def paragraph_style_ids(paragraph)
|
|
112
|
+
Array(paragraph.properties&.style).filter_map(&:value)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def run_style_ids(paragraph)
|
|
116
|
+
paragraph_runs(paragraph)
|
|
117
|
+
.filter_map { |run| run.properties&.style&.value }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def paragraph_runs(paragraph)
|
|
121
|
+
(paragraph.runs || []) +
|
|
122
|
+
(paragraph.hyperlinks || []).flat_map(&:runs)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def table_style_ids
|
|
126
|
+
ids = []
|
|
127
|
+
walk_tables(@document.body) do |table|
|
|
128
|
+
ids << table.properties&.style&.val
|
|
129
|
+
end
|
|
130
|
+
ids.compact
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def numbering_style_ids
|
|
134
|
+
numbering_definitions.flat_map do |definition|
|
|
135
|
+
(definition.levels || []).filter_map { |level| level.pStyle&.val }
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def numbering_definitions
|
|
140
|
+
@document.numbering_configuration&.definitions || []
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Paragraphs in body (incl. table cells), headers/footers,
|
|
144
|
+
# notes, comments.
|
|
145
|
+
def walk_all_paragraphs(&block)
|
|
146
|
+
each_container { |container| walk_paragraphs(container, &block) }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def walk_paragraphs(container, &block)
|
|
150
|
+
return unless container
|
|
151
|
+
|
|
152
|
+
(container.paragraphs || []).each(&block)
|
|
153
|
+
walk_tables(container) { |table| walk_table_rows(table, &block) }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def walk_table_rows(table, &block)
|
|
157
|
+
(table.rows || []).each do |row|
|
|
158
|
+
(row.cells || []).each { |cell| walk_paragraphs(cell, &block) }
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def walk_tables(container, &block)
|
|
163
|
+
return unless container
|
|
164
|
+
|
|
165
|
+
(container.tables || []).each do |table|
|
|
166
|
+
yield table
|
|
167
|
+
walk_table_cells(table, &block)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def walk_table_cells(table, &block)
|
|
172
|
+
(table.rows || []).each do |row|
|
|
173
|
+
(row.cells || []).each { |cell| walk_tables(cell, &block) }
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def each_container(&block)
|
|
178
|
+
yield @document.body if @document.body
|
|
179
|
+
header_footer_containers.each(&block)
|
|
180
|
+
note_containers.each(&block)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def header_footer_containers
|
|
184
|
+
(@document.header_footer_parts || []).filter_map do |part|
|
|
185
|
+
part.content if part.content.is_a?(Lutaml::Model::Serializable)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def note_containers
|
|
190
|
+
[
|
|
191
|
+
@document.footnotes&.footnote_entries,
|
|
192
|
+
@document.endnotes&.endnote_entries,
|
|
193
|
+
@document.comments&.comments,
|
|
194
|
+
].flatten.compact
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -28,18 +28,18 @@ module Uniword
|
|
|
28
28
|
namespace Uniword::Ooxml::Namespaces::WordProcessingML
|
|
29
29
|
mixed_content
|
|
30
30
|
|
|
31
|
+
map_element "cnfStyle", to: :cnf_style, render_nil: false
|
|
31
32
|
map_element "tcW", to: :cell_width, render_nil: false
|
|
32
|
-
map_element "tcBorders", to: :borders, render_nil: false
|
|
33
|
-
map_element "shd", to: :shading, render_nil: false
|
|
34
|
-
map_element "vAlign", to: :vertical_align, render_nil: false
|
|
35
33
|
map_element "gridSpan", to: :grid_span, render_nil: false
|
|
36
34
|
map_element "vMerge", to: :v_merge, render_nil: false
|
|
37
|
-
map_element "
|
|
38
|
-
map_element "
|
|
35
|
+
map_element "tcBorders", to: :borders, render_nil: false
|
|
36
|
+
map_element "shd", to: :shading, render_nil: false
|
|
39
37
|
map_element "noWrap", to: :no_wrap, render_nil: false
|
|
40
|
-
map_element "
|
|
38
|
+
map_element "tcMar", to: :tc_mar, render_nil: false
|
|
41
39
|
map_element "textDirection", to: :text_direction,
|
|
42
40
|
render_nil: false
|
|
41
|
+
map_element "vAlign", to: :vertical_align, render_nil: false
|
|
42
|
+
map_element "hideMark", to: :hide_mark, render_nil: false
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Uniword
|
|
6
|
+
module Wordprocessingml
|
|
7
|
+
# Update fields when the document is opened
|
|
8
|
+
#
|
|
9
|
+
# Element: <w:updateFields>
|
|
10
|
+
#
|
|
11
|
+
# When true, Word updates all fields (TOC, page numbers, cross
|
|
12
|
+
# references) the first time the document is opened — generated
|
|
13
|
+
# documents show correct field values without a manual F9.
|
|
14
|
+
class UpdateFields < Lutaml::Model::Serializable
|
|
15
|
+
attribute :value, Ooxml::Types::OoxmlBoolean,
|
|
16
|
+
default: -> { true }
|
|
17
|
+
|
|
18
|
+
xml do
|
|
19
|
+
element "updateFields"
|
|
20
|
+
namespace Uniword::Ooxml::Namespaces::WordProcessingML
|
|
21
|
+
|
|
22
|
+
map_attribute "val", to: :value, render_nil: false,
|
|
23
|
+
render_default: false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -16,15 +16,43 @@ module Uniword
|
|
|
16
16
|
# W16CID namespace for Word 2016+ citation identifiers
|
|
17
17
|
W16CID_NAMESPACE = Uniword::Ooxml::Namespaces::Word2016Cid
|
|
18
18
|
|
|
19
|
-
#
|
|
19
|
+
# ST_LongHexNumber (ECMA-376): exactly 8 hexadecimal digits
|
|
20
|
+
LONG_HEX_NUMBER_PATTERN = /\A[0-9A-Fa-f]{8}\z/
|
|
21
|
+
|
|
22
|
+
# Validate an ST_LongHexNumber value at cast time
|
|
23
|
+
#
|
|
24
|
+
# @param value [Object] the raw value
|
|
25
|
+
# @return [String, nil, Object] the validated value
|
|
26
|
+
# @raise [Lutaml::Model::Type::InvalidValueError] when the value is
|
|
27
|
+
# not 8 hexadecimal digits
|
|
28
|
+
def self.cast_long_hex_number(value)
|
|
29
|
+
casted = Lutaml::Model::Type::String.cast(value)
|
|
30
|
+
return casted if casted.nil? ||
|
|
31
|
+
Lutaml::Model::Utils.uninitialized?(casted)
|
|
32
|
+
return casted if LONG_HEX_NUMBER_PATTERN.match?(casted)
|
|
33
|
+
|
|
34
|
+
raise Lutaml::Model::Type::InvalidValueError.new(
|
|
35
|
+
value, ["ST_LongHexNumber: 8 hexadecimal digits"]
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Typed attribute for w14:paraId (ST_LongHexNumber)
|
|
20
40
|
class W14ParaId < Lutaml::Model::Type::String
|
|
41
|
+
def self.cast(value, _options = {})
|
|
42
|
+
Wordprocessingml.cast_long_hex_number(value)
|
|
43
|
+
end
|
|
44
|
+
|
|
21
45
|
xml do
|
|
22
46
|
namespace W14_NAMESPACE
|
|
23
47
|
end
|
|
24
48
|
end
|
|
25
49
|
|
|
26
|
-
# Typed attribute for w14:textId
|
|
50
|
+
# Typed attribute for w14:textId (ST_LongHexNumber)
|
|
27
51
|
class W14TextId < Lutaml::Model::Type::String
|
|
52
|
+
def self.cast(value, _options = {})
|
|
53
|
+
Wordprocessingml.cast_long_hex_number(value)
|
|
54
|
+
end
|
|
55
|
+
|
|
28
56
|
xml do
|
|
29
57
|
namespace W14_NAMESPACE
|
|
30
58
|
end
|
|
@@ -4,6 +4,7 @@ module Uniword
|
|
|
4
4
|
module Wordprocessingml
|
|
5
5
|
# Core document structure
|
|
6
6
|
autoload :DocumentRoot, "uniword/wordprocessingml/document_root"
|
|
7
|
+
autoload :DocumentStyling, "uniword/wordprocessingml/document_styling"
|
|
7
8
|
autoload :Body, "uniword/wordprocessingml/body"
|
|
8
9
|
autoload :Paragraph, "uniword/wordprocessingml/paragraph"
|
|
9
10
|
autoload :Run, "uniword/wordprocessingml/run"
|
|
@@ -64,6 +65,7 @@ module Uniword
|
|
|
64
65
|
# Structure and metadata
|
|
65
66
|
autoload :Level, "uniword/wordprocessingml/level"
|
|
66
67
|
autoload :Style, "uniword/wordprocessingml/style"
|
|
68
|
+
autoload :StyleCleanup, "uniword/wordprocessingml/style_cleanup"
|
|
67
69
|
autoload :StructuredDocumentTag,
|
|
68
70
|
"uniword/wordprocessingml/structured_document_tag"
|
|
69
71
|
autoload :StructuredDocumentTagProperties,
|
|
@@ -72,6 +74,7 @@ module Uniword
|
|
|
72
74
|
autoload :PageSize, "uniword/wordprocessingml/page_size"
|
|
73
75
|
autoload :PageMargins, "uniword/wordprocessingml/page_margins"
|
|
74
76
|
autoload :PageNumbering, "uniword/wordprocessingml/page_numbering"
|
|
77
|
+
autoload :PageSetup, "uniword/wordprocessingml/page_setup"
|
|
75
78
|
autoload :Columns, "uniword/wordprocessingml/columns"
|
|
76
79
|
autoload :HeaderReference, "uniword/wordprocessingml/header_reference"
|
|
77
80
|
autoload :FooterReference, "uniword/wordprocessingml/footer_reference"
|
|
@@ -130,6 +133,7 @@ module Uniword
|
|
|
130
133
|
|
|
131
134
|
# Fonts
|
|
132
135
|
autoload :Font, "uniword/wordprocessingml/font"
|
|
136
|
+
autoload :FontReplacer, "uniword/wordprocessingml/font_replacer"
|
|
133
137
|
autoload :Fonts, "uniword/wordprocessingml/fonts"
|
|
134
138
|
autoload :FontTable, "uniword/wordprocessingml/font_table"
|
|
135
139
|
|
|
@@ -162,9 +166,7 @@ module Uniword
|
|
|
162
166
|
autoload :NumFmt, "uniword/wordprocessingml/num_fmt"
|
|
163
167
|
autoload :LvlText, "uniword/wordprocessingml/lvl_text"
|
|
164
168
|
autoload :LvlJc, "uniword/wordprocessingml/lvl_jc"
|
|
165
|
-
autoload :Ind, "uniword/wordprocessingml/numbering_elements"
|
|
166
169
|
autoload :RFonts, "uniword/wordprocessingml/numbering_elements"
|
|
167
|
-
autoload :Tabs, "uniword/wordprocessingml/level"
|
|
168
170
|
autoload :PStyle, "uniword/wordprocessingml/level"
|
|
169
171
|
autoload :NumberingConfiguration,
|
|
170
172
|
"uniword/wordprocessingml/numbering_configuration"
|
|
@@ -191,6 +193,7 @@ module Uniword
|
|
|
191
193
|
autoload :Next, "uniword/wordprocessingml/next"
|
|
192
194
|
autoload :Link, "uniword/wordprocessingml/link"
|
|
193
195
|
autoload :UiPriority, "uniword/wordprocessingml/ui_priority"
|
|
196
|
+
autoload :UpdateFields, "uniword/wordprocessingml/update_fields"
|
|
194
197
|
autoload :LatentStyles, "uniword/wordprocessingml/latent_styles"
|
|
195
198
|
autoload :ParagraphStyle, "uniword/wordprocessingml/paragraph_style"
|
|
196
199
|
autoload :CharacterStyle, "uniword/wordprocessingml/character_style"
|
data/lib/uniword.rb
CHANGED
|
@@ -101,7 +101,6 @@ module Uniword
|
|
|
101
101
|
autoload :Template, "uniword/template"
|
|
102
102
|
autoload :TemplateManager, "uniword/template_manager"
|
|
103
103
|
autoload :Visitor, "uniword/visitor"
|
|
104
|
-
autoload :Validators, "uniword/validators"
|
|
105
104
|
autoload :Stylesets, "uniword/stylesets"
|
|
106
105
|
autoload :Infrastructure, "uniword/infrastructure"
|
|
107
106
|
autoload :Accessibility, "uniword/accessibility"
|
|
@@ -114,7 +113,6 @@ module Uniword
|
|
|
114
113
|
autoload :Configuration, "uniword/configuration"
|
|
115
114
|
autoload :Transformation, "uniword/transformation"
|
|
116
115
|
autoload :Validation, "uniword/validation"
|
|
117
|
-
autoload :Warnings, "uniword/warnings"
|
|
118
116
|
autoload :Mhtml, "uniword/mhtml"
|
|
119
117
|
autoload :Themes, "uniword/themes"
|
|
120
118
|
autoload :Resource, "uniword/resource"
|
|
@@ -135,6 +133,9 @@ module Uniword
|
|
|
135
133
|
# CLI
|
|
136
134
|
autoload :CLI, "uniword/cli/main"
|
|
137
135
|
autoload :GenerateCLI, "uniword/cli/generate_cli"
|
|
136
|
+
autoload :FontsCLI, "uniword/cli/fonts_cli"
|
|
137
|
+
autoload :PageCLI, "uniword/cli/page_cli"
|
|
138
|
+
autoload :StylesCLI, "uniword/cli/styles_cli"
|
|
138
139
|
autoload :DiffCLI, "uniword/cli/diff_cli"
|
|
139
140
|
autoload :TemplateCLI, "uniword/cli/template_cli"
|
|
140
141
|
autoload :CLIHelpers, "uniword/cli/helpers"
|
|
@@ -250,6 +251,30 @@ module Uniword
|
|
|
250
251
|
Wordprocessingml::DocumentRoot.new
|
|
251
252
|
end
|
|
252
253
|
|
|
254
|
+
# Get the global runtime configuration (memoized)
|
|
255
|
+
#
|
|
256
|
+
# @return [Configuration] The global configuration instance
|
|
257
|
+
#
|
|
258
|
+
# @example
|
|
259
|
+
# Uniword.configuration.validate_on_save # => true
|
|
260
|
+
def configuration
|
|
261
|
+
@configuration ||= Configuration.new
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Configure global runtime policy
|
|
265
|
+
#
|
|
266
|
+
# @yieldparam config [Configuration] The global configuration instance
|
|
267
|
+
# @return [Configuration] The global configuration instance
|
|
268
|
+
#
|
|
269
|
+
# @example
|
|
270
|
+
# Uniword.configure do |config|
|
|
271
|
+
# config.xsd_validation = true
|
|
272
|
+
# end
|
|
273
|
+
def configure
|
|
274
|
+
yield(configuration)
|
|
275
|
+
configuration
|
|
276
|
+
end
|
|
277
|
+
|
|
253
278
|
# Load document from file
|
|
254
279
|
#
|
|
255
280
|
# @param path [String] File path
|