From b7a92ff46b89f10cd975b9fd634cf2d536c5501b Mon Sep 17 00:00:00 2001
From: Joseph Englert
Date: Sat, 14 Nov 2015 11:59:31 +1300
Subject: [PATCH 1/4] Add formatting to text runs and paragraphs
---
lib/docx/containers/paragraph.rb | 16 +++++--
lib/docx/containers/text_run.rb | 50 ++++++++-----------
lib/docx/document.rb | 7 ++-
lib/docx/elements/bookmark.rb | 24 +++++-----
lib/docx/elements/element.rb | 2 +-
lib/docx/formatting/formatting.rb | 14 ++++++
lib/docx/formatting/paragraph_formatting.rb | 27 +++++++++++
lib/docx/formatting/text_run_formatting.rb | 53 +++++++++++++++++++++
8 files changed, 146 insertions(+), 47 deletions(-)
create mode 100644 lib/docx/formatting/formatting.rb
create mode 100644 lib/docx/formatting/paragraph_formatting.rb
create mode 100644 lib/docx/formatting/text_run_formatting.rb
diff --git a/lib/docx/containers/paragraph.rb b/lib/docx/containers/paragraph.rb
index 8652ead..9209012 100755
--- a/lib/docx/containers/paragraph.rb
+++ b/lib/docx/containers/paragraph.rb
@@ -1,5 +1,6 @@
require 'docx/containers/text_run'
require 'docx/containers/container'
+require 'docx/formatting/paragraph_formatting'
module Docx
module Elements
@@ -7,11 +8,14 @@ module Containers
class Paragraph
include Container
include Elements::Element
+ include ParagraphFormatting
def self.tag
'p'
end
+ attr_reader :properties_tag
+ alias_method :formatting, :parse_formatting
# Child elements: pPr, r, fldSimple, hlink, subDoc
# http://msdn.microsoft.com/en-us/library/office/ee364458(v=office.11).aspx
@@ -36,6 +40,12 @@ def text=(content)
end
end
+ # Set text of paragraph with formatting
+ def set_text(content, formatting={})
+ self.text = content
+ text_runs.each { |tr| tr.apply_formatting(formatting) }
+ end
+
# Return text of paragraph
def to_s
text_runs.map(&:text).join('')
@@ -79,17 +89,15 @@ def font_size
size_tag = @node.xpath('w:pPr//w:sz').first
size_tag ? size_tag.attributes['val'].value.to_i / 2 : @font_size
end
-
+
alias_method :text, :to_s
private
# Returns the alignment if any, or nil if left
def alignment
- alignment_tag = @node.xpath('.//w:jc').first
- alignment_tag ? alignment_tag.attributes['val'].value : nil
+ formatting[:alignment]
end
-
end
end
end
diff --git a/lib/docx/containers/text_run.rb b/lib/docx/containers/text_run.rb
index a4e82de..6e283a8 100755
--- a/lib/docx/containers/text_run.rb
+++ b/lib/docx/containers/text_run.rb
@@ -1,4 +1,5 @@
require 'docx/containers/container'
+require 'docx/formatting/text_run_formatting'
module Docx
module Elements
@@ -6,27 +7,23 @@ module Containers
class TextRun
include Container
include Elements::Element
+ include TextRunFormatting
- DEFAULT_FORMATTING = {
- italic: false,
- bold: false,
- underline: false
- }
-
def self.tag
'r'
end
attr_reader :text
- attr_reader :formatting
-
+ attr_reader :document_properties
+ attr_reader :properties_tag
+ alias_method :formatting, :parse_formatting
+
def initialize(node, document_properties = {})
@node = node
+ @document_properties = document_properties
@text_nodes = @node.xpath('w:t').map {|t_node| Elements::Text.new(t_node) }
@properties_tag = 'rPr'
@text = parse_text || ''
- @formatting = parse_formatting || DEFAULT_FORMATTING
- @document_properties = document_properties
@font_size = @document_properties[:font_size]
end
@@ -40,19 +37,17 @@ def text=(content)
end
end
+ # Set the text of text run with formatting
+ def set_text(content, formatting={})
+ self.text = content
+ apply_formatting(formatting)
+ end
+
# Returns text contained within text run
def parse_text
@text_nodes.map(&:content).join('')
end
- def parse_formatting
- {
- italic: !@node.xpath('.//w:i').empty?,
- bold: !@node.xpath('.//w:b').empty?,
- underline: !@node.xpath('.//w:u').empty?
- }
- end
-
def to_s
@text
end
@@ -65,26 +60,23 @@ def to_html
styles = {}
styles['text-decoration'] = 'underline' if underlined?
# No need to be granular with font size down to the span level if it doesn't vary.
- styles['font-size'] = "#{font_size}pt" if font_size != @font_size
+ styles['font-size'] = "#{font_size}pt" if font_size != @font_size
+ styles['font-family'] = %Q["#{formatting[:font]}"] if formatting[:font]
+ styles['color'] = "##{formatting[:color]}" if formatting[:color]
html = html_tag(:span, content: html, styles: styles) unless styles.empty?
return html
end
def italicized?
- @formatting[:italic]
+ formatting[:italic]
end
-
+
def bolded?
- @formatting[:bold]
- end
-
- def underlined?
- @formatting[:underline]
+ formatting[:bold]
end
- def font_size
- size_tag = @node.xpath('w:rPr//w:sz').first
- size_tag ? size_tag.attributes['val'].value.to_i / 2 : @font_size
+ def underlined?
+ formatting[:underline]
end
end
end
diff --git a/lib/docx/document.rb b/lib/docx/document.rb
index a5722d3..b1405c3 100755
--- a/lib/docx/document.rb
+++ b/lib/docx/document.rb
@@ -37,7 +37,8 @@ def initialize(path, &block)
# This stores the current global document properties, for now
def document_properties
{
- font_size: font_size
+ font_size: font_size,
+ font: font
}
end
@@ -74,6 +75,10 @@ def font_size
size_tag ? size_tag.attributes['val'].value.to_i / 2 : nil
end
+ def font
+ font_tag = @styles.at_xpath('//w:docDefaults//w:rPrDefault//w:rPr//w:rFonts')
+ font_tag ? font_tag['w:ascii'] : nil
+ end
##
# *Deprecated*
#
diff --git a/lib/docx/elements/bookmark.rb b/lib/docx/elements/bookmark.rb
index 025b15f..18b1185 100644
--- a/lib/docx/elements/bookmark.rb
+++ b/lib/docx/elements/bookmark.rb
@@ -5,7 +5,7 @@ module Elements
class Bookmark
include Element
attr_accessor :name
-
+
def self.tag
'bookmarkStart'
end
@@ -15,20 +15,20 @@ def initialize(node)
@name = @node['w:name']
end
- # Insert text before bookmarkStart node
- def insert_text_before(text)
+ # Insert text before bookmarkStart node with optional formatting
+ def insert_text_before(text, formatting={})
text_run = get_run_after
- text_run.text = "#{text}#{text_run.text}"
+ text_run.set_text("#{text}#{text_run.text}", formatting)
end
- # Insert text after bookmarkStart node
- def insert_text_after(text)
+ # Insert text after bookmarkStart node with optional formatting
+ def insert_text_after(text, formatting={})
text_run = get_run_before
- text_run.text = "#{text_run.text}#{text}"
+ text_run.set_text("#{text_run.text}#{text}", formatting)
end
- # insert multiple lines starting with paragraph containing bookmark node.
- def insert_multiple_lines(text_array)
+ # insert multiple lines starting with paragraph containing bookmark node. With optional formatting
+ def insert_multiple_lines(text_array, formatting={})
# Hold paragraphs to be inserted into, corresponding to the index of the strings in the text array
paragraphs = []
paragraph = self.parent_paragraph
@@ -45,13 +45,13 @@ def insert_multiple_lines(text_array)
# Insert text into corresponding newly created paragraphs
paragraphs.each_index do |index|
- paragraphs[index].text = text_array[index]
+ paragraphs[index].set_text(text_array[index], formatting)
end
end
# Get text run immediately prior to bookmark node
def get_run_before
- # at_xpath returns the first match found and preceding-sibling returns siblings in the
+ # at_xpath returns the first match found and preceding-sibling returns siblings in the
# order they appear in the document not the order as they appear when moving out from
# the starting node
if not (r_nodes = @node.xpath("./preceding-sibling::w:r")).empty?
@@ -76,4 +76,4 @@ def get_run_after
end
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/docx/elements/element.rb b/lib/docx/elements/element.rb
index 471918d..e361fca 100755
--- a/lib/docx/elements/element.rb
+++ b/lib/docx/elements/element.rb
@@ -93,4 +93,4 @@ def create_within(element)
end
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/docx/formatting/formatting.rb b/lib/docx/formatting/formatting.rb
new file mode 100644
index 0000000..4c32de0
--- /dev/null
+++ b/lib/docx/formatting/formatting.rb
@@ -0,0 +1,14 @@
+module Docx
+ module Formatting
+ def add_property(tag)
+ property_node.remove if properties_node.at_xpath(".//w:#{tag}") # Remove and replace property
+ properties_node.add_child("").first
+ end
+
+ def properties_node
+ properties = node.at_xpath(".//w:#{properties_tag}")
+ # Should a paragraph formatting node not exist create one
+ properties ||= node.prepend_child("").first
+ end
+ end
+end
diff --git a/lib/docx/formatting/paragraph_formatting.rb b/lib/docx/formatting/paragraph_formatting.rb
new file mode 100644
index 0000000..1d6d75d
--- /dev/null
+++ b/lib/docx/formatting/paragraph_formatting.rb
@@ -0,0 +1,27 @@
+require 'docx/formatting/formatting'
+
+module Docx
+ module ParagraphFormatting
+ include Formatting
+
+ def apply_formatting(formatting)
+ if (formatting[:alignment])
+ alignment_node = add_property('jc')
+ alignment_node['w:val'] = formatting[:alignment]
+ end
+ end
+
+ def parse_formatting
+ formatting = {}
+ alignment_node = node.at_xpath('.//w:jc')
+ formatting[:alignment] = alignment_node ? alignment_node['w:val'] : nil
+ formatting
+ end
+
+ def self.default_formatting
+ {
+ alignment: nil
+ }
+ end
+ end
+end
diff --git a/lib/docx/formatting/text_run_formatting.rb b/lib/docx/formatting/text_run_formatting.rb
new file mode 100644
index 0000000..98784b3
--- /dev/null
+++ b/lib/docx/formatting/text_run_formatting.rb
@@ -0,0 +1,53 @@
+require 'docx/formatting/formatting'
+
+module Docx
+ module TextRunFormatting
+ include Formatting
+
+ def apply_formatting(formatting)
+ if (formatting[:font])
+ font_node = add_property('rFonts')
+ font_node["w:ascii"] = formatting[:font]
+ font_node["w:hAnsi"] = formatting[:font]
+ end
+ if (formatting[:font_size])
+ font_size_node = add_property('sz')
+ font_size_node['w:val'] = formatting[:font_size] * 2 # Font size is stored in half-points
+ end
+ add_property('i') if formatting[:italic]
+ add_property('b') if formatting[:bold]
+ add_property('u') if formatting[:underline]
+ if (formatting[:color])
+ color_node = add_property('color')
+ color_node["w:val"] = formatting[:color]
+ end
+ end
+
+ def parse_formatting()
+ formatting = {}
+ formatting[:italic] = !node.xpath('.//w:i').empty?
+ formatting[:bold] = !node.xpath('.//w:b').empty?
+ formatting[:underline] = !node.xpath('.//w:u').empty?
+ font_node = node.at_xpath('.//w:rFonts')
+ formatting[:font] = font_node ? font_node['w:ascii'] : document_properties[:font]
+ formatting[:font_size] = font_size
+ color_node = node.at_xpath('.//w:color')
+ formatting[:color] = color_node ? color_node['w:val'] : nil
+ formatting
+ end
+
+ def self.default_formatting(document_properties)
+ {
+ italic: false, bold: false, underline: false,
+ font: document_properties[:font],
+ font_size: document_properties[:font_size],
+ color: nil
+ }
+ end
+
+ def font_size
+ size_tag = @node.at_xpath('.//w:sz')
+ size_tag ? size_tag.attributes['val'].value.to_i / 2 : @document_properties[:font_size]
+ end
+ end
+end
From b9f8caebda51ad2a1d33a771f8259ef7f301033a Mon Sep 17 00:00:00 2001
From: Joseph Englert
Date: Sat, 14 Nov 2015 12:00:52 +1300
Subject: [PATCH 2/4] Update tests
---
spec/docx/document_spec.rb | 168 ++++++++++++++++++++++++----------
spec/fixtures/formatting.docx | Bin 13292 -> 13478 bytes
2 files changed, 119 insertions(+), 49 deletions(-)
diff --git a/spec/docx/document_spec.rb b/spec/docx/document_spec.rb
index d038d66..b41b7db 100755
--- a/spec/docx/document_spec.rb
+++ b/spec/docx/document_spec.rb
@@ -5,7 +5,7 @@
describe Docx::Document do
before(:all) do
@fixtures_path = "spec/fixtures"
- @formatting_line_count = 12 # number of lines the formatting.docx file has
+ @formatting_line_count = 14 # number of lines the formatting.docx file has
end
describe 'reading' do
@@ -35,7 +35,7 @@
@doc.each_paragraph do |p|
p.each_text_run do |tr|
expect(tr).to be_an_instance_of(Docx::Elements::Containers::TextRun)
- expect(tr.formatting).to eq(Docx::Elements::Containers::TextRun::DEFAULT_FORMATTING)
+ expect(tr.formatting).to eq(Docx::TextRunFormatting.default_formatting(@doc.document_properties))
end
end
end
@@ -160,11 +160,58 @@
end
end
+ describe 'editing with formatting' do
+ before do
+ @doc = Docx::Document.open(@fixtures_path + '/editing.docx')
+ @formatting = { italic: false, underline: false, bold: true, font: 'Times New Roman', font_size: 20, color: 'FF0000' }
+ @default_formatting = Docx::TextRunFormatting::default_formatting(@doc.document_properties)
+ end
+
+ it 'allows insertion of text before a bookmark with formatting' do
+ expect(@doc.paragraphs.first.text).to eq('test text')
+ @doc.bookmarks['beginning_bookmark'].insert_text_before('foo', @formatting)
+ expect(@doc.paragraphs.first.text).to eq('footest text')
+ text_runs = @doc.paragraphs.first.text_runs
+ expect(text_runs[0].text).to eq('footest')
+ expect(text_runs[0].formatting).to eq @formatting
+ expect(text_runs[1].text).to eq(' text')
+ expect(text_runs[1].formatting).to eq @default_formatting
+ end
+
+ it 'allows insertion of text after a bookmark with formatting' do
+ expect(@doc.paragraphs.first.text).to eq('test text')
+ @doc.bookmarks['end_bookmark'].insert_text_after('bar', @formatting)
+ expect(@doc.paragraphs.first.text).to eq('test textbar')
+ text_runs = @doc.paragraphs.first.text_runs
+ expect(text_runs[0].text).to eq('test')
+ expect(text_runs[0].formatting).to eq @default_formatting
+ expect(text_runs[1].text).to eq(' textbar')
+ expect(text_runs[1].formatting).to eq @formatting
+ end
+
+ it 'should allow multiple lines of text to be inserted at a bookmark with formatting' do
+ expect(@doc.paragraphs.last.text).to eq('')
+ new_lines = ['replacement test', 'second paragraph test', 'and a third paragraph test']
+ @doc.bookmarks['isolated_bookmark'].insert_multiple_lines(new_lines, @formatting)
+ new_lines.each_index do |line|
+ expect(@doc.paragraphs[line + 2].text).to eq(new_lines[line])
+ text_run = @doc.paragraphs[line + 2].text_runs.first
+ expect(text_run.formatting).to eq(@formatting)
+ end
+ end
+
+ it 'should allow paragraphs to be aligned' do
+ expect(@doc.paragraphs[0].formatting).to eq(alignment: nil)
+ @doc.paragraphs[0].apply_formatting(alignment: 'center')
+ expect(@doc.paragraphs[0].formatting).to eq(alignment: 'center')
+ end
+ end
+
describe 'read formatting' do
before do
@doc = Docx::Document.open(@fixtures_path + '/formatting.docx')
@formatting = @doc.paragraphs.map { |p| p.text_runs.map(&:formatting) }
- @default_formatting = Docx::Elements::Containers::TextRun::DEFAULT_FORMATTING
+ @default_formatting = Docx::TextRunFormatting::default_formatting(@doc.document_properties)
@only_italic = @default_formatting.merge italic: true
@only_bold = @default_formatting.merge bold: true
@only_underline = @default_formatting.merge underline: true
@@ -184,57 +231,67 @@
expect(@doc.paragraphs[8].text).to eq('This paragraph is aligned right.')
expect(@doc.paragraphs[9].text).to eq('This paragraph is 14 points.')
expect(@doc.paragraphs[10].text).to eq('This paragraph has a word at 16 points.')
+ expect(@doc.paragraphs[11].text).to eq('This sentence has different formatting in different places.')
+ expect(@doc.paragraphs[12].text).to eq('This sentence uses the Times New Roman font.')
+ expect(@doc.paragraphs[13].text).to eq('This sentence is red. ')
end
it 'should contain a paragraph with multiple text runs' do
-
+ expect(@doc.paragraphs.any? { |p| p.text_runs.length <= 2 }).to eq(true)
end
it 'should detect normal formatting' do
[0, 4].each do |i|
expect(@formatting[i][0]).to eq(@default_formatting)
- expect(@doc.paragraphs[i].text_runs[0].italicized?).to eq(false)
- expect(@doc.paragraphs[i].text_runs[0].bolded?).to eq(false)
- expect(@doc.paragraphs[i].text_runs[0].underlined?).to eq(false)
+ text_run_formatting = @doc.paragraphs[i].text_runs[0].formatting
+ expect(text_run_formatting[:italic]).to eq(false)
+ expect(text_run_formatting[:bold]).to eq(false)
+ expect(text_run_formatting[:underline]).to eq(false)
end
end
it 'should detect italic formatting' do
expect(@formatting[1][0]).to eq(@only_italic)
- expect(@doc.paragraphs[1].text_runs[0].italicized?).to eq(true)
- expect(@doc.paragraphs[1].text_runs[0].bolded?).to eq(false)
- expect(@doc.paragraphs[1].text_runs[0].underlined?).to eq(false)
+ text_run_formatting = @doc.paragraphs[1].text_runs[0].formatting
+ expect(text_run_formatting[:italic]).to eq(true)
+ expect(text_run_formatting[:bold]).to eq(false)
+ expect(text_run_formatting[:underline]).to eq(false)
end
it 'should detect bold formatting' do
expect(@formatting[2][0]).to eq(@only_bold)
- expect(@doc.paragraphs[2].text_runs[0].italicized?).to eq(false)
- expect(@doc.paragraphs[2].text_runs[0].bolded?).to eq(true)
- expect(@doc.paragraphs[2].text_runs[0].underlined?).to eq(false)
+ text_run_formatting = @doc.paragraphs[2].text_runs[0].formatting
+ expect(text_run_formatting[:italic]).to eq(false)
+ expect(text_run_formatting[:bold]).to eq(true)
+ expect(text_run_formatting[:underline]).to eq(false)
end
it 'should detect underline formatting' do
expect(@formatting[3][0]).to eq(@only_underline)
- expect(@doc.paragraphs[3].text_runs[0].italicized?).to eq(false)
- expect(@doc.paragraphs[3].text_runs[0].bolded?).to eq(false)
- expect(@doc.paragraphs[3].text_runs[0].underlined?).to eq(true)
+ text_run_formatting = @doc.paragraphs[3].text_runs[0].formatting
+ expect(text_run_formatting[:italic]).to eq(false)
+ expect(text_run_formatting[:bold]).to eq(false)
+ expect(text_run_formatting[:underline]).to eq(true)
end
it 'should detect mixed formatting' do
expect(@formatting[5][0]).to eq(@default_formatting)
- expect(@doc.paragraphs[5].text_runs[0].italicized?).to eq(false)
- expect(@doc.paragraphs[5].text_runs[0].bolded?).to eq(false)
- expect(@doc.paragraphs[5].text_runs[0].underlined?).to eq(false)
-
+ text_run_formatting = @doc.paragraphs[5].text_runs[0].formatting
+ expect(text_run_formatting[:italic]).to eq(false)
+ expect(text_run_formatting[:bold]).to eq(false)
+ expect(text_run_formatting[:underline]).to eq(false)
+
expect(@formatting[5][1]).to eq(@all_formatted)
- expect(@doc.paragraphs[5].text_runs[1].italicized?).to eq(true)
- expect(@doc.paragraphs[5].text_runs[1].bolded?).to eq(true)
- expect(@doc.paragraphs[5].text_runs[1].underlined?).to eq(true)
-
+ text_run_formatting = @doc.paragraphs[5].text_runs[1].formatting
+ expect(text_run_formatting[:italic]).to eq(true)
+ expect(text_run_formatting[:bold]).to eq(true)
+ expect(text_run_formatting[:underline]).to eq(true)
+
expect(@formatting[5][2]).to eq(@default_formatting)
- expect(@doc.paragraphs[5].text_runs[2].italicized?).to eq(false)
- expect(@doc.paragraphs[5].text_runs[2].bolded?).to eq(false)
- expect(@doc.paragraphs[5].text_runs[2].underlined?).to eq(false)
+ text_run_formatting = @doc.paragraphs[5].text_runs[2].formatting
+ expect(text_run_formatting[:italic]).to eq(false)
+ expect(text_run_formatting[:bold]).to eq(false)
+ expect(text_run_formatting[:underline]).to eq(false)
end
it 'should detect centered paragraphs' do
@@ -255,27 +312,25 @@
expect(@doc.paragraphs[9].aligned_right?).to eq(false)
end
- # ECMA-376 Office Open XML spec (4th edition), 17.3.2.38, size is
- # defined in half-points, meaning 14pt text returns a value of 28.
- # http://www.ecma-international.org/publications/standards/Ecma-376.htm
- it 'should return proper font size for paragraphs' do
- expect(@doc.font_size).to eq 11
- expect(@doc.paragraphs[5].font_size).to eq 11
- paragraph = @doc.paragraphs[9]
- expect(paragraph.font_size).to eq 14
- expect(paragraph.text_runs[0].font_size).to eq 14
+ it 'should return proper font size for runs' do
+ expect(@doc.document_properties[:font_size]).to eq 11
+ text_runs = @doc.paragraphs[10].text_runs
+ expect(text_runs[0].formatting[:font_size]).to eq 11
+ expect(text_runs[1].formatting[:font_size]).to eq 16
+ expect(text_runs[2].formatting[:font_size]).to eq 11
+ expect(text_runs[3].formatting[:font_size]).to eq 11
+ expect(text_runs[4].formatting[:font_size]).to eq 11
end
- it 'should return proper font size for runs' do
- expect(@doc.font_size).to eq 11
- paragraph = @doc.paragraphs[10]
- expect(paragraph.font_size).to eq 11
- text_runs = paragraph.text_runs
- expect(text_runs[0].font_size).to eq 11
- expect(text_runs[1].font_size).to eq 16
- expect(text_runs[2].font_size).to eq 11
- expect(text_runs[3].font_size).to eq 11
- expect(text_runs[4].font_size).to eq 11
+ it 'should detect font for a textrun' do
+ expect(@doc.document_properties[:font]).to eq(nil)
+ textrun = @doc.paragraphs[12].text_runs.first
+ expect(textrun.formatting[:font]).to eq('Times New Roman')
+ end
+
+ it 'should detect the color of text in a textrun' do
+ textrun = @doc.paragraphs[13].text_runs.first
+ expect(textrun.formatting[:color]).to eq('FF0000')
end
end
@@ -327,7 +382,7 @@
expect(scan.last).to eq('
')
expect(scan[1]).to eq('Normal')
end
-
+
it 'should emphasize italicized text' do
scan = @doc.paragraphs[1].to_html.scan(@em_regex).flatten
expect(scan.first).to eq(']+style\=\"([^\"]+).+(<\/p>)/
+ regex = /(\]+style\=\"([^\"]+).+(<\/p>)/
scan = @doc.paragraphs[9].to_html.scan(regex).flatten
expect(scan.first).to eq '
'
@@ -370,6 +425,22 @@
expect(scan[1].split(';').include?('font-size:16pt')).to eq(true)
end
+ it 'should set font on styled text runs' do
+ regex = /(\]+style\=\"([^\;]+)[^\<]+(<\/span>)/
+ scan = @doc.paragraphs[12].to_html.scan(regex).flatten
+ expect(scan.first).to eq ''
+ expect(scan[1].split(';').include?('font-family:"Times New Roman"')).to eq(true)
+ end
+
+ it 'should set font color on styled text runs' do
+ regex = /(\]+style\=\"([^\"]+)[^\<]+(<\/span>)/
+ scan = @doc.paragraphs[13].to_html.scan(regex).flatten
+ expect(scan.first).to eq ''
+ expect(scan[1].split(';').include?('color:#FF0000')).to eq(true)
+ end
+
it 'should properly highlight different text in different places in a sentence' do
paragraph = @doc.paragraphs[11]
scan = paragraph.to_html.scan(@em_regex).flatten
@@ -423,4 +494,3 @@
end
end
end
-
diff --git a/spec/fixtures/formatting.docx b/spec/fixtures/formatting.docx
index 72b5b88759624985bb9df6ce0705a3777ef95924..68e1ab0e5b5e2bae54051538a5bd7a2f1b5abb30 100644
GIT binary patch
delta 3888
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
H{xSV8u1P0Z
delta 3642
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
Date: Sat, 14 Nov 2015 12:01:53 +1300
Subject: [PATCH 3/4] Update documentation
---
README.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index e779291..21454b6 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@ doc.tables.each do |table|
puts cell.text
end
end
-
+
table.columns.each do |column| # Column-based iteration
column.cells.each do |cell|
puts cell.text
@@ -84,6 +84,10 @@ doc.bookmarks['example_bookmark'].insert_text_after("Hello world.")
# Insert multiple lines of text at our bookmark
doc.bookmarks['example_bookmark_2'].insert_multiple_lines_after(['Hello', 'World', 'foo'])
+# The previous methods can also be passed a hash specifying formatting e.g.
+doc.bookmarks['example_bookmark'].insert_text_after("Hello world.",
+ { bold: true, font: 'Times New Roman', font_size: 20, color: 'FF0000' })
+
# Remove paragraphs
doc.paragraphs.each do |p|
p.remove! if p.to_s =~ /TODO/
@@ -117,6 +121,6 @@ p_child = p_element.at_xpath("//child::*") # selects first child
* Calculate element formatting based on values present in element properties as well as properties inherited from parents
* Default formatting of inserted elements to inherited values
-* Implement formattable elements.
+* Implement formattable tables.
* Implement styles.
* Easier multi-line text insertion at a single bookmark (inserting paragraph nodes after the one containing the bookmark)
From cd71d0976083a48115ff230f3124260642534ce9 Mon Sep 17 00:00:00 2001
From: Joseph Englert
Date: Sat, 14 Nov 2015 12:03:56 +1300
Subject: [PATCH 4/4] Version bump
---
lib/docx/version.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/docx/version.rb b/lib/docx/version.rb
index 663e8fe..aac1ff8 100644
--- a/lib/docx/version.rb
+++ b/lib/docx/version.rb
@@ -1,3 +1,3 @@
module Docx #:nodoc:
- VERSION = '0.2.07'
+ VERSION = '0.3.0'
end