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.
Files changed (60) hide show
  1. data/AUTHORS +1 -0
  2. data/CONTRIBUTERS +11 -0
  3. data/COPYING +24 -0
  4. data/ChangeLog +6683 -0
  5. data/GPL +674 -0
  6. data/README +43 -0
  7. data/VERSION +1 -0
  8. data/bin/kramdown +78 -0
  9. data/lib/kramdown.rb +23 -0
  10. data/lib/kramdown/compatibility.rb +49 -0
  11. data/lib/kramdown/converter.rb +41 -0
  12. data/lib/kramdown/converter/base.rb +169 -0
  13. data/lib/kramdown/converter/bean_html.rb +71 -0
  14. data/lib/kramdown/converter/html.rb +411 -0
  15. data/lib/kramdown/converter/kramdown.rb +428 -0
  16. data/lib/kramdown/converter/latex.rb +607 -0
  17. data/lib/kramdown/converter/toc.rb +82 -0
  18. data/lib/kramdown/document.rb +119 -0
  19. data/lib/kramdown/element.rb +524 -0
  20. data/lib/kramdown/error.rb +30 -0
  21. data/lib/kramdown/options.rb +373 -0
  22. data/lib/kramdown/parser.rb +39 -0
  23. data/lib/kramdown/parser/base.rb +136 -0
  24. data/lib/kramdown/parser/bean_kramdown.rb +25 -0
  25. data/lib/kramdown/parser/bean_kramdown/info_box.rb +52 -0
  26. data/lib/kramdown/parser/bean_kramdown/oembed.rb +230 -0
  27. data/lib/kramdown/parser/html.rb +570 -0
  28. data/lib/kramdown/parser/kramdown.rb +339 -0
  29. data/lib/kramdown/parser/kramdown/abbreviation.rb +71 -0
  30. data/lib/kramdown/parser/kramdown/autolink.rb +53 -0
  31. data/lib/kramdown/parser/kramdown/blank_line.rb +43 -0
  32. data/lib/kramdown/parser/kramdown/block_boundary.rb +46 -0
  33. data/lib/kramdown/parser/kramdown/blockquote.rb +51 -0
  34. data/lib/kramdown/parser/kramdown/codeblock.rb +63 -0
  35. data/lib/kramdown/parser/kramdown/codespan.rb +56 -0
  36. data/lib/kramdown/parser/kramdown/emphasis.rb +70 -0
  37. data/lib/kramdown/parser/kramdown/eob.rb +39 -0
  38. data/lib/kramdown/parser/kramdown/escaped_chars.rb +38 -0
  39. data/lib/kramdown/parser/kramdown/extensions.rb +204 -0
  40. data/lib/kramdown/parser/kramdown/footnote.rb +74 -0
  41. data/lib/kramdown/parser/kramdown/header.rb +68 -0
  42. data/lib/kramdown/parser/kramdown/horizontal_rule.rb +39 -0
  43. data/lib/kramdown/parser/kramdown/html.rb +169 -0
  44. data/lib/kramdown/parser/kramdown/html_entity.rb +44 -0
  45. data/lib/kramdown/parser/kramdown/image.rb +157 -0
  46. data/lib/kramdown/parser/kramdown/line_break.rb +38 -0
  47. data/lib/kramdown/parser/kramdown/link.rb +154 -0
  48. data/lib/kramdown/parser/kramdown/list.rb +240 -0
  49. data/lib/kramdown/parser/kramdown/math.rb +65 -0
  50. data/lib/kramdown/parser/kramdown/paragraph.rb +63 -0
  51. data/lib/kramdown/parser/kramdown/smart_quotes.rb +214 -0
  52. data/lib/kramdown/parser/kramdown/table.rb +178 -0
  53. data/lib/kramdown/parser/kramdown/typographic_symbol.rb +52 -0
  54. data/lib/kramdown/parser/markdown.rb +69 -0
  55. data/lib/kramdown/utils.rb +42 -0
  56. data/lib/kramdown/utils/entities.rb +348 -0
  57. data/lib/kramdown/utils/html.rb +85 -0
  58. data/lib/kramdown/utils/ordered_hash.rb +100 -0
  59. data/lib/kramdown/version.rb +28 -0
  60. 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