motion-markdown-it 0.4.0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +243 -0
- data/lib/motion-markdown-it.rb +71 -0
- data/lib/motion-markdown-it/common/entities.rb +1084 -0
- data/lib/motion-markdown-it/common/html_blocks.rb +60 -0
- data/lib/motion-markdown-it/common/html_re.rb +28 -0
- data/lib/motion-markdown-it/common/string.rb +14 -0
- data/lib/motion-markdown-it/common/url_schemas.rb +173 -0
- data/lib/motion-markdown-it/common/utils.rb +216 -0
- data/lib/motion-markdown-it/helpers/parse_link_destination.rb +75 -0
- data/lib/motion-markdown-it/helpers/parse_link_label.rb +51 -0
- data/lib/motion-markdown-it/helpers/parse_link_title.rb +48 -0
- data/lib/motion-markdown-it/index.rb +507 -0
- data/lib/motion-markdown-it/parser_block.rb +113 -0
- data/lib/motion-markdown-it/parser_core.rb +46 -0
- data/lib/motion-markdown-it/parser_inline.rb +121 -0
- data/lib/motion-markdown-it/presets/commonmark.rb +76 -0
- data/lib/motion-markdown-it/presets/default.rb +42 -0
- data/lib/motion-markdown-it/presets/zero.rb +59 -0
- data/lib/motion-markdown-it/renderer.rb +286 -0
- data/lib/motion-markdown-it/ruler.rb +327 -0
- data/lib/motion-markdown-it/rules_block/blockquote.rb +138 -0
- data/lib/motion-markdown-it/rules_block/code.rb +35 -0
- data/lib/motion-markdown-it/rules_block/fence.rb +94 -0
- data/lib/motion-markdown-it/rules_block/heading.rb +56 -0
- data/lib/motion-markdown-it/rules_block/hr.rb +45 -0
- data/lib/motion-markdown-it/rules_block/html_block.rb +73 -0
- data/lib/motion-markdown-it/rules_block/lheading.rb +54 -0
- data/lib/motion-markdown-it/rules_block/list.rb +242 -0
- data/lib/motion-markdown-it/rules_block/paragraph.rb +51 -0
- data/lib/motion-markdown-it/rules_block/reference.rb +161 -0
- data/lib/motion-markdown-it/rules_block/state_block.rb +184 -0
- data/lib/motion-markdown-it/rules_block/table.rb +161 -0
- data/lib/motion-markdown-it/rules_core/block.rb +20 -0
- data/lib/motion-markdown-it/rules_core/inline.rb +20 -0
- data/lib/motion-markdown-it/rules_core/linkify.rb +138 -0
- data/lib/motion-markdown-it/rules_core/normalize.rb +44 -0
- data/lib/motion-markdown-it/rules_core/replacements.rb +90 -0
- data/lib/motion-markdown-it/rules_core/smartquotes.rb +158 -0
- data/lib/motion-markdown-it/rules_core/state_core.rb +20 -0
- data/lib/motion-markdown-it/rules_inline/autolink.rb +74 -0
- data/lib/motion-markdown-it/rules_inline/backticks.rb +51 -0
- data/lib/motion-markdown-it/rules_inline/emphasis.rb +172 -0
- data/lib/motion-markdown-it/rules_inline/entity.rb +51 -0
- data/lib/motion-markdown-it/rules_inline/escape.rb +55 -0
- data/lib/motion-markdown-it/rules_inline/html_inline.rb +49 -0
- data/lib/motion-markdown-it/rules_inline/image.rb +158 -0
- data/lib/motion-markdown-it/rules_inline/link.rb +153 -0
- data/lib/motion-markdown-it/rules_inline/newline.rb +47 -0
- data/lib/motion-markdown-it/rules_inline/state_inline.rb +57 -0
- data/lib/motion-markdown-it/rules_inline/strikethrough.rb +130 -0
- data/lib/motion-markdown-it/rules_inline/text.rb +94 -0
- data/lib/motion-markdown-it/token.rb +134 -0
- data/lib/motion-markdown-it/version.rb +5 -0
- data/spec/motion-markdown-it/bench_mark_spec.rb +44 -0
- data/spec/motion-markdown-it/commonmark_spec.rb +16 -0
- data/spec/motion-markdown-it/markdown_it_spec.rb +18 -0
- data/spec/motion-markdown-it/misc_spec.rb +277 -0
- data/spec/motion-markdown-it/ruler_spec.rb +153 -0
- data/spec/motion-markdown-it/testgen_helper.rb +68 -0
- data/spec/motion-markdown-it/token_spec.rb +17 -0
- data/spec/motion-markdown-it/utils_spec.rb +82 -0
- data/spec/spec_helper.rb +6 -0
- metadata +158 -0
@@ -0,0 +1,184 @@
|
|
1
|
+
# Parser state class
|
2
|
+
#------------------------------------------------------------------------------
|
3
|
+
module MarkdownIt
|
4
|
+
module RulesBlock
|
5
|
+
class StateBlock
|
6
|
+
|
7
|
+
attr_accessor :src, :md, :env, :tokens, :bMarks, :eMarks, :tShift
|
8
|
+
attr_accessor :blkIndent, :line, :lineMax, :tight, :parentType, :ddIndent
|
9
|
+
attr_accessor :level, :result
|
10
|
+
|
11
|
+
#------------------------------------------------------------------------------
|
12
|
+
def initialize(src, md, env, tokens)
|
13
|
+
@src = src
|
14
|
+
|
15
|
+
# link to parser instance
|
16
|
+
@md = md
|
17
|
+
@env = env
|
18
|
+
|
19
|
+
#--- Internal state variables
|
20
|
+
|
21
|
+
@tokens = tokens
|
22
|
+
|
23
|
+
@bMarks = [] # line begin offsets for fast jumps
|
24
|
+
@eMarks = [] # line end offsets for fast jumps
|
25
|
+
@tShift = [] # indent for each line
|
26
|
+
|
27
|
+
# block parser variables
|
28
|
+
@blkIndent = 0 # required block content indent (for example, if we are in list)
|
29
|
+
@line = 0 # line index in src
|
30
|
+
@lineMax = 0 # lines count
|
31
|
+
@tight = false # loose/tight mode for lists
|
32
|
+
@parentType = 'root' # if `list`, block parser stops on two newlines
|
33
|
+
@ddIndent = -1 # indent of the current dd block (-1 if there isn't any)
|
34
|
+
|
35
|
+
@level = 0
|
36
|
+
|
37
|
+
# renderer
|
38
|
+
@result = ''
|
39
|
+
|
40
|
+
# Create caches
|
41
|
+
# Generate markers.
|
42
|
+
s = @src
|
43
|
+
indent = 0
|
44
|
+
indent_found = false
|
45
|
+
|
46
|
+
start = pos = indent = 0
|
47
|
+
len = s.length
|
48
|
+
start.upto(len - 1) do |pos|
|
49
|
+
# !!!!!!
|
50
|
+
# for (start = pos = indent = 0, len = s.length pos < len pos++) {
|
51
|
+
ch = s.charCodeAt(pos)
|
52
|
+
|
53
|
+
if !indent_found
|
54
|
+
if ch == 0x20 # space
|
55
|
+
indent += 1
|
56
|
+
next
|
57
|
+
else
|
58
|
+
indent_found = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if ch == 0x0A || pos == (len - 1)
|
63
|
+
pos += 1 if ch != 0x0A
|
64
|
+
@bMarks.push(start)
|
65
|
+
@eMarks.push(pos)
|
66
|
+
@tShift.push(indent)
|
67
|
+
|
68
|
+
indent_found = false
|
69
|
+
indent = 0
|
70
|
+
start = pos + 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Push fake entry to simplify cache bounds checks
|
75
|
+
@bMarks.push(s.length)
|
76
|
+
@eMarks.push(s.length)
|
77
|
+
@tShift.push(0)
|
78
|
+
|
79
|
+
@lineMax = @bMarks.length - 1 # don't count last fake line
|
80
|
+
end
|
81
|
+
|
82
|
+
# Push new token to "stream".
|
83
|
+
#------------------------------------------------------------------------------
|
84
|
+
def push(type, tag, nesting)
|
85
|
+
token = Token.new(type, tag, nesting)
|
86
|
+
token.block = true
|
87
|
+
|
88
|
+
@level -= 1 if nesting < 0
|
89
|
+
token.level = @level
|
90
|
+
@level += 1 if nesting > 0
|
91
|
+
|
92
|
+
@tokens.push(token)
|
93
|
+
return token
|
94
|
+
end
|
95
|
+
|
96
|
+
#------------------------------------------------------------------------------
|
97
|
+
def isEmpty(line)
|
98
|
+
return @bMarks[line] + @tShift[line] >= @eMarks[line]
|
99
|
+
end
|
100
|
+
|
101
|
+
#------------------------------------------------------------------------------
|
102
|
+
def skipEmptyLines(from)
|
103
|
+
while from < @lineMax
|
104
|
+
break if (@bMarks[from] + @tShift[from] < @eMarks[from])
|
105
|
+
from += 1
|
106
|
+
end
|
107
|
+
return from
|
108
|
+
end
|
109
|
+
|
110
|
+
# Skip spaces from given position.
|
111
|
+
#------------------------------------------------------------------------------
|
112
|
+
def skipSpaces(pos)
|
113
|
+
max = @src.length
|
114
|
+
while pos < max
|
115
|
+
break if @src.charCodeAt(pos) != 0x20 # space
|
116
|
+
pos += 1
|
117
|
+
end
|
118
|
+
return pos
|
119
|
+
end
|
120
|
+
|
121
|
+
# Skip char codes from given position
|
122
|
+
#------------------------------------------------------------------------------
|
123
|
+
def skipChars(pos, code)
|
124
|
+
max = @src.length
|
125
|
+
while pos < max
|
126
|
+
break if (@src.charCodeAt(pos) != code)
|
127
|
+
pos += 1
|
128
|
+
end
|
129
|
+
return pos
|
130
|
+
end
|
131
|
+
|
132
|
+
# Skip char codes reverse from given position - 1
|
133
|
+
#------------------------------------------------------------------------------
|
134
|
+
def skipCharsBack(pos, code, min)
|
135
|
+
return pos if pos <= min
|
136
|
+
|
137
|
+
while (pos > min)
|
138
|
+
return (pos + 1) if code != @src.charCodeAt(pos -= 1)
|
139
|
+
end
|
140
|
+
return pos
|
141
|
+
end
|
142
|
+
|
143
|
+
# cut lines range from source.
|
144
|
+
#------------------------------------------------------------------------------
|
145
|
+
def getLines(line_begin, line_end, indent, keepLastLF)
|
146
|
+
line = line_begin
|
147
|
+
|
148
|
+
return '' if line_begin >= line_end
|
149
|
+
|
150
|
+
# Opt: don't use push queue for single line
|
151
|
+
if (line + 1) == line_end
|
152
|
+
first = @bMarks[line] + [@tShift[line], indent].min
|
153
|
+
last = keepLastLF ? @bMarks[line_end] : @eMarks[line_end - 1]
|
154
|
+
return @src.slice(first...last)
|
155
|
+
end
|
156
|
+
|
157
|
+
queue = Array.new(line_end - line_begin)
|
158
|
+
|
159
|
+
i = 0
|
160
|
+
while line < line_end
|
161
|
+
shift = @tShift[line]
|
162
|
+
shift = indent if shift > indent
|
163
|
+
shift = 0 if shift < 0
|
164
|
+
|
165
|
+
first = @bMarks[line] + shift
|
166
|
+
|
167
|
+
if line + 1 < line_end || keepLastLF
|
168
|
+
# No need for bounds check because we have fake entry on tail.
|
169
|
+
last = @eMarks[line] + 1
|
170
|
+
else
|
171
|
+
last = @eMarks[line]
|
172
|
+
end
|
173
|
+
|
174
|
+
queue[i] = @src.slice(first...last)
|
175
|
+
line += 1
|
176
|
+
i += 1
|
177
|
+
end
|
178
|
+
|
179
|
+
return queue.join('')
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# GFM table, non-standard
|
2
|
+
#------------------------------------------------------------------------------
|
3
|
+
module MarkdownIt
|
4
|
+
module RulesBlock
|
5
|
+
class Table
|
6
|
+
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
def self.getLine(state, line)
|
9
|
+
pos = state.bMarks[line] + state.blkIndent
|
10
|
+
max = state.eMarks[line]
|
11
|
+
|
12
|
+
return state.src[pos, max - pos]
|
13
|
+
end
|
14
|
+
|
15
|
+
#------------------------------------------------------------------------------
|
16
|
+
def self.escapedSplit(str)
|
17
|
+
result = []
|
18
|
+
pos = 0
|
19
|
+
max = str.length
|
20
|
+
escapes = 0
|
21
|
+
lastPos = 0
|
22
|
+
ch = str.charCodeAt(pos)
|
23
|
+
|
24
|
+
while (pos < max)
|
25
|
+
if (ch == 0x7c && (escapes % 2 == 0)) # '|'
|
26
|
+
result.push(str[lastPos...pos])
|
27
|
+
lastPos = pos + 1
|
28
|
+
elsif (ch == 0x5c) # '\'
|
29
|
+
escapes += 1
|
30
|
+
else
|
31
|
+
escapes = 0
|
32
|
+
end
|
33
|
+
|
34
|
+
pos += 1
|
35
|
+
ch = str.charCodeAt(pos)
|
36
|
+
end
|
37
|
+
|
38
|
+
result.push(str.slice_to_end(lastPos))
|
39
|
+
|
40
|
+
return result
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
#------------------------------------------------------------------------------
|
45
|
+
def self.table(state, startLine, endLine, silent)
|
46
|
+
# should have at least three lines
|
47
|
+
return false if (startLine + 2 > endLine)
|
48
|
+
|
49
|
+
nextLine = startLine + 1
|
50
|
+
|
51
|
+
return false if (state.tShift[nextLine] < state.blkIndent)
|
52
|
+
|
53
|
+
# first character of the second line should be '|' or '-'
|
54
|
+
pos = state.bMarks[nextLine] + state.tShift[nextLine]
|
55
|
+
return false if (pos >= state.eMarks[nextLine])
|
56
|
+
|
57
|
+
ch = state.src.charCodeAt(pos)
|
58
|
+
return false if (ch != 0x7C && ch != 0x2D && ch != 0x3A) # != '|' && '-' && ':'
|
59
|
+
|
60
|
+
lineText = getLine(state, startLine + 1)
|
61
|
+
return false if (/^[-:| ]+$/ =~ lineText).nil?
|
62
|
+
|
63
|
+
rows = lineText.split('|')
|
64
|
+
return false if (rows.length < 2)
|
65
|
+
aligns = []
|
66
|
+
(0...rows.length).each do |i|
|
67
|
+
t = rows[i].strip
|
68
|
+
if t.empty?
|
69
|
+
# allow empty columns before and after table, but not in between columns
|
70
|
+
# e.g. allow ` |---| `, disallow ` ---||--- `
|
71
|
+
if (i == 0 || i == rows.length - 1)
|
72
|
+
next
|
73
|
+
else
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
return false if (/^:?-+:?$/ =~ t).nil?
|
79
|
+
if (t.charCodeAt(t.length - 1) == 0x3A) # ':'
|
80
|
+
aligns.push(t.charCodeAt(0) == 0x3A ? 'center' : 'right')
|
81
|
+
elsif (t.charCodeAt(0) == 0x3A)
|
82
|
+
aligns.push('left')
|
83
|
+
else
|
84
|
+
aligns.push('')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
lineText = getLine(state, startLine).strip
|
89
|
+
return false if !lineText.include?('|')
|
90
|
+
rows = self.escapedSplit(lineText.gsub(/^\||\|$/, ''))
|
91
|
+
return false if (aligns.length != rows.length)
|
92
|
+
return true if silent
|
93
|
+
|
94
|
+
token = state.push('table_open', 'table', 1)
|
95
|
+
token.map = tableLines = [ startLine, 0 ]
|
96
|
+
|
97
|
+
token = state.push('thead_open', 'thead', 1)
|
98
|
+
token.map = [ startLine, startLine + 1 ]
|
99
|
+
|
100
|
+
token = state.push('tr_open', 'tr', 1)
|
101
|
+
token.map = [ startLine, startLine + 1 ]
|
102
|
+
|
103
|
+
(0...rows.length).each do |i|
|
104
|
+
token = state.push('th_open', 'th', 1)
|
105
|
+
token.map = [ startLine, startLine + 1 ]
|
106
|
+
unless aligns[i].empty?
|
107
|
+
token.attrs = [ [ 'style', 'text-align:' + aligns[i] ] ]
|
108
|
+
end
|
109
|
+
|
110
|
+
token = state.push('inline', '', 0)
|
111
|
+
token.content = rows[i].strip
|
112
|
+
token.map = [ startLine, startLine + 1 ]
|
113
|
+
token.children = []
|
114
|
+
|
115
|
+
token = state.push('th_close', 'th', -1)
|
116
|
+
end
|
117
|
+
|
118
|
+
token = state.push('tr_close', 'tr', -1)
|
119
|
+
token = state.push('thead_close', 'thead', -1)
|
120
|
+
|
121
|
+
token = state.push('tbody_open', 'tbody', 1)
|
122
|
+
token.map = tbodyLines = [ startLine + 2, 0 ]
|
123
|
+
|
124
|
+
nextLine = startLine + 2
|
125
|
+
while nextLine < endLine
|
126
|
+
break if (state.tShift[nextLine] < state.blkIndent)
|
127
|
+
|
128
|
+
lineText = getLine(state, nextLine).strip
|
129
|
+
break if !lineText.include?('|')
|
130
|
+
rows = self.escapedSplit(lineText.gsub(/^\||\|$/, ''))
|
131
|
+
|
132
|
+
# set number of columns to number of columns in header row
|
133
|
+
rows_length = aligns.length
|
134
|
+
|
135
|
+
token = state.push('tr_open', 'tr', 1)
|
136
|
+
(0...rows_length).each do |i|
|
137
|
+
token = state.push('td_open', 'td', 1)
|
138
|
+
unless aligns[i].empty?
|
139
|
+
token.attrs = [ [ 'style', 'text-align:' + aligns[i] ] ]
|
140
|
+
end
|
141
|
+
|
142
|
+
token = state.push('inline', '', 0)
|
143
|
+
token.content = rows[i] ? rows[i].strip : ''
|
144
|
+
token.children = []
|
145
|
+
|
146
|
+
token = state.push('td_close', 'td', -1)
|
147
|
+
end
|
148
|
+
token = state.push('tr_close', 'tr', -1)
|
149
|
+
nextLine += 1
|
150
|
+
end
|
151
|
+
token = state.push('tbody_close', 'tbody', -1)
|
152
|
+
token = state.push('table_close', 'table', -1)
|
153
|
+
|
154
|
+
tableLines[1] = tbodyLines[1] = nextLine
|
155
|
+
state.line = nextLine
|
156
|
+
return true
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MarkdownIt
|
2
|
+
module RulesCore
|
3
|
+
class Block
|
4
|
+
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
def self.block(state)
|
7
|
+
if state.inlineMode
|
8
|
+
token = Token.new('inline', '', 0)
|
9
|
+
token.content = state.src
|
10
|
+
token.map = [ 0, 1 ]
|
11
|
+
token.children = []
|
12
|
+
state.tokens.push(token)
|
13
|
+
else
|
14
|
+
state.md.block.parse(state.src, state.md, state.env, state.tokens)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MarkdownIt
|
2
|
+
module RulesCore
|
3
|
+
class Inline
|
4
|
+
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
def self.inline(state)
|
7
|
+
tokens = state.tokens
|
8
|
+
|
9
|
+
# Parse inlines
|
10
|
+
0.upto(tokens.length - 1) do |i|
|
11
|
+
tok = tokens[i]
|
12
|
+
if tok.type == 'inline'
|
13
|
+
state.md.inline.parse(tok.content, state.md, state.env, tok.children)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# Replace link-like texts with link nodes.
|
2
|
+
#
|
3
|
+
# Currently restricted by `md.validateLink()` to http/https/ftp
|
4
|
+
#------------------------------------------------------------------------------
|
5
|
+
module MarkdownIt
|
6
|
+
module RulesCore
|
7
|
+
class Linkify
|
8
|
+
|
9
|
+
#------------------------------------------------------------------------------
|
10
|
+
def self.isLinkOpen(str)
|
11
|
+
return !(/^<a[>\s]/i =~ str).nil?
|
12
|
+
end
|
13
|
+
def self.isLinkClose(str)
|
14
|
+
return !(/^<\/a\s*>/i =~ str).nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
#------------------------------------------------------------------------------
|
18
|
+
def self.linkify(state)
|
19
|
+
blockTokens = state.tokens
|
20
|
+
|
21
|
+
return if (!state.md.options[:linkify])
|
22
|
+
|
23
|
+
(0...blockTokens.length).each do |j|
|
24
|
+
if (blockTokens[j].type != 'inline' || !state.md.linkify.pretest(blockTokens[j].content))
|
25
|
+
next
|
26
|
+
end
|
27
|
+
|
28
|
+
tokens = blockTokens[j].children
|
29
|
+
|
30
|
+
htmlLinkLevel = 0
|
31
|
+
|
32
|
+
# We scan from the end, to keep position when new tags added.
|
33
|
+
# Use reversed logic in links start/end match
|
34
|
+
i = tokens.length - 1
|
35
|
+
while i >= 0
|
36
|
+
currentToken = tokens[i]
|
37
|
+
|
38
|
+
# Skip content of markdown links
|
39
|
+
if (currentToken.type == 'link_close')
|
40
|
+
i -= 1
|
41
|
+
while (tokens[i].level != currentToken.level && tokens[i].type != 'link_open')
|
42
|
+
i -= 1
|
43
|
+
end
|
44
|
+
next
|
45
|
+
end
|
46
|
+
|
47
|
+
# Skip content of html tag links
|
48
|
+
if (currentToken.type == 'html_inline')
|
49
|
+
if (isLinkOpen(currentToken.content) && htmlLinkLevel > 0)
|
50
|
+
htmlLinkLevel -= 1
|
51
|
+
end
|
52
|
+
if (isLinkClose(currentToken.content))
|
53
|
+
htmlLinkLevel -= 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
next if (htmlLinkLevel > 0)
|
57
|
+
|
58
|
+
if (currentToken.type == 'text' && state.md.linkify =~ currentToken.content)
|
59
|
+
|
60
|
+
text = currentToken.content
|
61
|
+
links = state.md.linkify.match(text)
|
62
|
+
|
63
|
+
# Now split string to nodes
|
64
|
+
nodes = []
|
65
|
+
level = currentToken.level
|
66
|
+
lastPos = 0
|
67
|
+
|
68
|
+
(0...links.length).each do |ln|
|
69
|
+
url = links[ln].url
|
70
|
+
fullUrl = state.md.normalizeLink.call(url)
|
71
|
+
next if (!state.md.validateLink.call(fullUrl))
|
72
|
+
|
73
|
+
urlText = links[ln].text
|
74
|
+
|
75
|
+
# Linkifier might send raw hostnames like "example.com", where url
|
76
|
+
# starts with domain name. So we prepend http:// in those cases,
|
77
|
+
# and remove it afterwards.
|
78
|
+
#
|
79
|
+
|
80
|
+
# TODO work on this when clearer
|
81
|
+
puts "Linkify requires work"
|
82
|
+
# if (!links[ln].schema)
|
83
|
+
# urlText = state.md.normalizeLinkText.call('http://' + urlText).replace(/^http:\/\//, '')
|
84
|
+
# elsif (links[ln].schema == 'mailto:' && !Regexp.new('^mailto:/i') =~ urlText)
|
85
|
+
# urlText = state.md.normalizeLinkText.call('mailto:' + urlText).replace(/^mailto:/, '');
|
86
|
+
# } else {
|
87
|
+
# urlText = state.md.normalizeLinkText.call(urlText);
|
88
|
+
# }
|
89
|
+
|
90
|
+
pos = links[ln].index
|
91
|
+
|
92
|
+
if (pos > lastPos)
|
93
|
+
token = Token.new('text', '', 0)
|
94
|
+
token.content = text.slice(lastPos...pos)
|
95
|
+
token.level = level
|
96
|
+
nodes.push(token)
|
97
|
+
end
|
98
|
+
|
99
|
+
token = Token.new('link_open', 'a', 1)
|
100
|
+
token.attrs = [ [ 'href', fullUrl ] ]
|
101
|
+
token.level = level
|
102
|
+
level += 1
|
103
|
+
token.markup = 'linkify'
|
104
|
+
token.info = 'auto'
|
105
|
+
nodes.push(token)
|
106
|
+
|
107
|
+
token = Token.new('text', '', 0)
|
108
|
+
token.content = urlText
|
109
|
+
token.level = level
|
110
|
+
nodes.push(token)
|
111
|
+
|
112
|
+
token = Token.new('link_close', 'a', -1)
|
113
|
+
level -= 1
|
114
|
+
token.level = level
|
115
|
+
token.markup = 'linkify'
|
116
|
+
token.info = 'auto'
|
117
|
+
nodes.push(token)
|
118
|
+
|
119
|
+
lastPos = links[ln].lastIndex
|
120
|
+
end
|
121
|
+
if (lastPos < text.length)
|
122
|
+
token = Token.new('text', '', 0)
|
123
|
+
token.content = text.slice_to_end(lastPos)
|
124
|
+
token.level = level
|
125
|
+
nodes.push(token)
|
126
|
+
end
|
127
|
+
|
128
|
+
# replace current node
|
129
|
+
blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes)
|
130
|
+
end
|
131
|
+
i -= 1
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|