motion-markdown-it 0.4.0.3.0
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 +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
|