sablon 0.0.21 → 0.0.22
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/.travis.yml +4 -3
- data/Gemfile.lock +9 -9
- data/README.md +120 -11
- data/lib/sablon.rb +7 -1
- data/lib/sablon/configuration/configuration.rb +165 -0
- data/lib/sablon/configuration/html_tag.rb +99 -0
- data/lib/sablon/content.rb +12 -9
- data/lib/sablon/context.rb +27 -20
- data/lib/sablon/environment.rb +31 -0
- data/lib/sablon/html/ast.rb +290 -75
- data/lib/sablon/html/ast_builder.rb +90 -0
- data/lib/sablon/html/converter.rb +3 -123
- data/lib/sablon/numbering.rb +0 -5
- data/lib/sablon/operations.rb +11 -11
- data/lib/sablon/parser/mail_merge.rb +7 -6
- data/lib/sablon/processor/document.rb +9 -9
- data/lib/sablon/processor/numbering.rb +4 -4
- data/lib/sablon/template.rb +5 -4
- data/lib/sablon/version.rb +1 -1
- data/sablon.gemspec +3 -3
- data/test/configuration_test.rb +122 -0
- data/test/content_test.rb +7 -6
- data/test/context_test.rb +11 -11
- data/test/environment_test.rb +27 -0
- data/test/expression_test.rb +2 -2
- data/test/fixtures/html/html_test_content.html +174 -0
- data/test/fixtures/html_sample.docx +0 -0
- data/test/fixtures/xml/comment_block_and_comment_as_key.xml +31 -0
- data/test/html/ast_builder_test.rb +65 -0
- data/test/html/ast_test.rb +117 -0
- data/test/html/converter_test.rb +386 -87
- data/test/html/node_properties_test.rb +113 -0
- data/test/html_test.rb +10 -10
- data/test/mail_merge_parser_test.rb +3 -2
- data/test/processor/document_test.rb +20 -2
- data/test/section_properties_test.rb +1 -1
- data/test/support/html_snippets.rb +9 -0
- data/test/test_helper.rb +0 -1
- metadata +27 -7
data/lib/sablon/version.rb
CHANGED
data/sablon.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Sablon::VERSION
|
9
9
|
spec.authors = ["Yves Senn"]
|
10
10
|
spec.email = ["yves.senn@gmail.com"]
|
11
|
-
spec.summary = %q{docx
|
11
|
+
spec.summary = %q{docx template processor}
|
12
12
|
spec.description = %q{Sablon is a document template processor. At this time it works only with docx and MailMerge fields.}
|
13
13
|
spec.homepage = "http://github.com/senny/sablon"
|
14
14
|
spec.license = "MIT"
|
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
22
|
spec.add_runtime_dependency 'nokogiri', ">= 1.6.0"
|
23
|
-
spec.add_runtime_dependency 'rubyzip', ">= 1.1"
|
23
|
+
spec.add_runtime_dependency 'rubyzip', ">= 1.1.1"
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", ">= 1.6"
|
26
|
-
spec.add_development_dependency "rake", "~>
|
26
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
27
27
|
spec.add_development_dependency "minitest", "~> 5.4"
|
28
28
|
spec.add_development_dependency "xml-simple"
|
29
29
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "test_helper"
|
3
|
+
|
4
|
+
class ConfigurationTest < Sablon::TestCase
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@config = Sablon::Configuration.send(:new)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_register_tag
|
11
|
+
options = {
|
12
|
+
ast_class: :paragraph,
|
13
|
+
attributes: { dummy: 'value' },
|
14
|
+
properties: { pstyle: 'ListBullet' },
|
15
|
+
allowed_children: %i[_inline ol ul li]
|
16
|
+
}
|
17
|
+
# test initialization without type
|
18
|
+
tag = @config.register_html_tag(:test_tag, **options)
|
19
|
+
assert_equal @config.permitted_html_tags[:test_tag], tag
|
20
|
+
assert_equal tag.name, :test_tag
|
21
|
+
assert_equal tag.type, :inline
|
22
|
+
assert_equal tag.ast_class, Sablon::HTMLConverter::Paragraph
|
23
|
+
assert_equal tag.attributes, dummy: 'value'
|
24
|
+
assert_equal tag.properties, pstyle: 'ListBullet'
|
25
|
+
assert_equal tag.allowed_children, %i[_inline ol ul li]
|
26
|
+
|
27
|
+
# test initialization with type
|
28
|
+
tag = @config.register_html_tag('test_tag2', :block, **options)
|
29
|
+
assert_equal @config.permitted_html_tags[:test_tag2], tag
|
30
|
+
assert_equal tag.name, :test_tag2
|
31
|
+
assert_equal tag.type, :block
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_remove_tag
|
35
|
+
tag = @config.register_html_tag(:test)
|
36
|
+
assert_equal @config.remove_html_tag(:test), tag
|
37
|
+
assert_nil @config.permitted_html_tags[:test]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_register_style_converter_on_existing_ast_class
|
41
|
+
converter = ->(v) { return "test-attr-#{v}" }
|
42
|
+
@config.register_style_converter(:run, 'my-test-attr', converter)
|
43
|
+
#
|
44
|
+
assert @config.defined_style_conversions[:run]['my-test-attr'], 'converter should be stored in hash'
|
45
|
+
assert_equal 'test-attr-123', @config.defined_style_conversions[:run]['my-test-attr'].call(123)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_register_style_converter_on_newast_class
|
49
|
+
converter = ->(v) { return "test-attr-#{v}" }
|
50
|
+
@config.register_style_converter(:unset_ast_class, 'my-test-attr', converter)
|
51
|
+
#
|
52
|
+
assert @config.defined_style_conversions[:unset_ast_class]['my-test-attr'], 'converter should be stored in hash'
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_remove_style_converter
|
56
|
+
converter = ->(v) { return "test-attr-#{v}" }
|
57
|
+
converter = @config.register_style_converter(:run, 'my-test-attr', converter)
|
58
|
+
#
|
59
|
+
assert_equal converter, @config.remove_style_converter(:run, 'my-test-attr')
|
60
|
+
assert_nil @config.defined_style_conversions[:run]['my-test-attr']
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ConfigurationHTMLTagTest < Sablon::TestCase
|
65
|
+
# test basic instantiation of an HTMLTag
|
66
|
+
def test_html_tag_defaults
|
67
|
+
tag = Sablon::Configuration::HTMLTag.new(:a, :inline)
|
68
|
+
assert_equal tag.name, :a
|
69
|
+
assert_equal tag.type, :inline
|
70
|
+
assert_nil tag.ast_class
|
71
|
+
assert_equal tag.attributes, {}
|
72
|
+
assert_equal tag.properties, {}
|
73
|
+
assert_equal tag.allowed_children, %i[_inline ol ul]
|
74
|
+
end
|
75
|
+
|
76
|
+
# Exercising more of the logic used to conform args into valid
|
77
|
+
def test_html_tag_full_init
|
78
|
+
args = ['a', 'inline', ast_class: Sablon::HTMLConverter::Run]
|
79
|
+
tag = Sablon::Configuration::HTMLTag.new(*args)
|
80
|
+
assert_equal tag.name, :a
|
81
|
+
assert_equal tag.type, :inline
|
82
|
+
assert_equal tag.ast_class, Sablon::HTMLConverter::Run
|
83
|
+
#
|
84
|
+
options = {
|
85
|
+
ast_class: :run,
|
86
|
+
attributes: { dummy: 'value1' },
|
87
|
+
properties: { dummy2: 'value2' },
|
88
|
+
allowed_children: 'text'
|
89
|
+
}
|
90
|
+
tag = Sablon::Configuration::HTMLTag.new('a', 'inline', **options)
|
91
|
+
#
|
92
|
+
assert_equal tag.name, :a
|
93
|
+
assert_equal tag.type, :inline
|
94
|
+
assert_equal tag.ast_class, Sablon::HTMLConverter::Run
|
95
|
+
assert_equal tag.attributes, dummy: 'value1'
|
96
|
+
assert_equal tag.properties, dummy2: 'value2'
|
97
|
+
assert_equal tag.allowed_children, [:text]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_html_tag_init_block_without_class
|
101
|
+
e = assert_raises ArgumentError do
|
102
|
+
Sablon::Configuration::HTMLTag.new(:form, :block)
|
103
|
+
end
|
104
|
+
assert_equal "Block level tag form must have an AST class.", e.message
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_html_tag_allowed_children
|
108
|
+
# define different tags for testing
|
109
|
+
text = Sablon::Configuration::HTMLTag.new(:text, :inline)
|
110
|
+
div = Sablon::Configuration::HTMLTag.new(:div, :block, ast_class: :paragraph)
|
111
|
+
olist = Sablon::Configuration::HTMLTag.new(:ol, :block, ast_class: :paragraph, allowed_children: %i[_block])
|
112
|
+
|
113
|
+
# test default allowances
|
114
|
+
assert div.allowed_child?(text) # all inline elements allowed
|
115
|
+
assert div.allowed_child?(olist) # tag name is included even though it is bock leve
|
116
|
+
assert_equal div.allowed_child?(div), false # other block elms are not allowed
|
117
|
+
|
118
|
+
# test olist with allowances for all blocks but no inline
|
119
|
+
assert olist.allowed_child?(div) # all block elements allowed
|
120
|
+
assert_equal olist.allowed_child?(text), false # no inline elements
|
121
|
+
end
|
122
|
+
end
|
data/test/content_test.rb
CHANGED
@@ -76,6 +76,7 @@ module ContentTestSetup
|
|
76
76
|
@document = Nokogiri::XML.fragment(@template_text)
|
77
77
|
@paragraph = @document.children.first
|
78
78
|
@node = @document.css("span").first
|
79
|
+
@env = Sablon::Environment.new(nil)
|
79
80
|
end
|
80
81
|
|
81
82
|
private
|
@@ -88,7 +89,7 @@ class ContentStringTest < Sablon::TestCase
|
|
88
89
|
include ContentTestSetup
|
89
90
|
|
90
91
|
def test_single_line_string
|
91
|
-
Sablon.content(:string, "a normal string").append_to @paragraph, @node
|
92
|
+
Sablon.content(:string, "a normal string").append_to @paragraph, @node, @env
|
92
93
|
|
93
94
|
output = <<-XML.strip
|
94
95
|
<w:p><span>template</span><span>a normal string</span></w:p><w:p>AFTER</w:p>
|
@@ -97,7 +98,7 @@ class ContentStringTest < Sablon::TestCase
|
|
97
98
|
end
|
98
99
|
|
99
100
|
def test_numeric_string
|
100
|
-
Sablon.content(:string, 42).append_to @paragraph, @node
|
101
|
+
Sablon.content(:string, 42).append_to @paragraph, @node, @env
|
101
102
|
|
102
103
|
output = <<-XML.strip
|
103
104
|
<w:p><span>template</span><span>42</span></w:p><w:p>AFTER</w:p>
|
@@ -106,7 +107,7 @@ class ContentStringTest < Sablon::TestCase
|
|
106
107
|
end
|
107
108
|
|
108
109
|
def test_string_with_newlines
|
109
|
-
Sablon.content(:string, "a\nmultiline\n\nstring").append_to @paragraph, @node
|
110
|
+
Sablon.content(:string, "a\nmultiline\n\nstring").append_to @paragraph, @node, @env
|
110
111
|
|
111
112
|
output = <<-XML.strip.gsub("\n", "")
|
112
113
|
<w:p>
|
@@ -125,7 +126,7 @@ class ContentStringTest < Sablon::TestCase
|
|
125
126
|
end
|
126
127
|
|
127
128
|
def test_blank_string
|
128
|
-
Sablon.content(:string, "").append_to @paragraph, @node
|
129
|
+
Sablon.content(:string, "").append_to @paragraph, @node, @env
|
129
130
|
|
130
131
|
assert_xml_equal @template_text, @document
|
131
132
|
end
|
@@ -135,14 +136,14 @@ class ContentWordMLTest < Sablon::TestCase
|
|
135
136
|
include ContentTestSetup
|
136
137
|
|
137
138
|
def test_blank_word_ml
|
138
|
-
Sablon.content(:word_ml, "").append_to @paragraph, @node
|
139
|
+
Sablon.content(:word_ml, "").append_to @paragraph, @node, @env
|
139
140
|
|
140
141
|
assert_xml_equal "<w:p>AFTER</w:p>", @document
|
141
142
|
end
|
142
143
|
|
143
144
|
def test_inserts_word_ml_into_the_document
|
144
145
|
@word_ml = '<w:p><w:r><w:t xml:space="preserve">a </w:t></w:r></w:p>'
|
145
|
-
Sablon.content(:word_ml, @word_ml).append_to @paragraph, @node
|
146
|
+
Sablon.content(:word_ml, @word_ml).append_to @paragraph, @node, @env
|
146
147
|
|
147
148
|
output = <<-XML.strip.gsub("\n", "")
|
148
149
|
<w:p>
|
data/test/context_test.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require "test_helper"
|
3
3
|
|
4
|
-
class
|
4
|
+
class EnvironmentTest < Sablon::TestCase
|
5
5
|
def test_converts_symbol_keys_to_string_keys
|
6
|
-
|
7
|
-
assert_equal({"a"=>1, "b"=>{"c" =>2, "d"=>3}},
|
6
|
+
context = Sablon::Context.transform_hash(a: 1, b: { c: 2, "d" => 3 })
|
7
|
+
assert_equal({ "a" => 1, "b" => { "c" => 2, "d" => 3 } }, context)
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_recognizes_wordml_keys
|
11
|
-
|
12
|
-
assert_equal({ "mykey"=>Sablon.content(:word_ml, "<w:p><w:p>"),
|
13
|
-
"otherkey"=>"<nope>"},
|
11
|
+
context = Sablon::Context.transform_hash("word_ml:mykey" => "<w:p><w:p>", "otherkey" => "<nope>")
|
12
|
+
assert_equal({ "mykey" => Sablon.content(:word_ml, "<w:p><w:p>"),
|
13
|
+
"otherkey" => "<nope>"}, context)
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_recognizes_html_keys
|
17
|
-
|
18
|
-
assert_equal({ "mykey"=>Sablon.content(:html, "**yay**"),
|
19
|
-
"otherkey"=>"<nope>"},
|
17
|
+
context = Sablon::Context.transform_hash("html:mykey" => "**yay**", "otherkey" => "<nope>")
|
18
|
+
assert_equal({ "mykey" => Sablon.content(:html, "**yay**"),
|
19
|
+
"otherkey" => "<nope>"}, context)
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_does_not_wrap_html_and_wordml_with_nil_value
|
23
|
-
|
23
|
+
context = Sablon::Context.transform_hash("html:mykey" => nil, "word_ml:otherkey" => nil, "normalkey" => nil)
|
24
24
|
assert_equal({ "mykey" => nil,
|
25
25
|
"otherkey" => nil,
|
26
|
-
"normalkey" => nil},
|
26
|
+
"normalkey" => nil}, context)
|
27
27
|
end
|
28
28
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "test_helper"
|
3
|
+
|
4
|
+
class EnvironmentTest < Sablon::TestCase
|
5
|
+
def test_transforms_internal_hash
|
6
|
+
context = Sablon::Context.transform_hash(a: 1, b: { c: 2, "d" => 3 })
|
7
|
+
env = Sablon::Environment.new(nil, a: 1, b: { c: 2, "d" => 3 })
|
8
|
+
#
|
9
|
+
assert_nil env.template
|
10
|
+
assert_equal context, env.context
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_alter_context
|
14
|
+
# set initial context
|
15
|
+
env = Sablon::Environment.new(nil, a: 1, b: { c: 2, "d" => 3 })
|
16
|
+
# alter context to change a single key and set a new one
|
17
|
+
env2 = env.alter_context(a: "a", e: "new-key")
|
18
|
+
assert_equal({ "a" => "a", "b" => { "c" => 2, "d" => 3 }, "e" => "new-key" }, env2.context)
|
19
|
+
# check that the old context was not modified
|
20
|
+
assert_equal({"a" => 1, "b" => { "c" => 2, "d" => 3 }}, env.context)
|
21
|
+
# check that numbering and template are the same references
|
22
|
+
assert env.template.equal?(env2.template), "#{env.template} != #{env2.template}"
|
23
|
+
assert env.numbering.equal?(env2.numbering), "#{env.numbering} != #{env2.numbering}"
|
24
|
+
# check that a new context reference was created
|
25
|
+
assert !env.context.equal?(env2.context), "#{env.context} == #{env2.context}"
|
26
|
+
end
|
27
|
+
end
|
data/test/expression_test.rb
CHANGED
@@ -55,7 +55,7 @@ class LookupOrMethodCallTest < Sablon::TestCase
|
|
55
55
|
def test_missing_receiver
|
56
56
|
user = OpenStruct.new(first_name: "Jack")
|
57
57
|
expr = Sablon::Expression.parse("user.address.line_1")
|
58
|
-
|
59
|
-
|
58
|
+
assert_nil expr.evaluate("user" => user)
|
59
|
+
assert_nil expr.evaluate({})
|
60
60
|
end
|
61
61
|
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
<h1>Sablon HTML insertion</h1>
|
2
|
+
|
3
|
+
<h2>Text</h2>
|
4
|
+
|
5
|
+
<div>
|
6
|
+
Lorem <strong>ipsum</strong> <em>dolor</em> <strong>sit</strong>
|
7
|
+
<em>amet</em>, <strong>consectetur adipiscing elit</strong>.
|
8
|
+
<em>Suspendisse a tempus turpis</em>. <span>Duis urna <b>justo</b>,
|
9
|
+
<i>vehicula</i> vitae ultricies vel, congue at sem.</span> Fusce turpis
|
10
|
+
turpis, aliquet id pulvinar aliquam, iaculis non elit. Nulla feugiat
|
11
|
+
lectus nulla, in dictum ipsum cursus ac. Quisque at odio neque.
|
12
|
+
Sed ac tortor iaculis, bibendum leo ut, malesuada velit. Donec iaculis
|
13
|
+
sed urna eget pharetra. <u>Praesent ornare fermentum turpis</u>, placerat
|
14
|
+
iaculis urna bibendum vitae. Nunc in quam consequat, tristique tellus in,
|
15
|
+
commodo turpis. Curabitur ullamcorper odio purus, lobortis egestas magna
|
16
|
+
laoreet vitae. Nunc fringilla velit ante, eu aliquam nisi cursus vitae.
|
17
|
+
Suspendisse sit amet dui <s><sup>egestas</sup>, <sub>volutpat</sub></s>
|
18
|
+
nisi vel, mattis justo. Nullam pellentesque, ipsum eget blandit pharetra,
|
19
|
+
augue elit <sup>aliquam <sub>mauris</sub></sup>, vel mollis nisl augue ut
|
20
|
+
<s>ipsum</s>.
|
21
|
+
</div>
|
22
|
+
|
23
|
+
<h2>HTML Entities</h2>
|
24
|
+
<div>
|
25
|
+
All HTML entities should get passed through to the final doc <br/>
|
26
|
+
Less Than: < <br/>
|
27
|
+
Ampersand: & <br/>
|
28
|
+
Percent: % <br/>
|
29
|
+
One Quarter: ¼ <br/>
|
30
|
+
</div>
|
31
|
+
|
32
|
+
|
33
|
+
<h2>Lists</h2>
|
34
|
+
|
35
|
+
<ol>
|
36
|
+
<li>
|
37
|
+
Vestibulum
|
38
|
+
<ol>
|
39
|
+
<li>ante ipsum primis </li>
|
40
|
+
</ol>
|
41
|
+
</li>
|
42
|
+
<li>
|
43
|
+
in faucibus orci luctus
|
44
|
+
<ol>
|
45
|
+
<li>et ultrices posuere cubilia Curae;
|
46
|
+
<ol>
|
47
|
+
<li>Aliquam vel dolor </li>
|
48
|
+
<li>sed sem maximus </li>
|
49
|
+
</ol>
|
50
|
+
</li>
|
51
|
+
<li>
|
52
|
+
fermentum in non odio.
|
53
|
+
<ol>
|
54
|
+
<li>Fusce hendrerit ornare mollis. </li>
|
55
|
+
</ol>
|
56
|
+
</li>
|
57
|
+
<li>Nunc scelerisque nibh nec turpis tempor pulvinar. </li>
|
58
|
+
</ol>
|
59
|
+
</li>
|
60
|
+
<li>Donec eros turpis, </li>
|
61
|
+
<li>
|
62
|
+
aliquet vel volutpat sit amet,
|
63
|
+
<ol>
|
64
|
+
<li>semper eu purus. </li>
|
65
|
+
<li>
|
66
|
+
Proin ac erat nec urna efficitur vulputate.
|
67
|
+
<ol>
|
68
|
+
<li>Quisque varius convallis ultricies. </li>
|
69
|
+
<li>Nullam vel fermentum eros. </li>
|
70
|
+
</ol>
|
71
|
+
</li>
|
72
|
+
</ol>
|
73
|
+
</li>
|
74
|
+
</ol>
|
75
|
+
|
76
|
+
<div>
|
77
|
+
Pellentesque nulla leo, auctor ornare erat sed, rhoncus congue diam.
|
78
|
+
Duis non porttitor nulla, ut eleifend enim. Pellentesque non tempor sem.
|
79
|
+
</div>
|
80
|
+
|
81
|
+
<div>Mauris auctor egestas arcu, </div>
|
82
|
+
|
83
|
+
<ol>
|
84
|
+
<li>id venenatis nibh dignissim id. </li>
|
85
|
+
<li>In non placerat metus. </li>
|
86
|
+
</ol>
|
87
|
+
|
88
|
+
<ul>
|
89
|
+
<li>Nunc sed consequat metus. </li>
|
90
|
+
<li>Nulla consectetur lorem consequat, </li>
|
91
|
+
<li>malesuada dui at, lacinia lectus. </li>
|
92
|
+
</ul>
|
93
|
+
|
94
|
+
<ol>
|
95
|
+
<li>Aliquam efficitur </li>
|
96
|
+
<li>lorem a mauris feugiat, </li>
|
97
|
+
<li>at semper eros pellentesque. </li>
|
98
|
+
</ol>
|
99
|
+
|
100
|
+
<div>
|
101
|
+
Nunc lacus diam, consectetur ut odio sit amet, placerat pharetra erat.
|
102
|
+
Sed commodo ut sem id congue. Sed eget neque elit. Curabitur at erat tortor.
|
103
|
+
Maecenas eget sapien vitae est sagittis accumsan et nec orci. Integer
|
104
|
+
luctus at nisl eget venenatis. Nunc nunc eros, consectetur at tortor et,
|
105
|
+
tristique ultrices elit. Nulla in turpis nibh.
|
106
|
+
</div>
|
107
|
+
|
108
|
+
<ul>
|
109
|
+
<li>
|
110
|
+
Nam consectetur
|
111
|
+
<ul>
|
112
|
+
<li>venenatis tempor. </li>
|
113
|
+
</ul>
|
114
|
+
</li>
|
115
|
+
<li>
|
116
|
+
Aenean
|
117
|
+
<ul>
|
118
|
+
<li>blandit
|
119
|
+
<ul>
|
120
|
+
<li>porttitor massa,
|
121
|
+
<ul>
|
122
|
+
<li>non efficitur
|
123
|
+
<ul>
|
124
|
+
<li>metus. </li>
|
125
|
+
</ul>
|
126
|
+
</li>
|
127
|
+
</ul>
|
128
|
+
</li>
|
129
|
+
</ul>
|
130
|
+
</li>
|
131
|
+
</ul>
|
132
|
+
</li>
|
133
|
+
<li>Duis faucibus nunc nec venenatis faucibus. </li>
|
134
|
+
<li>Aliquam erat volutpat. </li>
|
135
|
+
</ul>
|
136
|
+
<div style="border: 5px double #FF00FF">
|
137
|
+
<strong>Quisque non neque ut lacus eleifend volutpat quis sed lacus.
|
138
|
+
<br />Praesent ultrices purus eu quam elementum, sit amet faucibus elit
|
139
|
+
interdum. In lectus orci,<br /> elementum quis dictum ac, porta ac ante.
|
140
|
+
Fusce tempus ac mauris id cursus. Phasellus a erat nulla. <em>Mauris dolor orci</em>,
|
141
|
+
malesuada auctor dignissim non, <u>posuere nec odio</u>. Etiam hendrerit
|
142
|
+
justo nec diam ullamcorper, nec blandit elit sodales.</strong>
|
143
|
+
</div>
|
144
|
+
|
145
|
+
|
146
|
+
<div style="text-align: both; background-color: #EAFEDA; vertical-align: top">
|
147
|
+
<span style="font-size: 24;">U</span>t eget auctor enim.
|
148
|
+
<span style="text-decoration: underline wavyDouble #123456">Quisque id
|
149
|
+
neque eu nibh feugiat <b style="text-decoration: line-through">imperdiet</b>
|
150
|
+
id ut dui.</span> Ut auctor libero eget <em style="text-decoration: emboss; color: #F3AADE">
|
151
|
+
massa tristique pharetra</em>. Cras tincidunt finibus sapien, ut maximus
|
152
|
+
tortor tempor at. <span style="background-color: #00FF00">Proin pulvinar
|
153
|
+
pretium</span> justo vitae malesuada. Suspendisse porta purus eget tortor
|
154
|
+
tincidunt vestibulum. Maecenas id egestas purus, quis vulputate
|
155
|
+
lacus. Quisque <span style="vertical-align: superscript">non</span>
|
156
|
+
<span style="vertical-align: subscript">eleifend</span> est.
|
157
|
+
</div>
|
158
|
+
|
159
|
+
<ul style="background-color: #F19F42">
|
160
|
+
<li>Item 1</li>
|
161
|
+
<li>Item 2</li>
|
162
|
+
<ul>
|
163
|
+
<li>Nested 1</li>
|
164
|
+
<li style="background-color: #FFAAAA">
|
165
|
+
Nested 2
|
166
|
+
<ul>
|
167
|
+
<li>Nested 2.1</li>
|
168
|
+
<li><span style="font-style: italic; font-weight: bold">Nested</span> 2.2</li>
|
169
|
+
<li>Nested 2.3</li>
|
170
|
+
</ul>
|
171
|
+
</li>
|
172
|
+
</ul>
|
173
|
+
<li>Item 3</li>
|
174
|
+
</ul>
|