Skip to content

Commit

Permalink
Fix inline paragraph block level replace bug (#131)
Browse files Browse the repository at this point in the history
* Implement logic to replace the parent of an InlineParagraphBlock

This block handles logic where the start and end fields occur inside
the same paragraph. This works without issue unless the content being
injected (i.e. WordML or HTML) is not allowed inside a Paragraph.
When this occured an undefined method `next_element' for nil:NilClass
exception would be throw because a parent paragraph could not be found.

* Add integration test for InlineParagraphBlock parent replacement

* Remove unneeded ParagraphBlock inheirentance from ImageBlock

Inheiriting from the Block class is sufficent, and not as misleading.

* Implement test to exercise inline image insertion

This includes inline if and loop constructs.
  • Loading branch information
stadelmanma authored Jun 11, 2019
1 parent ac237ea commit 4f6a059
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 5 deletions.
38 changes: 35 additions & 3 deletions lib/sablon/processor/document/blocks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def self.encloses?(start_field, end_field)
end
end

class ImageBlock < ParagraphBlock
class ImageBlock < Block
def self.encloses?(start_field, end_field)
start_field.expression.start_with?('@')
end
Expand All @@ -104,8 +104,8 @@ def replace(image)
blip.attributes['embed'].value = image.local_rid if blip
drawing_size = node.at_xpath('.//wp:extent')

# if image properties are defined, the size of the placeholder image
# should be replaced with the actual values
# if image properties are defined, the size of the placeholder
# image should be replaced with the actual values
if image.width && image.height
drawing_size.attributes['cx'].value = image.width.to_s if drawing_size
drawing_size.attributes['cy'].value = image.height.to_s if drawing_size
Expand All @@ -126,6 +126,28 @@ def self.encloses?(start_field, end_field)
super && parent(start_field) == parent(end_field)
end

def process(env)
# Create a mock document structure so xpath queries will work
# correctly on block level content (i.e. searching for the first
# ancestor paragraph)
doc_node = Nokogiri::XML::Node.new('document', start_node.document)
doc_node.namespace = start_node.parent.namespace
p_node = Nokogiri::XML::Node.new('p', doc_node.document)
p_node.namespace = start_node.parent.namespace
p_node.children = Nokogiri::XML::NodeSet.new(p_node.document,
body.map(&:dup))
doc_node.children = Nokogiri::XML::NodeSet.new(p_node.document,
[p_node])
Processor::Document.process doc_node, env

if p_node.parent.nil?
replace_parent_node(doc_node.children)
[]
else
p_node.children
end
end

def remove_control_elements
body.each(&:remove)
start_field.remove
Expand All @@ -139,6 +161,16 @@ def start_node
def end_node
@end_node ||= end_field.start_node
end

private

# A block level insertion has occurred which must replace the
# parent paragraph of the start node.
def replace_parent_node(content)
node = start_node.ancestors('.//w:p').first
content.each { |n| node.add_next_sibling n }
node.remove
end
end
end
end
Expand Down
Binary file modified test/fixtures/conditionals_sample.docx
Binary file not shown.
Binary file modified test/fixtures/conditionals_template.docx
Binary file not shown.
Binary file modified test/fixtures/images_sample.docx
Binary file not shown.
Binary file modified test/fixtures/images_template.docx
Binary file not shown.
5 changes: 3 additions & 2 deletions test/sablon_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def test_generate_document_from_template
object: OpenStruct.new(true_method: true, false_method: false),
success_content: '✓',
fail_content: '✗',
content: 'Some Content'
content: 'Some Content',
block_content: Sablon.content(:html, '<p>HTML paragraph injected</p>')
}
#
template.render_to_file @output_path, context
Expand Down Expand Up @@ -155,7 +156,7 @@ def test_generate_document_from_template
darth = Sablon.content(:image, @image_fixtures.join('darth_vader.jpg'))
#
im_data = StringIO.new(IO.binread(@image_fixtures.join('clone.jpg')))
trooper = Sablon.content(:image, im_data, filename: 'clone.jpg', properties: {height: '8cm', width: '4cm'})
trooper = Sablon.content(:image, im_data, filename: 'clone.jpg', properties: {height: '1cm', width: '4cm'})
#
# with the following context setup all trooper should be reused and
# only a single file added to media. R2D2 should get duplicated in the
Expand Down

0 comments on commit 4f6a059

Please sign in to comment.