bean-kramdown 0.13.5
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.
- data/AUTHORS +1 -0
- data/CONTRIBUTERS +11 -0
- data/COPYING +24 -0
- data/ChangeLog +6683 -0
- data/GPL +674 -0
- data/README +43 -0
- data/VERSION +1 -0
- data/bin/kramdown +78 -0
- data/lib/kramdown.rb +23 -0
- data/lib/kramdown/compatibility.rb +49 -0
- data/lib/kramdown/converter.rb +41 -0
- data/lib/kramdown/converter/base.rb +169 -0
- data/lib/kramdown/converter/bean_html.rb +71 -0
- data/lib/kramdown/converter/html.rb +411 -0
- data/lib/kramdown/converter/kramdown.rb +428 -0
- data/lib/kramdown/converter/latex.rb +607 -0
- data/lib/kramdown/converter/toc.rb +82 -0
- data/lib/kramdown/document.rb +119 -0
- data/lib/kramdown/element.rb +524 -0
- data/lib/kramdown/error.rb +30 -0
- data/lib/kramdown/options.rb +373 -0
- data/lib/kramdown/parser.rb +39 -0
- data/lib/kramdown/parser/base.rb +136 -0
- data/lib/kramdown/parser/bean_kramdown.rb +25 -0
- data/lib/kramdown/parser/bean_kramdown/info_box.rb +52 -0
- data/lib/kramdown/parser/bean_kramdown/oembed.rb +230 -0
- data/lib/kramdown/parser/html.rb +570 -0
- data/lib/kramdown/parser/kramdown.rb +339 -0
- data/lib/kramdown/parser/kramdown/abbreviation.rb +71 -0
- data/lib/kramdown/parser/kramdown/autolink.rb +53 -0
- data/lib/kramdown/parser/kramdown/blank_line.rb +43 -0
- data/lib/kramdown/parser/kramdown/block_boundary.rb +46 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +51 -0
- data/lib/kramdown/parser/kramdown/codeblock.rb +63 -0
- data/lib/kramdown/parser/kramdown/codespan.rb +56 -0
- data/lib/kramdown/parser/kramdown/emphasis.rb +70 -0
- data/lib/kramdown/parser/kramdown/eob.rb +39 -0
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +38 -0
- data/lib/kramdown/parser/kramdown/extensions.rb +204 -0
- data/lib/kramdown/parser/kramdown/footnote.rb +74 -0
- data/lib/kramdown/parser/kramdown/header.rb +68 -0
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +39 -0
- data/lib/kramdown/parser/kramdown/html.rb +169 -0
- data/lib/kramdown/parser/kramdown/html_entity.rb +44 -0
- data/lib/kramdown/parser/kramdown/image.rb +157 -0
- data/lib/kramdown/parser/kramdown/line_break.rb +38 -0
- data/lib/kramdown/parser/kramdown/link.rb +154 -0
- data/lib/kramdown/parser/kramdown/list.rb +240 -0
- data/lib/kramdown/parser/kramdown/math.rb +65 -0
- data/lib/kramdown/parser/kramdown/paragraph.rb +63 -0
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +214 -0
- data/lib/kramdown/parser/kramdown/table.rb +178 -0
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +52 -0
- data/lib/kramdown/parser/markdown.rb +69 -0
- data/lib/kramdown/utils.rb +42 -0
- data/lib/kramdown/utils/entities.rb +348 -0
- data/lib/kramdown/utils/html.rb +85 -0
- data/lib/kramdown/utils/ordered_hash.rb +100 -0
- data/lib/kramdown/version.rb +28 -0
- metadata +140 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'kramdown/parser/kramdown/extensions'
|
24
|
+
require 'kramdown/parser/kramdown/blank_line'
|
25
|
+
require 'kramdown/parser/kramdown/codeblock'
|
26
|
+
|
27
|
+
module Kramdown
|
28
|
+
module Parser
|
29
|
+
class Kramdown
|
30
|
+
|
31
|
+
FOOTNOTE_DEFINITION_START = /^#{OPT_SPACE}\[\^(#{ALD_ID_NAME})\]:\s*?(.*?\n#{CODEBLOCK_MATCH})/
|
32
|
+
|
33
|
+
# Parse the foot note definition at the current location.
|
34
|
+
def parse_footnote_definition
|
35
|
+
@src.pos += @src.matched_size
|
36
|
+
|
37
|
+
el = Element.new(:footnote_def)
|
38
|
+
parse_blocks(el, @src[2].gsub(INDENT, ''))
|
39
|
+
warning("Duplicate footnote name '#{@src[1]}' - overwriting") if @footnotes[@src[1]]
|
40
|
+
(@footnotes[@src[1]] = {})[:content] = el
|
41
|
+
@tree.children << Element.new(:eob, :footnote_def)
|
42
|
+
true
|
43
|
+
end
|
44
|
+
define_parser(:footnote_definition, FOOTNOTE_DEFINITION_START)
|
45
|
+
|
46
|
+
|
47
|
+
FOOTNOTE_MARKER_START = /\[\^(#{ALD_ID_NAME})\]/
|
48
|
+
|
49
|
+
# Parse the footnote marker at the current location.
|
50
|
+
def parse_footnote_marker
|
51
|
+
@src.pos += @src.matched_size
|
52
|
+
fn_def = @footnotes[@src[1]]
|
53
|
+
if fn_def
|
54
|
+
valid = fn_def[:marker] && fn_def[:stack][0..-2].zip(fn_def[:stack][1..-1]).all? do |par, child|
|
55
|
+
par.children.include?(child)
|
56
|
+
end
|
57
|
+
if !fn_def[:marker] || !valid
|
58
|
+
fn_def[:marker] = Element.new(:footnote, fn_def[:content], nil, :name => @src[1])
|
59
|
+
fn_def[:stack] = [@stack.map {|s| s.first}, @tree, fn_def[:marker]].flatten.compact
|
60
|
+
@tree.children << fn_def[:marker]
|
61
|
+
else
|
62
|
+
warning("Footnote marker '#{@src[1]}' already appeared in document, ignoring newly found marker")
|
63
|
+
add_text(@src.matched)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
warning("Footnote definition for '#{@src[1]}' not found")
|
67
|
+
add_text(@src.matched)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[')
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'kramdown/parser/kramdown/block_boundary'
|
24
|
+
|
25
|
+
module Kramdown
|
26
|
+
module Parser
|
27
|
+
class Kramdown
|
28
|
+
|
29
|
+
HEADER_ID=/(?:[ \t]\{#(\w[\w-]*)\})?/
|
30
|
+
SETEXT_HEADER_START = /^(#{OPT_SPACE}[^ \t].*?)#{HEADER_ID}[ \t]*?\n(-|=)+\s*?\n/
|
31
|
+
|
32
|
+
# Parse the Setext header at the current location.
|
33
|
+
def parse_setext_header
|
34
|
+
return false if !after_block_boundary?
|
35
|
+
|
36
|
+
@src.pos += @src.matched_size
|
37
|
+
text, id, level = @src[1], @src[2], @src[3]
|
38
|
+
text.strip!
|
39
|
+
el = new_block_el(:header, nil, nil, :level => (level == '-' ? 2 : 1), :raw_text => text)
|
40
|
+
add_text(text, el)
|
41
|
+
el.attr['id'] = id if id
|
42
|
+
@tree.children << el
|
43
|
+
true
|
44
|
+
end
|
45
|
+
define_parser(:setext_header, SETEXT_HEADER_START)
|
46
|
+
|
47
|
+
|
48
|
+
ATX_HEADER_START = /^\#{1,6}/
|
49
|
+
ATX_HEADER_MATCH = /^(\#{1,6})(.+?)\s*?#*#{HEADER_ID}\s*?\n/
|
50
|
+
|
51
|
+
# Parse the Atx header at the current location.
|
52
|
+
def parse_atx_header
|
53
|
+
return false if !after_block_boundary?
|
54
|
+
|
55
|
+
@src.scan(ATX_HEADER_MATCH)
|
56
|
+
level, text, id = @src[1], @src[2], @src[3]
|
57
|
+
text.strip!
|
58
|
+
el = new_block_el(:header, nil, nil, :level => level.length, :raw_text => text)
|
59
|
+
add_text(text, el)
|
60
|
+
el.attr['id'] = id if id
|
61
|
+
@tree.children << el
|
62
|
+
true
|
63
|
+
end
|
64
|
+
define_parser(:atx_header, ATX_HEADER_START)
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
module Kramdown
|
24
|
+
module Parser
|
25
|
+
class Kramdown
|
26
|
+
|
27
|
+
HR_START = /^#{OPT_SPACE}(\*|-|_)[ \t]*\1[ \t]*\1(\1|[ \t])*\n/
|
28
|
+
|
29
|
+
# Parse the horizontal rule at the current location.
|
30
|
+
def parse_horizontal_rule
|
31
|
+
@src.pos += @src.matched_size
|
32
|
+
@tree.children << new_block_el(:hr)
|
33
|
+
true
|
34
|
+
end
|
35
|
+
define_parser(:horizontal_rule, HR_START)
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'kramdown/parser/html'
|
24
|
+
|
25
|
+
module Kramdown
|
26
|
+
module Parser
|
27
|
+
class Kramdown
|
28
|
+
|
29
|
+
include Kramdown::Parser::Html::Parser
|
30
|
+
|
31
|
+
# Mapping of markdown attribute value to content model. I.e. :raw when "0", :default when "1"
|
32
|
+
# (use default content model for the HTML element), :span when "span", :block when block and
|
33
|
+
# for everything else +nil+ is returned.
|
34
|
+
HTML_MARKDOWN_ATTR_MAP = {"0" => :raw, "1" => :default, "span" => :span, "block" => :block}
|
35
|
+
|
36
|
+
TRAILING_WHITESPACE = /[ \t]*\n/
|
37
|
+
|
38
|
+
def handle_kramdown_html_tag(el, closed)
|
39
|
+
el.options[:ial] = @block_ial if @block_ial
|
40
|
+
|
41
|
+
content_model = if @tree.type != :html_element || @tree.options[:content_model] != :raw
|
42
|
+
(@options[:parse_block_html] ? HTML_CONTENT_MODEL[el.value] : :raw)
|
43
|
+
else
|
44
|
+
:raw
|
45
|
+
end
|
46
|
+
if val = HTML_MARKDOWN_ATTR_MAP[el.attr.delete('markdown')]
|
47
|
+
content_model = (val == :default ? HTML_CONTENT_MODEL[el.value] : val)
|
48
|
+
end
|
49
|
+
|
50
|
+
@src.scan(TRAILING_WHITESPACE) if content_model == :block
|
51
|
+
el.options[:content_model] = content_model
|
52
|
+
|
53
|
+
if !closed
|
54
|
+
if content_model == :block
|
55
|
+
if !parse_blocks(el)
|
56
|
+
warning("Found no end tag for '#{el.value}' - auto-closing it")
|
57
|
+
end
|
58
|
+
elsif content_model == :span
|
59
|
+
curpos = @src.pos
|
60
|
+
if @src.scan_until(/(?=<\/#{el.value}\s*>)/mi)
|
61
|
+
add_text(extract_string(curpos...@src.pos, @src), el)
|
62
|
+
@src.scan(HTML_TAG_CLOSE_RE)
|
63
|
+
else
|
64
|
+
add_text(@src.rest, el)
|
65
|
+
@src.terminate
|
66
|
+
warning("Found no end tag for '#{el.value}' - auto-closing it")
|
67
|
+
end
|
68
|
+
else
|
69
|
+
parse_raw_html(el, &method(:handle_kramdown_html_tag))
|
70
|
+
end
|
71
|
+
@src.scan(TRAILING_WHITESPACE) unless (@tree.type == :html_element && @tree.options[:content_model] == :raw)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
HTML_BLOCK_START = /^#{OPT_SPACE}<(#{REXML::Parsers::BaseParser::UNAME_STR}|\?|!--|\/)/
|
77
|
+
|
78
|
+
# Parse the HTML at the current position as block-level HTML.
|
79
|
+
def parse_block_html
|
80
|
+
if result = @src.scan(HTML_COMMENT_RE)
|
81
|
+
@tree.children << Element.new(:xml_comment, result, nil, :category => :block)
|
82
|
+
@src.scan(TRAILING_WHITESPACE)
|
83
|
+
true
|
84
|
+
elsif result = @src.scan(HTML_INSTRUCTION_RE)
|
85
|
+
@tree.children << Element.new(:xml_pi, result, nil, :category => :block)
|
86
|
+
@src.scan(TRAILING_WHITESPACE)
|
87
|
+
true
|
88
|
+
else
|
89
|
+
if result = @src.check(/^#{OPT_SPACE}#{HTML_TAG_RE}/) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase)
|
90
|
+
@src.pos += @src.matched_size
|
91
|
+
handle_html_start_tag(&method(:handle_kramdown_html_tag))
|
92
|
+
Kramdown::Parser::Html::ElementConverter.convert(@root, @tree.children.last) if @options[:html_to_native]
|
93
|
+
true
|
94
|
+
elsif result = @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/) && !HTML_SPAN_ELEMENTS.include?(@src[1].downcase)
|
95
|
+
name = @src[1].downcase
|
96
|
+
|
97
|
+
if @tree.type == :html_element && @tree.value == name
|
98
|
+
@src.pos += @src.matched_size
|
99
|
+
throw :stop_block_parsing, :found
|
100
|
+
else
|
101
|
+
false
|
102
|
+
end
|
103
|
+
else
|
104
|
+
false
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
define_parser(:block_html, HTML_BLOCK_START)
|
109
|
+
|
110
|
+
|
111
|
+
HTML_SPAN_START = /<(#{REXML::Parsers::BaseParser::UNAME_STR}|\?|!--|\/)/
|
112
|
+
|
113
|
+
# Parse the HTML at the current position as span-level HTML.
|
114
|
+
def parse_span_html
|
115
|
+
if result = @src.scan(HTML_COMMENT_RE)
|
116
|
+
@tree.children << Element.new(:xml_comment, result, nil, :category => :span)
|
117
|
+
elsif result = @src.scan(HTML_INSTRUCTION_RE)
|
118
|
+
@tree.children << Element.new(:xml_pi, result, nil, :category => :span)
|
119
|
+
elsif result = @src.scan(HTML_TAG_CLOSE_RE)
|
120
|
+
warning("Found invalidly used HTML closing tag for '#{@src[1]}'")
|
121
|
+
add_text(result)
|
122
|
+
elsif result = @src.scan(HTML_TAG_RE)
|
123
|
+
tag_name = @src[1].downcase
|
124
|
+
if HTML_BLOCK_ELEMENTS.include?(tag_name)
|
125
|
+
warning("Found block HTML tag '#{tag_name}' in span-level text")
|
126
|
+
add_text(result)
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
attrs = Utils::OrderedHash.new
|
131
|
+
@src[2].scan(HTML_ATTRIBUTE_RE).each {|name,sep,val| attrs[name.downcase] = (val || '').gsub(/\n+/, ' ')}
|
132
|
+
|
133
|
+
do_parsing = (HTML_CONTENT_MODEL[tag_name] == :raw || @tree.options[:content_model] == :raw ? false : @options[:parse_span_html])
|
134
|
+
if val = HTML_MARKDOWN_ATTR_MAP[attrs.delete('markdown')]
|
135
|
+
if val == :block
|
136
|
+
warning("Cannot use block-level parsing in span-level HTML tag - using default mode")
|
137
|
+
elsif val == :span
|
138
|
+
do_parsing = true
|
139
|
+
elsif val == :default
|
140
|
+
do_parsing = HTML_CONTENT_MODEL[tag_name] != :raw
|
141
|
+
elsif val == :raw
|
142
|
+
do_parsing = false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
el = Element.new(:html_element, tag_name, attrs, :category => :span, :content_model => (do_parsing ? :span : :raw))
|
147
|
+
@tree.children << el
|
148
|
+
stop_re = /<\/#{Regexp.escape(tag_name)}\s*>/i
|
149
|
+
if !@src[4] && HTML_ELEMENTS_WITHOUT_BODY.include?(el.value)
|
150
|
+
warning("The HTML tag '#{el.value}' cannot have any content - auto-closing it")
|
151
|
+
elsif !@src[4]
|
152
|
+
if parse_spans(el, stop_re, (do_parsing ? nil : [:span_html]))
|
153
|
+
@src.scan(stop_re)
|
154
|
+
else
|
155
|
+
warning("Found no end tag for '#{el.value}' - auto-closing it")
|
156
|
+
add_text(@src.rest, el)
|
157
|
+
@src.terminate
|
158
|
+
end
|
159
|
+
end
|
160
|
+
Kramdown::Parser::Html::ElementConverter.convert(@root, el) if @options[:html_to_native]
|
161
|
+
else
|
162
|
+
add_text(@src.getch)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
define_parser(:span_html, HTML_SPAN_START, '<')
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'kramdown/parser/html'
|
24
|
+
|
25
|
+
module Kramdown
|
26
|
+
module Parser
|
27
|
+
class Kramdown
|
28
|
+
|
29
|
+
# Parse the HTML entity at the current location.
|
30
|
+
def parse_html_entity
|
31
|
+
@src.pos += @src.matched_size
|
32
|
+
begin
|
33
|
+
@tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity(@src[1] || (@src[2] && @src[2].to_i) || @src[3].hex),
|
34
|
+
nil, :original => @src.matched)
|
35
|
+
rescue ::Kramdown::Error
|
36
|
+
@tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity('amp'))
|
37
|
+
add_text(@src.matched[1..-1])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&')
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2012 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown.
|
7
|
+
#
|
8
|
+
# kramdown is free software: you can redistribute it and/or modify
|
9
|
+
# it under the terms of the GNU General Public License as published by
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
11
|
+
# (at your option) any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
#++
|
21
|
+
#
|
22
|
+
|
23
|
+
#
|
24
|
+
# This file has been edited to suit the needs of The Beans Group Ltd. Changes were made to the types of media availbable
|
25
|
+
# images keep their ! however new types are ? for oembedd etc
|
26
|
+
# If you wish to change the types of media you need to change the IMAGE_START constant to include your special symbol
|
27
|
+
# for the new media object as well as change the reg ex on the parser definition towards the bottom of this file.
|
28
|
+
#
|
29
|
+
|
30
|
+
module Kramdown
|
31
|
+
module Parser
|
32
|
+
class Kramdown
|
33
|
+
|
34
|
+
# Normalize the link identifier.
|
35
|
+
def normalize_link_id(id)
|
36
|
+
id.gsub(/(\s|\n)+/, ' ').downcase
|
37
|
+
end
|
38
|
+
|
39
|
+
IMAGE_DEFINITION_START = /^#{OPT_SPACE}\[([^\n\]]+)\]:[ \t]*(?:<(.*?)>|([^'"\n]*?\S[^'"\n]*?))[ \t]*?(?:\n?[ \t]*?(["'])(.+?)\4[ \t]*?)?\n/
|
40
|
+
|
41
|
+
# Parse the link definition at the current location.
|
42
|
+
def parse_image_definition
|
43
|
+
@src.pos += @src.matched_size
|
44
|
+
link_id, link_url, link_title = normalize_link_id(@src[1]), @src[2] || @src[3], @src[5]
|
45
|
+
warning("Duplicate link ID '#{link_id}' - overwriting") if @link_defs[link_id]
|
46
|
+
@link_defs[link_id] = [link_url, link_title]
|
47
|
+
@tree.children << Element.new(:eob, :link_def)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
define_parser(:image_definition, IMAGE_DEFINITION_START)
|
51
|
+
|
52
|
+
|
53
|
+
# This helper methods adds the approriate attributes to the element +el+ of type +a+ or +img+
|
54
|
+
# and the element itself to the @tree.
|
55
|
+
def add_link(el, href, title, alt_text = nil)
|
56
|
+
# figure
|
57
|
+
fig = Element.new :figure
|
58
|
+
fig.attr['role'] = "img"
|
59
|
+
el.attr['src'] = href
|
60
|
+
el.attr['alt'] = alt_text
|
61
|
+
el.children.clear
|
62
|
+
fig.children << el
|
63
|
+
if title
|
64
|
+
# unique figure id
|
65
|
+
fig_id = rand(1000)
|
66
|
+
fig.attr['aria-labelledby'] = fig_id
|
67
|
+
el.attr['title'] = title
|
68
|
+
fig_cap = Element.new(:figCaption, title)
|
69
|
+
fig_cap.attr['id'] = fig_id
|
70
|
+
fig.children << fig_cap
|
71
|
+
end
|
72
|
+
@tree.children << fig
|
73
|
+
end
|
74
|
+
|
75
|
+
IMAGE_BRACKET_STOP_RE = /(\])|!?\[/
|
76
|
+
IMAGE_PAREN_STOP_RE = /(\()|(\))|\s(?=['"])/
|
77
|
+
IMAGE_INLINE_ID_RE = /\s*?\[([^\]]+)?\]/
|
78
|
+
IMAGE_INLINE_TITLE_RE = /\s*?(["'])(.+?)\1\s*?\)/
|
79
|
+
IMAGE_START = /!\[(?=[^^])/
|
80
|
+
|
81
|
+
# Parse the link at the current scanner position. This method is used to parse normal links as
|
82
|
+
# well as image links.
|
83
|
+
def parse_image
|
84
|
+
result = @src.scan(IMAGE_START)
|
85
|
+
reset_pos = @src.pos
|
86
|
+
link_type = :img
|
87
|
+
|
88
|
+
el = Element.new(link_type)
|
89
|
+
|
90
|
+
count = 1
|
91
|
+
found = parse_spans(el, IMAGE_BRACKET_STOP_RE) do
|
92
|
+
count = count + (@src[1] ? -1 : 1)
|
93
|
+
count - el.children.select {|c| c.type == :img}.size == 0
|
94
|
+
end
|
95
|
+
if !found
|
96
|
+
@src.pos = reset_pos
|
97
|
+
add_text(result)
|
98
|
+
return
|
99
|
+
end
|
100
|
+
alt_text = extract_string(reset_pos...@src.pos, @src)
|
101
|
+
@src.scan(IMAGE_BRACKET_STOP_RE)
|
102
|
+
|
103
|
+
# reference style link or no link url
|
104
|
+
if @src.scan(IMAGE_INLINE_ID_RE) || !@src.check(/\(/)
|
105
|
+
link_id = normalize_link_id(@src[1] || alt_text)
|
106
|
+
if @link_defs.has_key?(link_id)
|
107
|
+
add_link(el, @link_defs[link_id].first, @link_defs[link_id].last, alt_text)
|
108
|
+
else
|
109
|
+
warning("No link definition for link ID '#{link_id}' found")
|
110
|
+
@src.pos = reset_pos
|
111
|
+
add_text(result)
|
112
|
+
end
|
113
|
+
return
|
114
|
+
end
|
115
|
+
|
116
|
+
# link url in parentheses
|
117
|
+
if @src.scan(/\(<(.*?)>/)
|
118
|
+
link_url = @src[1]
|
119
|
+
if @src.scan(/\)/)
|
120
|
+
add_link(el, link_url, nil, alt_text)
|
121
|
+
return
|
122
|
+
end
|
123
|
+
else
|
124
|
+
link_url = ''
|
125
|
+
nr_of_brackets = 0
|
126
|
+
while temp = @src.scan_until(IMAGE_PAREN_STOP_RE)
|
127
|
+
link_url << temp
|
128
|
+
if @src[2]
|
129
|
+
nr_of_brackets -= 1
|
130
|
+
break if nr_of_brackets == 0
|
131
|
+
elsif @src[1]
|
132
|
+
nr_of_brackets += 1
|
133
|
+
else
|
134
|
+
break
|
135
|
+
end
|
136
|
+
end
|
137
|
+
link_url = link_url[1..-2]
|
138
|
+
link_url.strip!
|
139
|
+
|
140
|
+
if nr_of_brackets == 0
|
141
|
+
add_link(el, link_url, nil, alt_text)
|
142
|
+
return
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
if @src.scan(IMAGE_INLINE_TITLE_RE)
|
147
|
+
add_link(el, link_url, @src[2], alt_text)
|
148
|
+
else
|
149
|
+
@src.pos = reset_pos
|
150
|
+
add_text(result)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
define_parser(:image, IMAGE_START, '!\[')
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|