uniword 1.0.4 → 1.0.6
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/uniword/accessibility/rules/descriptive_headings_rule.rb +7 -9
- data/lib/uniword/accessibility/rules/document_title_rule.rb +2 -2
- data/lib/uniword/accessibility/rules/heading_structure_rule.rb +4 -3
- data/lib/uniword/accessibility/rules/language_specification_rule.rb +2 -2
- data/lib/uniword/accessibility/rules/table_headers_rule.rb +1 -1
- data/lib/uniword/assembly/cross_reference_resolver.rb +6 -59
- data/lib/uniword/assembly/toc.rb +2 -2
- data/lib/uniword/assembly/variable_substitutor.rb +0 -24
- data/lib/uniword/batch/stages/compress_images_stage.rb +2 -2
- data/lib/uniword/batch/stages/normalize_styles_stage.rb +12 -12
- data/lib/uniword/batch/stages/update_metadata_stage.rb +26 -11
- data/lib/uniword/batch/stages/validate_links_stage.rb +1 -1
- data/lib/uniword/builder/bibliography_builder.rb +1 -1
- data/lib/uniword/builder/chart_builder.rb +2 -2
- data/lib/uniword/builder/has_borders.rb +1 -1
- data/lib/uniword/builder/image_builder.rb +1 -1
- data/lib/uniword/cli/main.rb +4 -4
- data/lib/uniword/diff/document_differ.rb +11 -7
- data/lib/uniword/document_factory.rb +3 -3
- data/lib/uniword/docx/document_statistics.rb +3 -3
- data/lib/uniword/docx/package_defaults.rb +2 -2
- data/lib/uniword/docx/reconciler.rb +10 -28
- data/lib/uniword/element_registry.rb +1 -1
- data/lib/uniword/endnote.rb +3 -1
- data/lib/uniword/footnote.rb +3 -1
- data/lib/uniword/format_converter.rb +7 -7
- data/lib/uniword/format_detector.rb +1 -1
- data/lib/uniword/generation/document_generator.rb +2 -2
- data/lib/uniword/infrastructure/zip_extractor.rb +1 -1
- data/lib/uniword/math_equation.rb +3 -1
- data/lib/uniword/mhtml/math_converter.rb +1 -1
- data/lib/uniword/mhtml/word_css.rb +14 -14
- data/lib/uniword/ooxml/schema/element_serializer.rb +14 -14
- data/lib/uniword/quality/document_checker.rb +2 -2
- data/lib/uniword/quality/rules/link_validation_rule.rb +4 -4
- data/lib/uniword/quality/rules/style_consistency_rule.rb +1 -1
- data/lib/uniword/quality/rules/table_header_rule.rb +1 -1
- data/lib/uniword/resource/color_transformer.rb +1 -1
- data/lib/uniword/resource/resource_resolver.rb +1 -1
- data/lib/uniword/resource/theme_processor.rb +1 -1
- data/lib/uniword/resource/theme_transition.rb +1 -1
- data/lib/uniword/review/interactive_review.rb +1 -1
- data/lib/uniword/spellcheck/spell_checker.rb +6 -6
- data/lib/uniword/styleset.rb +1 -1
- data/lib/uniword/template/helpers/conditional_helper.rb +3 -4
- data/lib/uniword/template/helpers/filter_helper.rb +1 -1
- data/lib/uniword/template/helpers/loop_helper.rb +1 -1
- data/lib/uniword/template/helpers/variable_helper.rb +1 -1
- data/lib/uniword/template/template_parser.rb +9 -7
- data/lib/uniword/template/template_renderer.rb +3 -3
- data/lib/uniword/template/variable_resolver.rb +5 -6
- data/lib/uniword/themes/theme_transformation.rb +1 -1
- data/lib/uniword/toc/toc_generator.rb +1 -1
- data/lib/uniword/transformation/mhtml_element_renderer.rb +5 -7
- data/lib/uniword/transformation/mhtml_metadata_builder.rb +17 -18
- data/lib/uniword/transformation/ooxml_to_html_converter.rb +1 -1
- data/lib/uniword/transformation/transformer.rb +6 -6
- data/lib/uniword/validation/checkers/external_link_checker.rb +1 -1
- data/lib/uniword/validation/checkers/file_reference_checker.rb +5 -5
- data/lib/uniword/validation/checkers/footnote_reference_checker.rb +12 -12
- data/lib/uniword/validation/checkers/internal_link_checker.rb +7 -9
- data/lib/uniword/validation/link_validator.rb +17 -23
- data/lib/uniword/validation/validation_report.rb +5 -3
- data/lib/uniword/validation/validation_result.rb +4 -4
- data/lib/uniword/validators/element_validator.rb +1 -7
- data/lib/uniword/version.rb +1 -1
- data/lib/uniword/visitor/text_extractor.rb +3 -3
- data/lib/uniword/warnings/warning_collector.rb +1 -1
- data/lib/uniword/watermark/manager.rb +1 -1
- data/lib/uniword/wordprocessingml/numbering_configuration.rb +1 -1
- data/lib/uniword/wordprocessingml/run.rb +4 -4
- data/lib/uniword/wordprocessingml/styles/style_definition.rb +1 -1
- metadata +2 -2
|
@@ -178,10 +178,10 @@ module Uniword
|
|
|
178
178
|
def remove_template_comments(document)
|
|
179
179
|
# Remove comments from paragraphs
|
|
180
180
|
document.paragraphs.each do |para|
|
|
181
|
-
next unless para.
|
|
181
|
+
next unless para.is_a?(Uniword::CommentsPart)
|
|
182
182
|
|
|
183
183
|
# Filter out template comments
|
|
184
|
-
next unless para.
|
|
184
|
+
next unless para.is_a?(Uniword::CommentsPart)
|
|
185
185
|
|
|
186
186
|
para.attached_comments.reject! do |c|
|
|
187
187
|
template_comment?(c)
|
|
@@ -194,7 +194,7 @@ module Uniword
|
|
|
194
194
|
# @param comment [Comment] Comment to check
|
|
195
195
|
# @return [Boolean] true if template comment
|
|
196
196
|
def template_comment?(comment)
|
|
197
|
-
return false unless comment.
|
|
197
|
+
return false unless comment.is_a?(Uniword::Comment)
|
|
198
198
|
|
|
199
199
|
text = comment.text
|
|
200
200
|
text.match?(/^\{\{.+\}\}$/)
|
|
@@ -108,9 +108,8 @@ module Uniword
|
|
|
108
108
|
# For hashes, use key access
|
|
109
109
|
if object.is_a?(Hash)
|
|
110
110
|
object[property.to_sym] || object[property]
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
object.send(property.to_sym)
|
|
111
|
+
else
|
|
112
|
+
object.public_send(property.to_sym)
|
|
114
113
|
end
|
|
115
114
|
end
|
|
116
115
|
|
|
@@ -176,7 +175,7 @@ module Uniword
|
|
|
176
175
|
|
|
177
176
|
return false if left_num.nil? || right_num.nil?
|
|
178
177
|
|
|
179
|
-
left_num.
|
|
178
|
+
left_num.public_send(operator, right_num)
|
|
180
179
|
end
|
|
181
180
|
|
|
182
181
|
# Convert value to number
|
|
@@ -185,8 +184,8 @@ module Uniword
|
|
|
185
184
|
# @return [Numeric, nil] Numeric value or nil
|
|
186
185
|
def to_number(value)
|
|
187
186
|
return value if value.is_a?(Numeric)
|
|
188
|
-
return value.to_i if value.
|
|
189
|
-
return value.to_f if value.
|
|
187
|
+
return value.to_i if value.to_s.match?(/^\d+$/)
|
|
188
|
+
return value.to_f if value.to_s.match?(/^\d+\.\d+$/)
|
|
190
189
|
|
|
191
190
|
nil
|
|
192
191
|
end
|
|
@@ -239,7 +239,7 @@ module Uniword
|
|
|
239
239
|
result = %(<span style="font-size:#{size_pt}pt">#{result}</span>)
|
|
240
240
|
end
|
|
241
241
|
|
|
242
|
-
if props.font.
|
|
242
|
+
if props.font.is_a?(Uniword::Properties::RunFonts) && props.font.ascii
|
|
243
243
|
result = %(<span style="font-family:'#{props.font.ascii}'">#{result}</span>)
|
|
244
244
|
elsif props.font.is_a?(String) && !props.font.empty?
|
|
245
245
|
result = %(<span style="font-family:'#{props.font}'">#{result}</span>)
|
|
@@ -582,7 +582,7 @@ module Uniword
|
|
|
582
582
|
|
|
583
583
|
attrs = []
|
|
584
584
|
|
|
585
|
-
attrs << %(w:id="#{props.id.value}") if props.id
|
|
585
|
+
attrs << %(w:id="#{props.id.value}") if props.id&.value
|
|
586
586
|
|
|
587
587
|
attrs << 'w:showingPlcHdr="t"' if props.showing_placeholder_header
|
|
588
588
|
|
|
@@ -590,14 +590,12 @@ module Uniword
|
|
|
590
590
|
|
|
591
591
|
if props.placeholder&.doc_part
|
|
592
592
|
doc_part = props.placeholder.doc_part
|
|
593
|
-
attrs << %(w:docPart="#{doc_part.value}") if doc_part
|
|
593
|
+
attrs << %(w:docPart="#{doc_part.value}") if doc_part&.value
|
|
594
594
|
end
|
|
595
595
|
|
|
596
|
-
attrs << %(w:
|
|
596
|
+
attrs << %(w:tag="#{escape_xml(props.tag.value)}") if props.tag&.value
|
|
597
597
|
|
|
598
|
-
attrs << %(w:
|
|
599
|
-
|
|
600
|
-
attrs << %(w:alias="#{escape_xml(props.alias_name.value)}") if props.alias_name.respond_to?(:value) && props.alias_name.value
|
|
598
|
+
attrs << %(w:alias="#{escape_xml(props.alias_name.value)}") if props.alias_name&.value
|
|
601
599
|
|
|
602
600
|
attrs.empty? ? "" : " #{attrs.join(' ')}"
|
|
603
601
|
end
|
|
@@ -49,14 +49,11 @@ module Uniword
|
|
|
49
49
|
props = Uniword::Mhtml::Metadata::DocumentProperties.new
|
|
50
50
|
cp = core_properties
|
|
51
51
|
|
|
52
|
-
if cp
|
|
53
|
-
props.author = cp.creator.to_s if cp.
|
|
54
|
-
props.created = cp.created.value.to_s if cp.
|
|
55
|
-
props.last_author = cp.last_modified_by.to_s if cp.
|
|
56
|
-
props.last_saved = cp.modified.value.to_s if cp.
|
|
57
|
-
props.pages = cp.pages.to_s if cp.respond_to?(:pages) && cp.pages
|
|
58
|
-
props.words = cp.words.to_s if cp.respond_to?(:words) && cp.words
|
|
59
|
-
props.characters = cp.characters.to_s if cp.respond_to?(:characters) && cp.characters
|
|
52
|
+
if cp.is_a?(Uniword::Ooxml::CoreProperties)
|
|
53
|
+
props.author = cp.creator.to_s if cp.creator
|
|
54
|
+
props.created = cp.created.value.to_s if cp.created
|
|
55
|
+
props.last_author = cp.last_modified_by.to_s if cp.last_modified_by
|
|
56
|
+
props.last_saved = cp.modified.value.to_s if cp.modified
|
|
60
57
|
props.application = "Microsoft Word"
|
|
61
58
|
end
|
|
62
59
|
|
|
@@ -109,11 +106,11 @@ module Uniword
|
|
|
109
106
|
props = core_properties
|
|
110
107
|
return "" unless props
|
|
111
108
|
|
|
112
|
-
author = props.
|
|
113
|
-
last_author = props.
|
|
114
|
-
revision = props.
|
|
115
|
-
created = props.
|
|
116
|
-
last_saved = props.
|
|
109
|
+
author = props.is_a?(Uniword::Ooxml::CoreProperties) ? props.creator : nil
|
|
110
|
+
last_author = props.is_a?(Uniword::Ooxml::CoreProperties) ? props.last_modified_by : nil
|
|
111
|
+
revision = props.is_a?(Uniword::Ooxml::CoreProperties) ? props.revision : nil
|
|
112
|
+
created = props.is_a?(Uniword::Ooxml::CoreProperties) && props.created ? props.created.value : nil
|
|
113
|
+
last_saved = props.is_a?(Uniword::Ooxml::CoreProperties) && props.modified ? props.modified.value : nil
|
|
117
114
|
|
|
118
115
|
stats = calculate_document_stats
|
|
119
116
|
|
|
@@ -212,11 +209,13 @@ module Uniword
|
|
|
212
209
|
|
|
213
210
|
# Get a custom document property by name
|
|
214
211
|
def custom_property(name)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
nil
|
|
212
|
+
cp = @document.custom_properties
|
|
213
|
+
return nil unless cp
|
|
214
|
+
|
|
215
|
+
prop = cp.properties.find { |p| p.name == name }
|
|
216
|
+
return nil unless prop
|
|
217
|
+
|
|
218
|
+
prop.lpwstr || prop.lpstr || prop.bstr
|
|
220
219
|
end
|
|
221
220
|
|
|
222
221
|
# Escape XML special characters
|
|
@@ -110,7 +110,7 @@ module Uniword
|
|
|
110
110
|
def self.wrap_html(body_html, document)
|
|
111
111
|
title = document.title ? escape_html(document.title) : "Document"
|
|
112
112
|
core_props = document.core_properties
|
|
113
|
-
author = core_props.
|
|
113
|
+
author = core_props.is_a?(Uniword::Ooxml::CoreProperties) ? core_props.creator : nil
|
|
114
114
|
|
|
115
115
|
meta_tags = []
|
|
116
116
|
meta_tags << "<meta name=\"author\" content=\"#{escape_html(author)}\">" if author
|
|
@@ -166,7 +166,7 @@ module Uniword
|
|
|
166
166
|
ooxml_doc = Wordprocessingml::DocumentRoot.new
|
|
167
167
|
|
|
168
168
|
# Get HTML content - use raw_html which is the correct method on Mhtml::Document
|
|
169
|
-
html_content = source.raw_html if source.
|
|
169
|
+
html_content = source.raw_html if source.is_a?(Uniword::Mhtml::Document) && source.raw_html
|
|
170
170
|
return ooxml_doc if html_content.nil? || html_content.empty?
|
|
171
171
|
|
|
172
172
|
# Convert HTML to OOXML paragraphs
|
|
@@ -185,15 +185,15 @@ module Uniword
|
|
|
185
185
|
doc_props = source.document_properties
|
|
186
186
|
if doc_props
|
|
187
187
|
ooxml_doc.core_properties ||= Uniword::Ooxml::CoreProperties.new
|
|
188
|
-
ooxml_doc.core_properties.creator = doc_props.author if doc_props.
|
|
189
|
-
ooxml_doc.core_properties.creator = doc_props.author if doc_props.
|
|
190
|
-
if doc_props.
|
|
188
|
+
ooxml_doc.core_properties.creator = doc_props.author if doc_props.author
|
|
189
|
+
ooxml_doc.core_properties.creator = doc_props.author if doc_props.author
|
|
190
|
+
if doc_props.created
|
|
191
191
|
ooxml_doc.core_properties.created = Uniword::Ooxml::Types::DctermsCreatedType.new(
|
|
192
192
|
value: doc_props.created, type: "dcterms:W3CDTF",
|
|
193
193
|
)
|
|
194
194
|
end
|
|
195
|
-
ooxml_doc.core_properties.last_modified_by = doc_props.last_author if doc_props.
|
|
196
|
-
if doc_props.
|
|
195
|
+
ooxml_doc.core_properties.last_modified_by = doc_props.last_author if doc_props.last_author
|
|
196
|
+
if doc_props.last_saved
|
|
197
197
|
ooxml_doc.core_properties.modified = Uniword::Ooxml::Types::DctermsModifiedType.new(
|
|
198
198
|
value: doc_props.last_saved, type: "dcterms:W3CDTF",
|
|
199
199
|
)
|
|
@@ -55,7 +55,7 @@ module Uniword
|
|
|
55
55
|
# checker.can_check?(hyperlink) # => true
|
|
56
56
|
def can_check?(link)
|
|
57
57
|
return false unless enabled?
|
|
58
|
-
return false unless link.
|
|
58
|
+
return false unless link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:url)
|
|
59
59
|
|
|
60
60
|
url = link.url
|
|
61
61
|
url&.to_s&.match?(%r{^https?://})
|
|
@@ -47,10 +47,10 @@ module Uniword
|
|
|
47
47
|
# Check if link is a file path (string or has path attribute)
|
|
48
48
|
if link.is_a?(String)
|
|
49
49
|
looks_like_file_path?(link)
|
|
50
|
-
elsif link.
|
|
50
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:url)
|
|
51
51
|
url = link.url
|
|
52
52
|
url && looks_like_file_path?(url)
|
|
53
|
-
elsif link.
|
|
53
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:path)
|
|
54
54
|
true
|
|
55
55
|
else
|
|
56
56
|
false
|
|
@@ -135,9 +135,9 @@ module Uniword
|
|
|
135
135
|
def extract_file_path(link)
|
|
136
136
|
if link.is_a?(String)
|
|
137
137
|
link
|
|
138
|
-
elsif link.
|
|
138
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:path)
|
|
139
139
|
link.path
|
|
140
|
-
elsif link.
|
|
140
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:url)
|
|
141
141
|
url = link.url
|
|
142
142
|
# Extract file path from file:// URLs
|
|
143
143
|
if url&.start_with?("file://")
|
|
@@ -170,7 +170,7 @@ module Uniword
|
|
|
170
170
|
# @return [String] Base path
|
|
171
171
|
def determine_base_path(document)
|
|
172
172
|
# Try to get document's directory
|
|
173
|
-
if document.
|
|
173
|
+
if document.is_a?(Lutaml::Model::Serializable) && document.class.attributes.key?(:file_path)
|
|
174
174
|
File.dirname(document.file_path)
|
|
175
175
|
else
|
|
176
176
|
# Use configured base path
|
|
@@ -39,10 +39,10 @@ module Uniword
|
|
|
39
39
|
return false unless enabled?
|
|
40
40
|
|
|
41
41
|
# Check if link is a footnote reference
|
|
42
|
-
link.
|
|
43
|
-
link.
|
|
44
|
-
(link.
|
|
45
|
-
|
|
42
|
+
(link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:footnote_id)) ||
|
|
43
|
+
(link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:endnote_id)) ||
|
|
44
|
+
(link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:type) && %i[footnote
|
|
45
|
+
endnote].include?(link.type))
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Validate the footnote reference.
|
|
@@ -117,11 +117,11 @@ module Uniword
|
|
|
117
117
|
# @param link [Object] The link object
|
|
118
118
|
# @return [String, Integer, nil] Note ID
|
|
119
119
|
def extract_note_id(link)
|
|
120
|
-
if link.
|
|
120
|
+
if link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:footnote_id)
|
|
121
121
|
link.footnote_id
|
|
122
|
-
elsif link.
|
|
122
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:endnote_id)
|
|
123
123
|
link.endnote_id
|
|
124
|
-
elsif link.
|
|
124
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:id)
|
|
125
125
|
link.id
|
|
126
126
|
end
|
|
127
127
|
end
|
|
@@ -131,9 +131,9 @@ module Uniword
|
|
|
131
131
|
# @param link [Object] The link object
|
|
132
132
|
# @return [Symbol] Note type (:footnote or :endnote)
|
|
133
133
|
def determine_note_type(link)
|
|
134
|
-
if link.
|
|
134
|
+
if link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:type)
|
|
135
135
|
link.type
|
|
136
|
-
elsif link.
|
|
136
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:endnote_id)
|
|
137
137
|
:endnote
|
|
138
138
|
else
|
|
139
139
|
:footnote
|
|
@@ -151,8 +151,8 @@ module Uniword
|
|
|
151
151
|
# Try to get notes from document
|
|
152
152
|
collection_name = note_type == :endnote ? :endnotes : :footnotes
|
|
153
153
|
|
|
154
|
-
if document.
|
|
155
|
-
collection = document.
|
|
154
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
155
|
+
collection = document.public_send(collection_name)
|
|
156
156
|
|
|
157
157
|
case collection
|
|
158
158
|
when Hash
|
|
@@ -160,7 +160,7 @@ module Uniword
|
|
|
160
160
|
when Array
|
|
161
161
|
# Convert array to hash indexed by ID
|
|
162
162
|
collection.each do |note|
|
|
163
|
-
id = note.
|
|
163
|
+
id = note.is_a?(Lutaml::Model::Serializable) && note.class.attributes.key?(:id) ? note.id : note.to_s
|
|
164
164
|
notes[id] = note
|
|
165
165
|
end
|
|
166
166
|
end
|
|
@@ -40,12 +40,10 @@ module Uniword
|
|
|
40
40
|
# checker.can_check?(hyperlink) # => true
|
|
41
41
|
def can_check?(link)
|
|
42
42
|
return false unless enabled?
|
|
43
|
-
return false unless link.
|
|
43
|
+
return false unless link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:anchor)
|
|
44
44
|
|
|
45
45
|
# Internal links have anchor but no URL
|
|
46
|
-
link.anchor && !link.
|
|
47
|
-
has_url ? !link.url : true
|
|
48
|
-
end
|
|
46
|
+
link.anchor && !(link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:url) && link.url)
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
# Validate the internal link.
|
|
@@ -108,13 +106,13 @@ module Uniword
|
|
|
108
106
|
bookmarks = []
|
|
109
107
|
|
|
110
108
|
# Extract from document.bookmarks if available
|
|
111
|
-
if document.
|
|
109
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
112
110
|
case document.bookmarks
|
|
113
111
|
when Hash
|
|
114
112
|
bookmarks.concat(document.bookmarks.keys.map(&:to_s))
|
|
115
113
|
when Array
|
|
116
114
|
bookmarks.concat(document.bookmarks.map do |b|
|
|
117
|
-
b.
|
|
115
|
+
b.is_a?(Lutaml::Model::Serializable) && b.class.attributes.key?(:name) ? b.name : b.to_s
|
|
118
116
|
end)
|
|
119
117
|
end
|
|
120
118
|
end
|
|
@@ -132,13 +130,13 @@ module Uniword
|
|
|
132
130
|
# @param document [Object] The document
|
|
133
131
|
# @return [Array<String>] Heading bookmark names
|
|
134
132
|
def extract_heading_bookmarks(document)
|
|
135
|
-
return [] unless document.
|
|
133
|
+
return [] unless document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
136
134
|
|
|
137
135
|
document.paragraphs.select do |p|
|
|
138
|
-
p.
|
|
136
|
+
p.is_a?(Lutaml::Model::Serializable) && p.class.attributes.key?(:style) && p.style&.match?(/^Heading/)
|
|
139
137
|
end.filter_map do |p|
|
|
140
138
|
# Generate bookmark from heading text
|
|
141
|
-
p.
|
|
139
|
+
p.is_a?(Lutaml::Model::Serializable) && p.class.attributes.key?(:text) ? heading_to_bookmark(p.text) : nil
|
|
142
140
|
end
|
|
143
141
|
end
|
|
144
142
|
|
|
@@ -193,27 +193,27 @@ module Uniword
|
|
|
193
193
|
links = []
|
|
194
194
|
|
|
195
195
|
# Extract from paragraphs
|
|
196
|
-
if document.
|
|
196
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
197
197
|
document.paragraphs.each do |para|
|
|
198
198
|
links.concat(extract_links_from_paragraph(para))
|
|
199
199
|
end
|
|
200
200
|
end
|
|
201
201
|
|
|
202
202
|
# Extract from tables
|
|
203
|
-
if document.
|
|
203
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
204
204
|
document.tables.each do |table|
|
|
205
205
|
links.concat(extract_links_from_table(table))
|
|
206
206
|
end
|
|
207
207
|
end
|
|
208
208
|
|
|
209
209
|
# Extract from headers/footers
|
|
210
|
-
if document.
|
|
210
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot) && document.headers
|
|
211
211
|
document.headers.each do |header|
|
|
212
212
|
links.concat(extract_links_from_section(header))
|
|
213
213
|
end
|
|
214
214
|
end
|
|
215
215
|
|
|
216
|
-
if document.
|
|
216
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot) && document.footers
|
|
217
217
|
document.footers.each do |footer|
|
|
218
218
|
links.concat(extract_links_from_section(footer))
|
|
219
219
|
end
|
|
@@ -230,14 +230,12 @@ module Uniword
|
|
|
230
230
|
links = []
|
|
231
231
|
|
|
232
232
|
# Check paragraph runs for hyperlinks
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
links << run if run.is_a?(Wordprocessingml::Hyperlink)
|
|
236
|
-
end
|
|
233
|
+
para.runs.each do |run|
|
|
234
|
+
links << run if run.is_a?(Wordprocessingml::Hyperlink)
|
|
237
235
|
end
|
|
238
236
|
|
|
239
237
|
# Check for hyperlinks collection
|
|
240
|
-
links.concat(para.hyperlinks) if para.
|
|
238
|
+
links.concat(para.hyperlinks) if para.hyperlinks
|
|
241
239
|
|
|
242
240
|
links
|
|
243
241
|
end
|
|
@@ -249,16 +247,14 @@ module Uniword
|
|
|
249
247
|
def extract_links_from_table(table)
|
|
250
248
|
links = []
|
|
251
249
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
next unless row.respond_to?(:cells)
|
|
250
|
+
table.rows&.each do |row|
|
|
251
|
+
next unless row.is_a?(Uniword::Wordprocessingml::TableRow)
|
|
255
252
|
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
row.cells.each do |cell|
|
|
254
|
+
next unless cell.is_a?(Uniword::Wordprocessingml::TableCell)
|
|
258
255
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
end
|
|
256
|
+
cell.paragraphs.each do |para|
|
|
257
|
+
links.concat(extract_links_from_paragraph(para))
|
|
262
258
|
end
|
|
263
259
|
end
|
|
264
260
|
end
|
|
@@ -273,10 +269,8 @@ module Uniword
|
|
|
273
269
|
def extract_links_from_section(section)
|
|
274
270
|
links = []
|
|
275
271
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
links.concat(extract_links_from_paragraph(para))
|
|
279
|
-
end
|
|
272
|
+
section.paragraphs&.each do |para|
|
|
273
|
+
links.concat(extract_links_from_paragraph(para))
|
|
280
274
|
end
|
|
281
275
|
|
|
282
276
|
links
|
|
@@ -290,7 +284,7 @@ module Uniword
|
|
|
290
284
|
refs = []
|
|
291
285
|
|
|
292
286
|
# Check if document has footnotes
|
|
293
|
-
if document.
|
|
287
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
294
288
|
footnotes = document.footnotes
|
|
295
289
|
case footnotes
|
|
296
290
|
when Hash
|
|
@@ -301,7 +295,7 @@ module Uniword
|
|
|
301
295
|
end
|
|
302
296
|
|
|
303
297
|
# Check if document has endnotes
|
|
304
|
-
if document.
|
|
298
|
+
if document.is_a?(Uniword::Wordprocessingml::DocumentRoot)
|
|
305
299
|
endnotes = document.endnotes
|
|
306
300
|
case endnotes
|
|
307
301
|
when Hash
|
|
@@ -330,11 +330,13 @@ module Uniword
|
|
|
330
330
|
# @param link [Object] The link object
|
|
331
331
|
# @return [Symbol] Link type
|
|
332
332
|
def classify_link_type(link)
|
|
333
|
-
if link.
|
|
333
|
+
if link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:url) && link.url
|
|
334
334
|
:external
|
|
335
|
-
elsif link.
|
|
335
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:anchor) && link.anchor
|
|
336
336
|
:internal
|
|
337
|
-
elsif link.
|
|
337
|
+
elsif link.is_a?(Uniword::Wordprocessingml::Hyperlink) && link.id
|
|
338
|
+
:external
|
|
339
|
+
elsif link.is_a?(Lutaml::Model::Serializable) && link.class.attributes.key?(:id)
|
|
338
340
|
:footnote
|
|
339
341
|
elsif link.is_a?(String) && File.exist?(link)
|
|
340
342
|
:file
|
|
@@ -152,13 +152,13 @@ module Uniword
|
|
|
152
152
|
# @example
|
|
153
153
|
# result.link_identifier # => "https://example.com"
|
|
154
154
|
def link_identifier
|
|
155
|
-
if @link.
|
|
155
|
+
if @link.is_a?(Lutaml::Model::Serializable) && @link.class.attributes.key?(:url) && @link.url
|
|
156
156
|
@link.url
|
|
157
|
-
elsif @link.
|
|
157
|
+
elsif @link.is_a?(Lutaml::Model::Serializable) && @link.class.attributes.key?(:anchor) && @link.anchor
|
|
158
158
|
"##{@link.anchor}"
|
|
159
|
-
elsif @link.
|
|
159
|
+
elsif @link.is_a?(Lutaml::Model::Serializable) && @link.class.attributes.key?(:id)
|
|
160
160
|
@link.id.to_s
|
|
161
|
-
elsif @link.
|
|
161
|
+
elsif @link.is_a?(Lutaml::Model::Serializable) && @link.class.attributes.key?(:name)
|
|
162
162
|
@link.name
|
|
163
163
|
else
|
|
164
164
|
@link.to_s
|
|
@@ -74,13 +74,7 @@ module Uniword
|
|
|
74
74
|
a.to_s.include?("Serializable")
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
# v1.x: Elements have a valid? method
|
|
79
|
-
if element.respond_to?(:valid?)
|
|
80
|
-
element.valid?
|
|
81
|
-
else
|
|
82
|
-
true
|
|
83
|
-
end
|
|
77
|
+
true
|
|
84
78
|
end
|
|
85
79
|
|
|
86
80
|
# Get validation errors for an element
|
data/lib/uniword/version.rb
CHANGED
|
@@ -37,14 +37,14 @@ module Uniword
|
|
|
37
37
|
# @return [void]
|
|
38
38
|
def visit_document(document)
|
|
39
39
|
# Visit both paragraphs and tables from body
|
|
40
|
-
if document.body.
|
|
40
|
+
if document.body.is_a?(Uniword::Wordprocessingml::Body)
|
|
41
41
|
document.body.elements.each do |element|
|
|
42
|
-
element.accept(self) if element.
|
|
42
|
+
element.accept(self) if element.is_a?(Lutaml::Model::Serializable)
|
|
43
43
|
end
|
|
44
44
|
else
|
|
45
45
|
# Legacy support: visit paragraphs only
|
|
46
46
|
document.elements.each do |element|
|
|
47
|
-
element.accept(self) if element.
|
|
47
|
+
element.accept(self) if element.is_a?(Lutaml::Model::Serializable)
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -218,7 +218,7 @@ module Uniword
|
|
|
218
218
|
|
|
219
219
|
# Use Uniword logger if available
|
|
220
220
|
if defined?(Uniword::Logger)
|
|
221
|
-
Uniword::Logger.
|
|
221
|
+
Uniword::Logger.public_send(level, message)
|
|
222
222
|
elsif %i[warn error].include?(level)
|
|
223
223
|
# Fall back to standard output
|
|
224
224
|
puts message
|
|
@@ -106,7 +106,7 @@ module Uniword
|
|
|
106
106
|
|
|
107
107
|
def watermark?(paragraph)
|
|
108
108
|
return false unless paragraph.properties
|
|
109
|
-
return false unless paragraph.properties.
|
|
109
|
+
return false unless paragraph.properties.is_a?(Uniword::Wordprocessingml::ParagraphProperties)
|
|
110
110
|
|
|
111
111
|
paragraph.properties.style.to_s == "UniwordWatermark"
|
|
112
112
|
end
|
|
@@ -127,7 +127,7 @@ module Uniword
|
|
|
127
127
|
|
|
128
128
|
# Get a definition by abstract_num_id (accepts Integer or AbstractNumId)
|
|
129
129
|
def get_definition(abstract_num_id)
|
|
130
|
-
target_id = abstract_num_id.
|
|
130
|
+
target_id = abstract_num_id.is_a?(AbstractNumId) ? abstract_num_id.val : abstract_num_id
|
|
131
131
|
definitions.find { |d| d.abstract_num_id == target_id }
|
|
132
132
|
end
|
|
133
133
|
|
|
@@ -180,8 +180,8 @@ module Uniword
|
|
|
180
180
|
|
|
181
181
|
# Get all attribute names from RunProperties class
|
|
182
182
|
RunProperties.attributes.each_key do |attr_name|
|
|
183
|
-
override_val = override.
|
|
184
|
-
base_val = base.
|
|
183
|
+
override_val = override.public_send(attr_name)
|
|
184
|
+
base_val = base.public_send(attr_name)
|
|
185
185
|
|
|
186
186
|
# Use override if it's non-nil AND not using default value
|
|
187
187
|
# For boolean properties like Bold, check if it was explicitly set
|
|
@@ -197,9 +197,9 @@ module Uniword
|
|
|
197
197
|
|
|
198
198
|
begin
|
|
199
199
|
if use_override
|
|
200
|
-
merged.
|
|
200
|
+
merged.public_send(:"#{attr_name}=", override_val)
|
|
201
201
|
elsif base_val
|
|
202
|
-
merged.
|
|
202
|
+
merged.public_send(:"#{attr_name}=", base_val)
|
|
203
203
|
end
|
|
204
204
|
rescue StandardError => e
|
|
205
205
|
Uniword.logger&.debug do
|
|
@@ -25,7 +25,7 @@ module Uniword
|
|
|
25
25
|
def resolve_inheritance(library = nil)
|
|
26
26
|
return properties unless @base_style && library
|
|
27
27
|
|
|
28
|
-
base_def = library.
|
|
28
|
+
base_def = library.public_send(style_type, @base_style)
|
|
29
29
|
base_props = base_def.resolve_inheritance(library)
|
|
30
30
|
|
|
31
31
|
merge_properties(base_props, properties)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: uniword
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: logger
|