Skip to content

Commit d0170aa

Browse files
committed
basic to_html implemenation
1 parent f77425b commit d0170aa

5 files changed

Lines changed: 123 additions & 2 deletions

File tree

lib/docx/containers/paragraph.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ def to_s
4141
text_runs.map(&:text).join('')
4242
end
4343

44+
# Return paragraph as a <p></p> HTML fragment with formatting based on properties.
45+
def to_html
46+
html = ''
47+
text_runs.each do |text_run|
48+
html << text_run.to_html
49+
end
50+
styles = { 'font-size' => "#{font_size}pt" }
51+
styles['text-align'] = alignment if alignment
52+
html_tag(:p, content: html, styles: styles)
53+
end
54+
55+
4456
# Array of text runs contained within paragraph
4557
def text_runs
4658
@node.xpath('w:r|w:hyperlink/w:r').map { |r_node| Containers::TextRun.new(r_node, @document_properties) }

lib/docx/containers/text_run.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,20 @@ def parse_formatting
5656
def to_s
5757
@text
5858
end
59-
59+
60+
# Return text as a HTML fragment with formatting based on properties.
61+
def to_html
62+
html = @text
63+
html = html_tag(:em, content: html) if italicized?
64+
html = html_tag(:strong, content: html) if bolded?
65+
styles = {}
66+
styles['text-decoration'] = 'underline' if underlined?
67+
# No need to be granular with font size down to the span level if it doesn't vary.
68+
styles['font-size'] = "#{font_size}pt" if font_size != @font_size
69+
html = html_tag(:span, content: html, styles: styles) unless styles.empty?
70+
return html
71+
end
72+
6073
def italicized?
6174
@formatting[:italic]
6275
end

lib/docx/document.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ def to_s
8888
paragraphs.map(&:to_s).join("\n")
8989
end
9090

91+
# Output entire document as a String HTML fragment
92+
def to_html
93+
paragraphs.map(&:to_html).join('\n')
94+
end
95+
9196
# Save document to provided path
9297
# call-seq:
9398
# save(filepath) => void

lib/docx/elements/element.rb

100644100755
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,30 @@ def copy
5555
self.class.new(@node.dup)
5656
end
5757

58+
# A method to wrap content in an HTML tag.
59+
# Currently used in paragraph and text_run for the to_html methods
60+
#
61+
# content:: The base text content for the tag.
62+
# styles:: Hash of the inline CSS styles to be applied. e.g.
63+
# { 'font-size' => '12pt', 'text-decoration' => 'underline' }
64+
#
65+
def html_tag(name, options = {})
66+
content = options[:content]
67+
styles = options[:styles]
68+
69+
html = "<#{name.to_s}"
70+
unless styles.nil? || styles.empty?
71+
styles_array = []
72+
styles.each do |property, value|
73+
styles_array << "#{property.to_s}:#{value};"
74+
end
75+
html << " style=\"#{styles_array.join('')}\""
76+
end
77+
html << ">"
78+
html << content if content
79+
html << "</#{name.to_s}>"
80+
end
81+
5882
module ClassMethods
5983
def create_with(element)
6084
# Need to somehow get the xml document accessible here by default, but this is alright in the interim

spec/docx/document_spec.rb

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
describe Docx::Document do
66
before(:all) do
77
@fixtures_path = "spec/fixtures"
8+
@formatting_line_count = 11 # number of lines the formatting.docx file has
89
end
910

1011
describe 'reading' do
@@ -166,7 +167,7 @@
166167
end
167168

168169
it 'should have the correct text' do
169-
@doc.paragraphs.size.should eq 11
170+
@doc.paragraphs.size.should eq @formatting_line_count
170171
@doc.paragraphs[0].text.should eq 'Normal'
171172
@doc.paragraphs[1].text.should eq 'Italic'
172173
@doc.paragraphs[2].text.should eq 'Bold'
@@ -304,4 +305,70 @@
304305
end
305306
end
306307
end
308+
309+
310+
describe 'outputting html' do
311+
before do
312+
@doc = Docx::Document.open(@fixtures_path + '/formatting.docx')
313+
@formatted_line = @doc.paragraphs[5]
314+
end
315+
316+
it 'should wrap pragraphs in a p tag' do
317+
scan = @doc.paragraphs[0].to_html.scan(/(^\<p).+((?<=\>)\w+)(\<\/p>$)/).flatten
318+
scan.first.should eq '<p'
319+
scan.last.should eq '</p>'
320+
scan[1].should eq 'Normal'
321+
end
322+
323+
it 'should emphasize italicized text' do
324+
scan = @doc.paragraphs[1].to_html.scan(/(\<em\>)(\w+)(\<\/em\>)/).flatten
325+
scan.first.should eq '<em>'
326+
scan.last.should eq '</em>'
327+
scan[1].should eq 'Italic'
328+
end
329+
330+
it 'should strong bolded text' do
331+
scan = @doc.paragraphs[2].to_html.scan(/(\<strong\>)(\w+)(\<\/strong\>)/).flatten
332+
scan.first.should eq '<strong>'
333+
scan.last.should eq '</strong>'
334+
scan[1].should eq 'Bold'
335+
end
336+
337+
it 'should underline underlined text' do
338+
scan = @doc.paragraphs[3].to_html.scan(/\<span\s+([^\>]+)/).flatten
339+
scan.first.should eq 'style="text-decoration:underline;"'
340+
end
341+
342+
it 'should justify paragraphs' do
343+
regex = /^<p[^\"]+.(?<=\")([^\"]+)/
344+
@doc.paragraphs[6].to_html.scan(regex).flatten.first.split(';').include?('text-align:center').should be_true
345+
@doc.paragraphs[7].to_html.scan(regex).flatten.first.split(';').include?('text-align:left').should be_false
346+
@doc.paragraphs[8].to_html.scan(regex).flatten.first.split(';').include?('text-align:right').should be_true
347+
end
348+
349+
it "should set font size on styled paragraphs" do
350+
regex = /(\<p{1})[^\>]+style\=\"([^\"]+).+(<\/p>)/
351+
scan = @doc.paragraphs[9].to_html.scan(regex).flatten
352+
scan.first.should eq '<p'
353+
scan.last.should eq '</p>'
354+
scan[1].split(';').include?('font-size:14pt').should be_true
355+
end
356+
357+
it 'should set font size on styled text runs' do
358+
regex = /(\<span)[^\>]+style\=\"([^\"]+)[^\<]+(<\/span>)/
359+
scan = @doc.paragraphs[10].to_html.scan(regex).flatten
360+
scan.first.should eq '<span'
361+
scan.last.should eq '</span>'
362+
scan[1].split(';').include?('font-size:16pt').should be_true
363+
end
364+
365+
it 'should output an entire document as html' do
366+
@doc.to_html.scan(/(\<p)/).flatten.size.should eq @formatting_line_count
367+
end
368+
369+
it 'should output styled html' do
370+
@formatted_line.to_html.scan('<span style="text-decoration:underline;"><strong><em>all</em></strong></span>').size.should eq 1
371+
end
372+
373+
end
307374
end

0 commit comments

Comments
 (0)