minidown 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +73 -0
- data/Rakefile +4 -0
- data/bin/minidown +33 -0
- data/lib/minidown.rb +13 -0
- data/lib/minidown/document.rb +142 -0
- data/lib/minidown/element.rb +40 -0
- data/lib/minidown/elements.rb +15 -0
- data/lib/minidown/elements/block_element.rb +37 -0
- data/lib/minidown/elements/code_block_element.rb +44 -0
- data/lib/minidown/elements/dividing_line_element.rb +11 -0
- data/lib/minidown/elements/html_element.rb +22 -0
- data/lib/minidown/elements/indent_code_element.rb +23 -0
- data/lib/minidown/elements/line_element.rb +28 -0
- data/lib/minidown/elements/list_element.rb +36 -0
- data/lib/minidown/elements/list_group_element.rb +87 -0
- data/lib/minidown/elements/order_list_element.rb +20 -0
- data/lib/minidown/elements/paragraph_element.rb +56 -0
- data/lib/minidown/elements/raw_html_element.rb +11 -0
- data/lib/minidown/elements/table_element.rb +80 -0
- data/lib/minidown/elements/text_element.rb +198 -0
- data/lib/minidown/elements/unorder_list_element.rb +31 -0
- data/lib/minidown/html_helper.rb +18 -0
- data/lib/minidown/parser.rb +19 -0
- data/lib/minidown/utils.rb +28 -0
- data/lib/minidown/version.rb +3 -0
- data/minidown.gemspec +26 -0
- data/spec/blank_line_spec.rb +21 -0
- data/spec/code_block_spec.rb +182 -0
- data/spec/dividing_line_spec.rb +35 -0
- data/spec/h1_and_h2_spec.rb +55 -0
- data/spec/indent_block_spec.rb +17 -0
- data/spec/li_spec.rb +354 -0
- data/spec/minidown_spec.rb +12 -0
- data/spec/paragraph_spec.rb +17 -0
- data/spec/raw_html_spec.rb +43 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/start_with_gt_spec.rb +70 -0
- data/spec/start_with_shape_spec.rb +42 -0
- data/spec/table_spec.rb +63 -0
- data/spec/task_list_spec.rb +18 -0
- data/spec/text_element_spec.rb +317 -0
- metadata +175 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Minidown
|
2
|
+
class HtmlElement < Element
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize doc, content, name
|
6
|
+
super doc, content
|
7
|
+
@name = name
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse
|
11
|
+
nodes << self
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_html
|
15
|
+
build_tag @name do |tag|
|
16
|
+
# self.content is some Element
|
17
|
+
self.content = content.text if ParagraphElement === self.content
|
18
|
+
tag << self.content.to_html
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Minidown
|
2
|
+
class IndentCodeElement < Element
|
3
|
+
def initialize *_
|
4
|
+
super
|
5
|
+
@lines = [content]
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse
|
9
|
+
while line = unparsed_lines.shift
|
10
|
+
case line
|
11
|
+
when Utils::Regexp[:indent_code]
|
12
|
+
@lines << $1
|
13
|
+
else
|
14
|
+
unparsed_lines.unshift line
|
15
|
+
break
|
16
|
+
end
|
17
|
+
end
|
18
|
+
unparsed_lines.unshift '```'
|
19
|
+
unparsed_lines.unshift *@lines
|
20
|
+
unparsed_lines.unshift '```'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Minidown
|
2
|
+
class LineElement < Element
|
3
|
+
attr_accessor :display
|
4
|
+
|
5
|
+
def initialize doc, content=nil
|
6
|
+
super
|
7
|
+
@display = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def blank?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse
|
15
|
+
node = nodes.last
|
16
|
+
@display = (doc.within_block || TextElement === node)
|
17
|
+
nodes << self
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_html
|
21
|
+
if @display
|
22
|
+
br_tag
|
23
|
+
else
|
24
|
+
''
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Minidown
|
2
|
+
class ListElement < Element
|
3
|
+
attr_accessor :p_tag_content, :contents, :task_list, :checked
|
4
|
+
CheckedBox = '<input type="checkbox" class="task-list-item-checkbox" checked="" disabled="">'.freeze
|
5
|
+
UnCheckedBox = '<input type="checkbox" class="task-list-item-checkbox" disabled="">'.freeze
|
6
|
+
|
7
|
+
def initialize *_
|
8
|
+
super
|
9
|
+
@p_tag_content = false
|
10
|
+
@contents = [TextElement.new(doc, content)]
|
11
|
+
@task_list = false
|
12
|
+
@checked = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_html
|
16
|
+
@contents.map! do |content|
|
17
|
+
ParagraphElement === content ? content.text : content
|
18
|
+
end if @p_tag_content
|
19
|
+
content = list_content
|
20
|
+
content = build_tag('p'.freeze){|p| p << content} if @p_tag_content
|
21
|
+
attr = nil
|
22
|
+
attr = {class: 'task-list-item'.freeze} if @task_list
|
23
|
+
build_tag 'li'.freeze, attr do |li|
|
24
|
+
li << content
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_content
|
29
|
+
content = @contents.map(&:to_html).join(@p_tag_content ? br_tag : "\n".freeze)
|
30
|
+
if @task_list
|
31
|
+
content = (@checked ? CheckedBox : UnCheckedBox) + content
|
32
|
+
end
|
33
|
+
content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Minidown
|
2
|
+
class ListGroupElement < Element
|
3
|
+
IndentRegexp = /\A\s{4,}(.+)/
|
4
|
+
StartWithBlankRegexp = /\A\s+(.+)/
|
5
|
+
|
6
|
+
attr_accessor :lists, :indent_level
|
7
|
+
|
8
|
+
def parse
|
9
|
+
nodes << self
|
10
|
+
while line = unparsed_lines.shift
|
11
|
+
#handle nested list
|
12
|
+
if (line =~ UnorderListElement::NestRegexp && list_class = UnorderListElement) || (line =~ OrderListElement::NestRegexp && list_class = OrderListElement)
|
13
|
+
li, str = $1.size, $2
|
14
|
+
if li > @indent_level
|
15
|
+
list_class.new(doc, str, li).parse
|
16
|
+
@lists.last.contents << nodes.pop
|
17
|
+
next
|
18
|
+
elsif li == @indent_level
|
19
|
+
list_class.new(doc, str, li).parse
|
20
|
+
child = nodes.pop
|
21
|
+
if LineElement === nodes.last
|
22
|
+
@lists.last.p_tag_content = child.lists.first.p_tag_content = true
|
23
|
+
end
|
24
|
+
if child.is_a?(ListGroupElement)
|
25
|
+
nodes.push *child.children
|
26
|
+
@lists.push *child.lists
|
27
|
+
else
|
28
|
+
@lists.last.contents << child
|
29
|
+
end
|
30
|
+
next
|
31
|
+
else
|
32
|
+
unparsed_lines.unshift line
|
33
|
+
break
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
doc.parse_line line
|
38
|
+
child = nodes.pop
|
39
|
+
case child
|
40
|
+
when self.class
|
41
|
+
if LineElement === nodes.last
|
42
|
+
@lists.last.p_tag_content = child.lists.first.p_tag_content = true
|
43
|
+
end
|
44
|
+
nodes.push *child.children
|
45
|
+
@lists.push *child.lists
|
46
|
+
break
|
47
|
+
when ParagraphElement
|
48
|
+
contents = @lists.last.contents
|
49
|
+
if line =~ StartWithBlankRegexp
|
50
|
+
doc.parse_line $1
|
51
|
+
node = nodes.pop
|
52
|
+
if TextElement === node || ParagraphElement === node
|
53
|
+
if TextElement === contents.last
|
54
|
+
contents.push(contents.pop.paragraph)
|
55
|
+
end
|
56
|
+
node = node.paragraph if TextElement === node
|
57
|
+
end
|
58
|
+
else
|
59
|
+
if @blank
|
60
|
+
unparsed_lines.unshift line
|
61
|
+
break
|
62
|
+
end
|
63
|
+
node = child.text
|
64
|
+
end
|
65
|
+
contents << node if node
|
66
|
+
when LineElement
|
67
|
+
next_line = unparsed_lines.first
|
68
|
+
if next_line.nil? || next_line.empty? || StartWithBlankRegexp === next_line || self.class.const_get(:ListRegexp) === next_line
|
69
|
+
child.display = false
|
70
|
+
nodes << child
|
71
|
+
else
|
72
|
+
unparsed_lines.unshift line
|
73
|
+
break
|
74
|
+
end
|
75
|
+
else
|
76
|
+
@put_back << child if child
|
77
|
+
break
|
78
|
+
end
|
79
|
+
@blank = (LineElement === child)
|
80
|
+
end
|
81
|
+
children_range = (nodes.index(self) + 1)..-1
|
82
|
+
children.push *nodes[children_range]
|
83
|
+
nodes[children_range] = []
|
84
|
+
nodes.push *@put_back
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Minidown
|
2
|
+
class OrderListElement < ListGroupElement
|
3
|
+
NestRegexp = /\A(\s*)\d+\.\s+(.+)/
|
4
|
+
ListRegexp = Minidown::Utils::Regexp[:order_list]
|
5
|
+
|
6
|
+
def initialize doc, line, indent_level = 0
|
7
|
+
super doc, line
|
8
|
+
@children << ListElement.new(doc, content)
|
9
|
+
@lists = @children.dup
|
10
|
+
@indent_level = indent_level
|
11
|
+
@put_back = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_html
|
15
|
+
build_tag 'ol'.freeze do |content|
|
16
|
+
children.each { |child| content << child.to_html}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Minidown
|
2
|
+
class ParagraphElement < Element
|
3
|
+
attr_reader :contents
|
4
|
+
attr_accessor :extra
|
5
|
+
|
6
|
+
ExcludeSchemeRegexp = /\A[^@:]+\z/
|
7
|
+
StringSymbolRegexp = /"|'/
|
8
|
+
|
9
|
+
def initialize *_
|
10
|
+
super
|
11
|
+
@contents = [raw_content]
|
12
|
+
@extra = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
if ParagraphElement === nodes.last
|
17
|
+
nodes.last.contents << raw_content
|
18
|
+
else
|
19
|
+
nodes << self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def text
|
24
|
+
build_element raw_content
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_html
|
28
|
+
if @extra
|
29
|
+
contents.map{|content| ParagraphElement.new(doc, content).to_html }.join ''.freeze
|
30
|
+
else
|
31
|
+
contents.map! do |line|
|
32
|
+
build_element line
|
33
|
+
end
|
34
|
+
build_tag 'p'.freeze do |content|
|
35
|
+
pre_elem = contents.shift
|
36
|
+
content << pre_elem.to_html
|
37
|
+
while elem = contents.shift
|
38
|
+
content << br_tag if TextElement === pre_elem && TextElement === elem
|
39
|
+
content << elem.to_html
|
40
|
+
pre_elem = elem
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def build_element content_str
|
49
|
+
if Utils::Regexp[:raw_html] =~ content_str && (raw = $1) && (ExcludeSchemeRegexp =~ raw || StringSymbolRegexp =~ raw)
|
50
|
+
RawHtmlElement.new doc, raw
|
51
|
+
else
|
52
|
+
TextElement.new doc, content_str
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Minidown
|
2
|
+
class TableElement < Element
|
3
|
+
AlignSpecRegexp = /\A\|?\s*([\-:]\-+[\-:]\s*(?:\|\s*[\-:]\-+[\-:]\s*)*)\|?\s*\z/
|
4
|
+
|
5
|
+
def initialize doc, content, raw_head
|
6
|
+
super doc, content
|
7
|
+
@raw_head = raw_head
|
8
|
+
@heads = @raw_head.split('|'.freeze).map! &:strip
|
9
|
+
@column_count = @heads.count
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_column_spec raw_column_spec
|
13
|
+
if @valid.nil?
|
14
|
+
@valid = Utils::Regexp[:pipe_symbol] =~ raw_column_spec && AlignSpecRegexp =~ raw_column_spec && (column_spec_str = $1) && (@column_specs = column_spec_str.split('|'.freeze).map! &:strip) && @column_specs.count == @column_count
|
15
|
+
else
|
16
|
+
@valid
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse
|
21
|
+
if @valid
|
22
|
+
nodes << self
|
23
|
+
@bodys = []
|
24
|
+
@column_specs.map! do |column_spec|
|
25
|
+
if column_spec[0] == column_spec[-1]
|
26
|
+
column_spec[0] == ':'.freeze ? 'center'.freeze : nil
|
27
|
+
else
|
28
|
+
column_spec[0] == ':'.freeze ? 'left'.freeze : 'right'.freeze
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
while line = unparsed_lines.shift
|
33
|
+
if Utils::Regexp[:table] =~ line && (cells = $1.split('|'.freeze).map! &:strip) && @column_count == cells.count
|
34
|
+
@bodys << cells
|
35
|
+
else
|
36
|
+
unparsed_lines.unshift line
|
37
|
+
break
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
raise 'table column specs not valid'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_html
|
46
|
+
attrs = @column_specs.map do |align|
|
47
|
+
{align: align}.freeze if align
|
48
|
+
end
|
49
|
+
build_tag 'table'.freeze do |table|
|
50
|
+
thead = build_tag 'thead'.freeze do |thead|
|
51
|
+
tr = build_tag 'tr'.freeze do |tr|
|
52
|
+
@heads.each_with_index do |cell, i|
|
53
|
+
th = build_tag 'th'.freeze, attrs[i] do |th|
|
54
|
+
th << cell
|
55
|
+
end
|
56
|
+
tr << th
|
57
|
+
end
|
58
|
+
end
|
59
|
+
thead << tr
|
60
|
+
end
|
61
|
+
table << thead
|
62
|
+
|
63
|
+
tbody = build_tag 'tbody'.freeze do |tbody|
|
64
|
+
@bodys.each do |row|
|
65
|
+
tr = build_tag 'tr'.freeze do |tr|
|
66
|
+
row.each_with_index do |cell, i|
|
67
|
+
td = build_tag 'td'.freeze, attrs[i] do |td|
|
68
|
+
td << TextElement.new(doc, cell).to_html
|
69
|
+
end
|
70
|
+
tr << td
|
71
|
+
end
|
72
|
+
end
|
73
|
+
tbody << tr
|
74
|
+
end
|
75
|
+
end
|
76
|
+
table << tbody
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
module Minidown
|
2
|
+
class TextElement < Element
|
3
|
+
EscapeChars = %w{# > * + \- ` _ { } ( ) . ! \[ \] ~}
|
4
|
+
EscapeRegexp = /(?<!\\)\\([#{EscapeChars.join '|'}|\\])/
|
5
|
+
|
6
|
+
Regexp = {
|
7
|
+
tag: /(\\*)<(.+?)(\\*)>/,
|
8
|
+
quot: /"/,
|
9
|
+
link: /(?<!\!)\[(.+?)\]\((.+?)\)/,
|
10
|
+
link_title: /((?<=").+?(?="))/,
|
11
|
+
link_url: /(\S+)/,
|
12
|
+
link_ref: /(?<!\!)\[(.+?)\]\s*\[(.*?)\]/,
|
13
|
+
image: /\!\[(.+?)\]\((.+?)\)/,
|
14
|
+
image_ref: /\!\[(.+?)\]\s*\[(.*?)\]/,
|
15
|
+
star: /((?<!\\)\*{1,2})(.+?)\1/,
|
16
|
+
underline: /(?<=\A|\s)((?<!\\)\_{1,2})(\S+)\1(?=\z|\s)/,
|
17
|
+
delete_line: /(?<!\\)~~(?!\s)(.+?)(?<!\s)~~/,
|
18
|
+
quotlink: /\<(.+?)\>/,
|
19
|
+
link_scheme: /\A\S+?\:\/\//,
|
20
|
+
email: /\A[A-Za-z0-9]+@[A-Za-z0-9]+\.[A-Za-z0-9]+/,
|
21
|
+
auto_email: /(?<!\S)[A-Za-z0-9]+@[A-Za-z0-9]+\.[A-Za-z0-9]+(?!\S)/,
|
22
|
+
auto_link: /(?<!\S)\w+?\:\/\/.+?(?!\S)/,
|
23
|
+
inline_code: /(?<!\\)(`+)\s*(.+?)\s*(?<!\\)\1/
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
attr_accessor :escape, :convert, :sanitize
|
27
|
+
|
28
|
+
def initialize *_
|
29
|
+
super
|
30
|
+
@escape = true
|
31
|
+
@sanitize = false
|
32
|
+
@convert = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse
|
36
|
+
nodes << self
|
37
|
+
end
|
38
|
+
|
39
|
+
def content
|
40
|
+
str = super
|
41
|
+
str = convert_str(str) if convert
|
42
|
+
escape_content! str
|
43
|
+
escape_str! str
|
44
|
+
escape_html str if sanitize
|
45
|
+
str
|
46
|
+
end
|
47
|
+
|
48
|
+
def escape_str! str
|
49
|
+
str.gsub!(EscapeRegexp, '\\1'.freeze) if escape
|
50
|
+
end
|
51
|
+
|
52
|
+
def escape_html str
|
53
|
+
str.replace Utils.escape_html(str)
|
54
|
+
end
|
55
|
+
|
56
|
+
def escape_content! str
|
57
|
+
return str unless @escape
|
58
|
+
escape_html str
|
59
|
+
|
60
|
+
str.gsub! Regexp[:tag] do
|
61
|
+
left, tag, right = $1, $2, $3
|
62
|
+
tag.gsub! Regexp[:quot] do
|
63
|
+
'"'.freeze
|
64
|
+
end
|
65
|
+
|
66
|
+
left = left.size.odd? ? "#{left[0..-2]}<" : "#{left}<" if left
|
67
|
+
left ||= "<".freeze
|
68
|
+
|
69
|
+
right = right.size.odd? ? "#{right[0..-2]}>" : "#{right}>" if right
|
70
|
+
right ||= ">".freeze
|
71
|
+
|
72
|
+
"#{left}#{tag}#{right}"
|
73
|
+
end
|
74
|
+
str
|
75
|
+
end
|
76
|
+
|
77
|
+
def convert_str str
|
78
|
+
#auto link
|
79
|
+
str.gsub! Regexp[:auto_link] do |origin_str|
|
80
|
+
build_tag 'a'.freeze, href: origin_str do |a|
|
81
|
+
a << origin_str
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#auto email
|
86
|
+
str.gsub! Regexp[:auto_email] do |origin_str|
|
87
|
+
build_tag 'a'.freeze, href: "mailto:#{origin_str}" do |a|
|
88
|
+
a << origin_str
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#parse <link>
|
93
|
+
str.gsub! Regexp[:quotlink] do |origin_str|
|
94
|
+
link = $1
|
95
|
+
attr = case link
|
96
|
+
when Regexp[:link_scheme]
|
97
|
+
{href: link}
|
98
|
+
when Regexp[:email]
|
99
|
+
{href: "mailto:#{link}"}
|
100
|
+
end
|
101
|
+
attr ? build_tag('a'.freeze, attr){|a| a << link} : origin_str
|
102
|
+
end
|
103
|
+
|
104
|
+
#parse * _
|
105
|
+
Regexp.values_at(:star, :underline).each do |regex|
|
106
|
+
str.gsub! regex do |origin_str|
|
107
|
+
tag_name = $1.size > 1 ? 'strong'.freeze : 'em'.freeze
|
108
|
+
build_tag tag_name do |tag|
|
109
|
+
tag << $2
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
#parse ~~del~~
|
115
|
+
str.gsub! Regexp[:delete_line] do |origin_str|
|
116
|
+
build_tag 'del'.freeze do |tag|
|
117
|
+
tag << $1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
#convert image reference
|
122
|
+
str.gsub! Regexp[:image_ref] do |origin_str|
|
123
|
+
alt = $1
|
124
|
+
id = ($2 && !$2.empty?) ? $2 : $1
|
125
|
+
ref = doc.links_ref[id.downcase]
|
126
|
+
if ref
|
127
|
+
attr = {src: ref[:url], alt: alt}
|
128
|
+
attr[:title] = ref[:title] if ref[:title] && !ref[:title].empty?
|
129
|
+
build_tag 'img'.freeze, attr
|
130
|
+
else
|
131
|
+
origin_str
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#convert image syntax
|
136
|
+
str.gsub! Regexp[:image] do
|
137
|
+
alt, url = $1, $2
|
138
|
+
url =~ Regexp[:link_title]
|
139
|
+
title = $1
|
140
|
+
url =~ Regexp[:link_url]
|
141
|
+
url = $1
|
142
|
+
attr = {src: url, alt: alt}
|
143
|
+
attr[:title] = title if title
|
144
|
+
build_tag 'img'.freeze, attr
|
145
|
+
end
|
146
|
+
|
147
|
+
#convert link reference
|
148
|
+
str.gsub! Regexp[:link_ref] do |origin_str|
|
149
|
+
text = $1
|
150
|
+
id = ($2 && !$2.empty?) ? $2 : $1
|
151
|
+
ref = doc.links_ref[id.downcase]
|
152
|
+
if ref
|
153
|
+
attr = {href: ref[:url]}
|
154
|
+
attr[:title] = ref[:title] if ref[:title] && !ref[:title].empty?
|
155
|
+
build_tag 'a'.freeze, attr do |a|
|
156
|
+
a << text
|
157
|
+
end
|
158
|
+
else
|
159
|
+
origin_str
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
#convert link syntax
|
164
|
+
str.gsub! Regexp[:link] do
|
165
|
+
text, url = $1, $2
|
166
|
+
url =~ Regexp[:link_title]
|
167
|
+
title = $1
|
168
|
+
url =~ Regexp[:link_url]
|
169
|
+
url = $1
|
170
|
+
attr = {href: url}
|
171
|
+
attr[:title] = title if title
|
172
|
+
build_tag 'a'.freeze, attr do |content|
|
173
|
+
content << text
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
escape_content! str
|
178
|
+
|
179
|
+
#inline code
|
180
|
+
str.gsub! Regexp[:inline_code] do |origin_str|
|
181
|
+
build_tag 'code'.freeze do |code|
|
182
|
+
code << escape_html($2)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
escape_str! str
|
186
|
+
@escape = false
|
187
|
+
str
|
188
|
+
end
|
189
|
+
|
190
|
+
def paragraph
|
191
|
+
ParagraphElement.new doc, raw_content
|
192
|
+
end
|
193
|
+
|
194
|
+
def to_html
|
195
|
+
content
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|