gollum-lib 5.0.a.4-java → 5.0.1-java
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 +4 -4
- data/Gemfile +2 -1
- data/README.md +12 -7
- data/Rakefile +7 -7
- data/adapter_dependencies.rb +7 -0
- data/gemspec.rb +18 -10
- data/gollum-lib.gemspec +2 -6
- data/gollum-lib_java.gemspec +2 -2
- data/lib/gollum-lib.rb +9 -9
- data/lib/gollum-lib/blob_entry.rb +2 -8
- data/lib/gollum-lib/committer.rb +22 -60
- data/lib/gollum-lib/file.rb +105 -82
- data/lib/gollum-lib/file_view.rb +8 -4
- data/lib/gollum-lib/filter.rb +12 -0
- data/lib/gollum-lib/filter/code.rb +9 -13
- data/lib/gollum-lib/filter/critic_markup.rb +97 -0
- data/lib/gollum-lib/filter/emoji.rb +10 -8
- data/lib/gollum-lib/filter/macro.rb +5 -2
- data/lib/gollum-lib/filter/plantuml.rb +1 -1
- data/lib/gollum-lib/filter/remote_code.rb +3 -2
- data/lib/gollum-lib/filter/render.rb +25 -2
- data/lib/gollum-lib/filter/sanitize.rb +1 -8
- data/lib/gollum-lib/filter/tags.rb +57 -47
- data/lib/gollum-lib/filter/toc.rb +17 -21
- data/lib/gollum-lib/filter/yaml.rb +1 -1
- data/lib/gollum-lib/git_access.rb +0 -25
- data/lib/gollum-lib/helpers.rb +13 -3
- data/lib/gollum-lib/macro/audio.rb +9 -0
- data/lib/gollum-lib/macro/global_toc.rb +2 -1
- data/lib/gollum-lib/macro/navigation.rb +8 -6
- data/lib/gollum-lib/macro/note.rb +19 -0
- data/lib/gollum-lib/macro/octicon.rb +12 -0
- data/lib/gollum-lib/macro/warn.rb +11 -0
- data/lib/gollum-lib/markup.rb +17 -32
- data/lib/gollum-lib/markups.rb +11 -7
- data/lib/gollum-lib/page.rb +79 -165
- data/lib/gollum-lib/pagination.rb +7 -6
- data/lib/gollum-lib/redirects.rb +38 -0
- data/lib/gollum-lib/sanitization.rb +32 -357
- data/lib/gollum-lib/version.rb +1 -1
- data/lib/gollum-lib/wiki.rb +216 -404
- metadata +125 -79
- data/ROADMAP +0 -6
data/lib/gollum-lib/file_view.rb
CHANGED
@@ -10,12 +10,13 @@ module Gollum
|
|
10
10
|
# set pages to wiki.pages + wiki.files and show_all to true
|
11
11
|
def initialize(pages, options = {})
|
12
12
|
@pages = pages
|
13
|
+
@wiki = @pages.first ? @pages.first.wiki : nil
|
13
14
|
@show_all = options[:show_all] || false
|
14
15
|
@checked = options[:collapse_tree] ? '' : "checked"
|
15
16
|
end
|
16
17
|
|
17
18
|
def enclose_tree(string)
|
18
|
-
%Q(<ol class="tree">\n) + string + %Q(</ol>)
|
19
|
+
sanitize_html(%Q(<ol class="tree">\n) + string + %Q(</ol>))
|
19
20
|
end
|
20
21
|
|
21
22
|
def new_page(page)
|
@@ -96,7 +97,7 @@ module Gollum
|
|
96
97
|
</li>
|
97
98
|
HTML
|
98
99
|
|
99
|
-
return enclose_tree
|
100
|
+
return enclose_tree(html)
|
100
101
|
end
|
101
102
|
|
102
103
|
sorted_folders = []
|
@@ -153,8 +154,11 @@ module Gollum
|
|
153
154
|
changed = false
|
154
155
|
end
|
155
156
|
|
156
|
-
|
157
|
-
enclose_tree html
|
157
|
+
enclose_tree(html)
|
158
158
|
end # end render_files
|
159
|
+
|
160
|
+
def sanitize_html(data)
|
161
|
+
@wiki ? @wiki.sanitizer.clean(data) : data
|
162
|
+
end
|
159
163
|
end # end FileView class
|
160
164
|
end # end Gollum module
|
data/lib/gollum-lib/filter.rb
CHANGED
@@ -47,14 +47,21 @@ module Gollum
|
|
47
47
|
class Filter
|
48
48
|
include Gollum::Helpers
|
49
49
|
|
50
|
+
PLACEHOLDER_PATTERN = /%(\S+)%.+=\1=/
|
51
|
+
|
50
52
|
# Setup the object. Sets `@markup` to be the instance of Gollum::Markup that
|
51
53
|
# is running this filter chain, and sets `@map` to be an empty hash (for use
|
52
54
|
# in your extract/process operations).
|
55
|
+
|
53
56
|
def initialize(markup)
|
54
57
|
@markup = markup
|
55
58
|
@map = {}
|
59
|
+
@open_pattern = "%#{self.class.to_s.split('::').last}%"
|
60
|
+
@close_pattern = "=#{self.class.to_s.split('::').last}="
|
56
61
|
end
|
57
62
|
|
63
|
+
attr_reader :open_pattern, :close_pattern
|
64
|
+
|
58
65
|
def extract(data)
|
59
66
|
raise RuntimeError,
|
60
67
|
"#{self.class} has not implemented ##extract!"
|
@@ -66,6 +73,11 @@ module Gollum
|
|
66
73
|
end
|
67
74
|
|
68
75
|
protected
|
76
|
+
|
77
|
+
def sanitize(data)
|
78
|
+
@markup.wiki.sanitizer.clean(data, @markup.historical)
|
79
|
+
end
|
80
|
+
|
69
81
|
# Render a (presumably) non-fatal error as HTML
|
70
82
|
#
|
71
83
|
def html_error(message)
|
@@ -14,31 +14,27 @@ class Gollum::Filter::Code < Gollum::Filter
|
|
14
14
|
org_headers = %r{([ \t]*#\+HEADER[S]?:[^\r\n]*\n)*}
|
15
15
|
org_name = %r{([ \t]*#\+NAME:[^\r\n]*\n)?}
|
16
16
|
org_lang = %r{[ ]*([^\n \r]*)[ ]*[^\r\n]*}
|
17
|
-
org_begin = %r{[ \t]
|
18
|
-
org_end = %r{\n[ \t]*#\+END_SRC[ \t]*}
|
17
|
+
org_begin = %r{([ \t]*)#\+BEGIN_SRC#{org_lang}\r?\n}
|
18
|
+
org_end = %r{\r?\n[ \t]*#\+END_SRC[ \t\r]*}
|
19
19
|
data.gsub!(/^#{org_headers}#{org_name}#{org_begin}(.+?)#{org_end}$/mi) do
|
20
|
-
cache_codeblock(Regexp.last_match[
|
20
|
+
"#{Regexp.last_match[3]}#{cache_codeblock(Regexp.last_match[4], Regexp.last_match[5])}"
|
21
21
|
end
|
22
22
|
when :markdown
|
23
|
-
data.gsub!(/^([
|
23
|
+
data.gsub!(/^([ ]{0,3})(~~~+) ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}(~~~+)[ \t\r]*$/m) do
|
24
24
|
m_indent = Regexp.last_match[1]
|
25
25
|
m_start = Regexp.last_match[2] # ~~~
|
26
26
|
m_lang = Regexp.last_match[3]
|
27
27
|
m_code = Regexp.last_match[4]
|
28
28
|
m_end = Regexp.last_match[5] # ~~~
|
29
|
-
#
|
30
|
-
next '' if
|
31
|
-
lang = m_lang ? m_lang.strip : nil
|
32
|
-
if lang
|
33
|
-
lang = lang.match(/\.([^}\s]+)/)
|
34
|
-
lang = lang[1] unless lang.nil?
|
35
|
-
end
|
29
|
+
# The closing code fence must be at least as long as the opening fence
|
30
|
+
next '' if m_end.length < m_start.length
|
31
|
+
lang = m_lang ? m_lang.strip.split.first : nil
|
36
32
|
"#{m_indent}#{cache_codeblock(lang, m_code, m_indent)}"
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
36
|
|
41
|
-
data.gsub!(/^([
|
37
|
+
data.gsub!(/^([ ]{0,3})``` ?([^\r\n]+)?\r?\n(.+?)\r?\n[ ]{0,3}```[ \t]*\r?$/m) do
|
42
38
|
"#{Regexp.last_match[1]}#{cache_codeblock(Regexp.last_match[2].to_s.strip, Regexp.last_match[3], Regexp.last_match[1])}" # print the SHA1 ID with the proper indentation
|
43
39
|
end
|
44
40
|
data
|
@@ -133,7 +129,7 @@ class Gollum::Filter::Code < Gollum::Filter
|
|
133
129
|
|
134
130
|
def cache_codeblock(language, code, indent = "")
|
135
131
|
language = language.to_s.empty? ? nil : language
|
136
|
-
id = Digest::SHA1.hexdigest("#{language}.#{code}")
|
132
|
+
id = "#{open_pattern}#{Digest::SHA1.hexdigest("#{language}.#{code}")}#{close_pattern}"
|
137
133
|
cached = @markup.check_cache(:code, id)
|
138
134
|
@map[id] = cached ?
|
139
135
|
{ :output => cached } :
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
|
3
|
+
# CriticMarkup
|
4
|
+
#
|
5
|
+
# Render CriticMarkup
|
6
|
+
|
7
|
+
class Gollum::Filter::CriticMarkup < Gollum::Filter
|
8
|
+
|
9
|
+
# Patterns inspired by https://github.com/DivineDominion/criticmarkup.tmbundle/blob/master/Syntaxes/criticmarkup.tmLanguage
|
10
|
+
# All patterns use multiline matching (m flag)
|
11
|
+
# Logic inspired by https://github.com/CriticMarkup/CriticMarkup-toolkit/blob/master/CLI/criticParser_CLI.py
|
12
|
+
|
13
|
+
ADDITION_PATTERN = %r|{\+\+(?<content>.*?)\+\+[ \t]*(\[(.*?)\])?[ \t]*\}|m
|
14
|
+
DELETION_PATTERN = %r|{--(?<content>.*?)--[ \t]*(\[(.*?)\])?[ \t]*\}|m
|
15
|
+
SUBSTITUTION_PATTERN = %r|{~~(?<oldcontent>.*?)~>(?<newcontent>.*?)~~}|m
|
16
|
+
HIGHLIGHT_PATTERN = %r|{\=\=(?<content>.*?)[ \t]*(\[(.*?)\])?[ \t]*\=\=\}{>>(?<comment>.*?)<<}|m
|
17
|
+
COMMENT_PATTERN = %r|{>>(?<content>.*?)<<}|m
|
18
|
+
|
19
|
+
def extract(data)
|
20
|
+
data.gsub! ADDITION_PATTERN do
|
21
|
+
content = $~[:content]
|
22
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
23
|
+
# Is there a new paragraph followed by new text
|
24
|
+
if content.start_with?("\n\n") && content != "\n\n"
|
25
|
+
html = "\n\n<ins class='critic break'> </ins>\n\n<ins>#{content.gsub('\n', ' ')}</ins>"
|
26
|
+
# Is the addition just a single new paragraph
|
27
|
+
elsif content == "\n\n"
|
28
|
+
html = "\n\n<ins class='critic break'> </ins>\n\n"
|
29
|
+
# Is it added text followed by a new paragraph?
|
30
|
+
elsif content.end_with?("\n\n") && content != "\n\n"
|
31
|
+
html = "<ins>#{content.gsub('\n', ' ')}</ins>\n\n<ins class='critic break'> </ins>\n\n"
|
32
|
+
else
|
33
|
+
html = "<ins>#{content.gsub('\n', ' ')}</ins>"
|
34
|
+
end
|
35
|
+
@map[placeholder] = html
|
36
|
+
placeholder
|
37
|
+
end
|
38
|
+
|
39
|
+
data.gsub! DELETION_PATTERN do
|
40
|
+
content = $~[:content]
|
41
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
42
|
+
if content == "\n\n"
|
43
|
+
html = "<del> </del>"
|
44
|
+
else
|
45
|
+
html = "<del>#{content.gsub('\n\n', ' ')}</del>"
|
46
|
+
end
|
47
|
+
@map[placeholder] = html
|
48
|
+
placeholder
|
49
|
+
end
|
50
|
+
|
51
|
+
data.gsub! SUBSTITUTION_PATTERN do
|
52
|
+
oldcontent = $~[:oldcontent]
|
53
|
+
newcontent = $~[:newcontent]
|
54
|
+
placeholder = generate_placeholder("#{oldcontent}#{newcontent}#{@map.size}")
|
55
|
+
html = "<del>#{oldcontent}</del><ins>#{newcontent}</ins>"
|
56
|
+
@map[placeholder] = html
|
57
|
+
placeholder
|
58
|
+
end
|
59
|
+
|
60
|
+
data.gsub! HIGHLIGHT_PATTERN do
|
61
|
+
content = $~[:content]
|
62
|
+
comment = $~[:comment]
|
63
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
64
|
+
html = "<mark>#{content}</mark><span class='critic comment'>#{comment}</span>"
|
65
|
+
@map[placeholder] = html
|
66
|
+
placeholder
|
67
|
+
end
|
68
|
+
|
69
|
+
data.gsub! COMMENT_PATTERN do
|
70
|
+
content = $~[:content]
|
71
|
+
placeholder = generate_placeholder("#{content}#{@map.size}")
|
72
|
+
html = "<span class='critic comment'>#{content}</span>"
|
73
|
+
@map[placeholder] = html
|
74
|
+
placeholder
|
75
|
+
end
|
76
|
+
|
77
|
+
data
|
78
|
+
end
|
79
|
+
|
80
|
+
def process(data)
|
81
|
+
data.gsub! process_pattern do
|
82
|
+
@map[$~[:placeholder]]
|
83
|
+
end
|
84
|
+
data
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def process_pattern
|
90
|
+
/(?<placeholder>#{open_pattern}\h{40}#{close_pattern})/
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_placeholder(content)
|
94
|
+
"#{open_pattern}#{Digest::SHA1.hexdigest(content)}#{close_pattern}"
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -14,17 +14,11 @@ class Gollum::Filter::Emoji < Gollum::Filter
|
|
14
14
|
(?!\]{^2})
|
15
15
|
}ix
|
16
16
|
|
17
|
-
PROCESS_PATTERN = %r{
|
18
|
-
=EEMMOOJJII=
|
19
|
-
(?<name>[\w-]+)
|
20
|
-
=IIJJOOMMEE=
|
21
|
-
}ix
|
22
|
-
|
23
17
|
def extract(data)
|
24
18
|
data.gsub! EXTRACT_PATTERN do
|
25
19
|
case
|
26
20
|
when $~[:escape] then $&[1..-1]
|
27
|
-
when emoji_exists?($~[:name]) then "
|
21
|
+
when emoji_exists?($~[:name]) then "#{open_pattern}#{$~[:name]}#{close_pattern}"
|
28
22
|
else $&
|
29
23
|
end
|
30
24
|
end
|
@@ -32,12 +26,20 @@ class Gollum::Filter::Emoji < Gollum::Filter
|
|
32
26
|
end
|
33
27
|
|
34
28
|
def process(data)
|
35
|
-
data.gsub!
|
29
|
+
data.gsub! process_pattern, %q(<img src="/gollum/emoji/\k<name>" alt="\k<name>" class="emoji">)
|
36
30
|
data
|
37
31
|
end
|
38
32
|
|
39
33
|
private
|
40
34
|
|
35
|
+
def process_pattern
|
36
|
+
%r{
|
37
|
+
#{open_pattern}
|
38
|
+
(?<name>[\w-]+)
|
39
|
+
#{close_pattern}
|
40
|
+
}ix
|
41
|
+
end
|
42
|
+
|
41
43
|
def emoji_exists?(name)
|
42
44
|
@index ||= Gemojione::Index.new
|
43
45
|
!!@index.find_by_name(name)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# ~*~ encoding: utf-8 ~*~
|
2
|
+
require 'octicons'
|
2
3
|
|
3
4
|
# Replace specified tokens with dynamically generated content.
|
4
5
|
class Gollum::Filter::Macro < Gollum::Filter
|
@@ -12,7 +13,7 @@ class Gollum::Filter::Macro < Gollum::Filter
|
|
12
13
|
|
13
14
|
data.gsub(/('?)\<\<\s*([A-Z][A-Za-z0-9]*)\s*\(#{arg_list}\)\s*\>\>/) do
|
14
15
|
next CGI.escape_html($&[1..-1]) unless Regexp.last_match[1].empty?
|
15
|
-
id = Digest::SHA1.hexdigest(Regexp.last_match[2] + Regexp.last_match[3])
|
16
|
+
id = "#{open_pattern}#{Digest::SHA1.hexdigest(Regexp.last_match[2] + Regexp.last_match[3])}#{close_pattern}"
|
16
17
|
macro = Regexp.last_match[2]
|
17
18
|
argstr = Regexp.last_match[3]
|
18
19
|
args = []
|
@@ -47,7 +48,9 @@ class Gollum::Filter::Macro < Gollum::Filter
|
|
47
48
|
begin
|
48
49
|
Gollum::Macro.instance(macro, @markup.wiki, @markup.page).render(*args)
|
49
50
|
rescue StandardError => e
|
50
|
-
|
51
|
+
icon = Octicons::Octicon.new('zap', {width: 24, height: 24})
|
52
|
+
icon.options[:class] << ' mr-2'
|
53
|
+
"<div class='flash flash-error'>#{icon.to_svg}Macro Error for #{macro}: #{e.message}</div>"
|
51
54
|
end
|
52
55
|
end
|
53
56
|
end
|
@@ -70,7 +70,7 @@ class Gollum::Filter::PlantUML < Gollum::Filter
|
|
70
70
|
# placeholders.
|
71
71
|
def extract(data)
|
72
72
|
data.gsub(/(@startuml\r?\n.+?\r?\n@enduml\r?$)/m) do
|
73
|
-
id = Digest::SHA1.hexdigest($1)
|
73
|
+
id = "#{open_pattern}#{Digest::SHA1.hexdigest($1)}#{close_pattern}"
|
74
74
|
@map[id] = { :code => $1 }
|
75
75
|
id
|
76
76
|
end
|
@@ -20,7 +20,7 @@ class Gollum::Filter::RemoteCode < Gollum::Filter
|
|
20
20
|
|
21
21
|
# Detect local file
|
22
22
|
if protocol.nil?
|
23
|
-
if (file = @markup.
|
23
|
+
if (file = @markup.wiki.file(uri, @markup.wiki.ref))
|
24
24
|
contents = file.raw_data
|
25
25
|
else
|
26
26
|
# How do we communicate a render error?
|
@@ -45,7 +45,8 @@ class Gollum::Filter::RemoteCode < Gollum::Filter
|
|
45
45
|
return "Too many redirects or retries" if cut >= 10
|
46
46
|
http = Net::HTTP.new uri.host, uri.port
|
47
47
|
http.use_ssl = true
|
48
|
-
|
48
|
+
path = uri.path.empty? ? '/' : uri.path
|
49
|
+
resp = http.get path, {
|
49
50
|
'Accept' => 'text/plain',
|
50
51
|
'Cache-Control' => 'no-cache',
|
51
52
|
'Connection' => 'keep-alive',
|
@@ -3,7 +3,11 @@
|
|
3
3
|
class Gollum::Filter::Render < Gollum::Filter
|
4
4
|
def extract(data)
|
5
5
|
begin
|
6
|
-
|
6
|
+
working_dir = Pathname.new(@markup.wiki.path).join(@markup.dir)
|
7
|
+
working_dir = working_dir.exist? ? working_dir.to_s : '.'
|
8
|
+
Dir.chdir(working_dir) do
|
9
|
+
data = GitHub::Markup.render_s(@markup.format, data)
|
10
|
+
end
|
7
11
|
if data.nil?
|
8
12
|
raise "There was an error converting #{@markup.name} to HTML."
|
9
13
|
end
|
@@ -15,6 +19,25 @@ class Gollum::Filter::Render < Gollum::Filter
|
|
15
19
|
end
|
16
20
|
|
17
21
|
def process(data)
|
22
|
+
data = add_editable_header_class(data)
|
18
23
|
data
|
19
24
|
end
|
20
|
-
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def add_editable_header_class(data)
|
29
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
30
|
+
doc.css('h1,h2,h3,h4,h5,h6').each_with_index do |header, i|
|
31
|
+
next if header.content.empty?
|
32
|
+
next if header.inner_html.match(PLACEHOLDER_PATTERN)
|
33
|
+
klass = header['class']
|
34
|
+
if klass
|
35
|
+
header['class'] = klass << ' editable'
|
36
|
+
else
|
37
|
+
header['class'] = 'editable'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
doc.to_xml(@markup.class.to_xml_opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -6,13 +6,6 @@ class Gollum::Filter::Sanitize < Gollum::Filter
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def process(data)
|
9
|
-
|
10
|
-
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
11
|
-
doc = @markup.sanitize.clean_node!(doc)
|
12
|
-
|
13
|
-
doc.to_xml(@markup.to_xml_opts).gsub(/<p><\/p>/, '')
|
14
|
-
else
|
15
|
-
data
|
16
|
-
end
|
9
|
+
sanitize(data)
|
17
10
|
end
|
18
11
|
end
|
@@ -34,7 +34,7 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
34
34
|
doc.traverse do |node|
|
35
35
|
if node.text? then
|
36
36
|
content = node.content
|
37
|
-
content.gsub!(
|
37
|
+
content.gsub!(%r{#{open_pattern}[a-f0-9]+#{close_pattern}}) do |id|
|
38
38
|
if (tag = @map[id]) then
|
39
39
|
if is_preformatted?(node) then
|
40
40
|
"[[#{tag}]]"
|
@@ -56,7 +56,7 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
56
56
|
INCLUDE_TAG = 'include:'
|
57
57
|
|
58
58
|
def register_tag(tag)
|
59
|
-
id = "
|
59
|
+
id = "#{open_pattern}#{Digest::SHA1.hexdigest(tag)}#{close_pattern}"
|
60
60
|
@map[id] = tag
|
61
61
|
id
|
62
62
|
end
|
@@ -77,7 +77,6 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
77
77
|
return generate_link('', nil, nil, :page_absent) if link_part.nil?
|
78
78
|
img_args = extra ? [extra, link_part] : [link_part]
|
79
79
|
mime = MIME::Types.type_for(::File.extname(img_args.first.to_s)).first
|
80
|
-
|
81
80
|
result = if tag =~ /^_TOC_/
|
82
81
|
%{[[#{tag}]]}
|
83
82
|
elsif link_part =~ /^_$/
|
@@ -122,9 +121,9 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
122
121
|
len = INCLUDE_TAG.length
|
123
122
|
return html_error('Cannot process include directive: no page name given') if tag.length <= len
|
124
123
|
page_name = tag[len..-1]
|
125
|
-
resolved_page_name = ::File.
|
124
|
+
resolved_page_name = ::File.join(@markup.dir, page_name)
|
126
125
|
if @markup.include_levels > 0
|
127
|
-
page =
|
126
|
+
page = find_page_or_file_from_path(resolved_page_name)
|
128
127
|
if page
|
129
128
|
page.formatted_data(@markup.encoding, @markup.include_levels-1)
|
130
129
|
else
|
@@ -146,8 +145,8 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
146
145
|
opts = parse_image_tag_options(options)
|
147
146
|
if path =~ /^https?:\/\/.+$/i
|
148
147
|
generate_image(path, opts)
|
149
|
-
elsif file =
|
150
|
-
generate_image(generate_href_for_path(file.
|
148
|
+
elsif file = find_page_or_file_from_path(path, :file)
|
149
|
+
generate_image(generate_href_for_path(file.url_path), opts)
|
151
150
|
else
|
152
151
|
generate_image('', opts)
|
153
152
|
end
|
@@ -173,14 +172,8 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
173
172
|
# Return the String HTML if the tag is a valid external link tag or
|
174
173
|
# nil if it is not.
|
175
174
|
def process_external_link_tag(url, pretty_name = nil)
|
176
|
-
|
177
|
-
if
|
178
|
-
accepted_protocols.select!{|protocol| protocol != :relative}
|
179
|
-
regexp = %r{^((#{accepted_protocols.join("|")}):)?(//)}
|
180
|
-
else
|
181
|
-
regexp = %r{^((#{accepted_protocols.join("|")}):)}
|
182
|
-
end
|
183
|
-
if url =~ regexp
|
175
|
+
@accepted_protocols_regex ||= %r{^((#{::Gollum::Sanitization.accepted_protocols.join('|')}):)?(//)}
|
176
|
+
if url =~ @accepted_protocols_regex
|
184
177
|
generate_link(url, pretty_name, nil, :external)
|
185
178
|
else
|
186
179
|
nil
|
@@ -195,8 +188,9 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
195
188
|
# Returns the String HTML if the tag is a valid file link tag or nil
|
196
189
|
# if it is not.
|
197
190
|
def process_file_link_tag(link_part, pretty_name)
|
198
|
-
|
199
|
-
|
191
|
+
return nil if ::Gollum::Page.valid_extension?(link_part)
|
192
|
+
if file = find_page_or_file_from_path(link_part, :file)
|
193
|
+
generate_link(file.url_path, pretty_name, nil, :file)
|
200
194
|
else
|
201
195
|
nil
|
202
196
|
end
|
@@ -212,18 +206,31 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
212
206
|
def process_page_link_tag(link_part, pretty_name = nil)
|
213
207
|
presence = :page_absent
|
214
208
|
link = link_part
|
215
|
-
page =
|
209
|
+
page = find_page_or_file_from_path(link)
|
216
210
|
|
217
211
|
# If no match yet, try finding page with anchor removed
|
218
|
-
if
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
212
|
+
if page.nil?
|
213
|
+
if pos = link.rindex('#')
|
214
|
+
extra = link[pos..-1]
|
215
|
+
link = link[0...pos]
|
216
|
+
else
|
217
|
+
extra = nil
|
218
|
+
end
|
219
|
+
|
220
|
+
if link.empty? && extra # Internal anchor link, don't search for the page but return immediately
|
221
|
+
return generate_link(nil, pretty_name, extra, :internal_anchor)
|
222
|
+
end
|
224
223
|
|
225
|
-
|
226
|
-
|
224
|
+
page = find_page_or_file_from_path(link)
|
225
|
+
end
|
226
|
+
presence = :page_present if page
|
227
|
+
|
228
|
+
if pretty_name
|
229
|
+
name = pretty_name
|
230
|
+
else
|
231
|
+
name = page ? path_to_link_text(link) : link
|
232
|
+
end
|
233
|
+
link = page ? page.escaped_url_path : ERB::Util.url_encode(link).force_encoding('utf-8')
|
227
234
|
generate_link(link, name, extra, presence)
|
228
235
|
end
|
229
236
|
|
@@ -232,15 +239,15 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
232
239
|
# path - The String path to search for.
|
233
240
|
#
|
234
241
|
# Returns a Gollum::Page instance if a page is found, or nil otherwise
|
235
|
-
def
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
+
def find_page_or_file_from_path(path, kind = :page)
|
243
|
+
if Pathname.new(path).relative?
|
244
|
+
result = @markup.wiki.send(kind, ::File.join(@markup.dir, path))
|
245
|
+
if result.nil? && @markup.wiki.global_tag_lookup # 4.x link compatibility option. Slow!
|
246
|
+
result = @markup.wiki.send(kind, path, nil, true)
|
247
|
+
end
|
248
|
+
result
|
242
249
|
else
|
243
|
-
@markup.wiki.
|
250
|
+
@markup.wiki.send(kind, path)
|
244
251
|
end
|
245
252
|
end
|
246
253
|
|
@@ -264,7 +271,8 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
264
271
|
#
|
265
272
|
# Returns a String href.
|
266
273
|
def generate_href_for_path(path, extra = nil)
|
267
|
-
|
274
|
+
return extra if !path && extra # Internal anchor link
|
275
|
+
"#{trim_leading_slashes(::File.join(@markup.wiki.base_path, path))}#{extra}"
|
268
276
|
end
|
269
277
|
|
270
278
|
# Construct a CSS class and attribute string for different kinds of links: internal Pages (absent or present) and Files, and External links.
|
@@ -278,6 +286,8 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
278
286
|
'class="internal absent"'
|
279
287
|
when :page_present
|
280
288
|
'class="internal present"'
|
289
|
+
when :internal_anchor
|
290
|
+
'class="internal anchorlink"'
|
281
291
|
when :file
|
282
292
|
nil
|
283
293
|
when :external
|
@@ -299,10 +309,10 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
299
309
|
attr_string = attrs.map {|key, value| "#{key}=\"#{value}\""}.join(' ')
|
300
310
|
|
301
311
|
if containered
|
302
|
-
%{<span class="#{classes.join(' ')}">} +
|
303
|
-
%{<span>} +
|
312
|
+
%{<span class="d-flex #{classes[:container].join(' ')}">} +
|
313
|
+
%{<span class="#{classes[:nested].join(' ')}">} +
|
304
314
|
%{<img src="#{path}" #{attr_string}/>} +
|
305
|
-
(attrs[:alt] ? %{<span>#{attrs[:alt]}</span>} : '') +
|
315
|
+
(options[:frame] && attrs[:alt] ? %{<span class="clearfix">#{attrs[:alt]}</span>} : '') +
|
306
316
|
%{</span>} +
|
307
317
|
%{</span>}
|
308
318
|
else
|
@@ -314,31 +324,31 @@ class Gollum::Filter::Tags < Gollum::Filter
|
|
314
324
|
#
|
315
325
|
# options - The Hash of parsed image options.
|
316
326
|
#
|
317
|
-
# Returns
|
327
|
+
# Returns a Hash containing CSS class Arrays, a Hash of CSS attributes, and a Boolean indicating whether or not the image is containered.
|
318
328
|
def generate_image_attributes(options)
|
319
329
|
containered = false
|
320
|
-
classes = [] # applied to
|
330
|
+
classes = {container: [], nested: []} # applied to the container(s)
|
321
331
|
attrs = {} # applied to the image
|
322
332
|
|
323
333
|
align = options[:align]
|
324
334
|
if options[:float]
|
325
335
|
containered = true
|
326
|
-
align
|
327
|
-
|
328
|
-
classes << "float-#{align}"
|
329
|
-
end
|
336
|
+
align = 'left' unless align == 'right'
|
337
|
+
classes[:container] << "float-#{align} pb-4"
|
330
338
|
elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align)
|
331
339
|
attrs[:align] = align
|
332
340
|
elsif align
|
333
341
|
if %w{left center right}.include?(align)
|
334
342
|
containered = true
|
335
|
-
|
343
|
+
text_align = "text-#{align}"
|
344
|
+
align = 'end' if align == 'right'
|
345
|
+
classes[:container] << "flex-justify-#{align} #{text_align}"
|
336
346
|
end
|
337
347
|
end
|
338
348
|
|
339
|
-
if options[:frame]
|
349
|
+
if options[:frame]
|
340
350
|
containered = true
|
341
|
-
classes << '
|
351
|
+
classes[:nested] << 'border p-4'
|
342
352
|
end
|
343
353
|
|
344
354
|
attrs[:alt] = options[:alt] if options[:alt]
|