gollum-lib 5.0.a.3-java → 5.0.a.4-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 43de530f54acdb12ffac21a4bb96db1844f59119
4
- data.tar.gz: f4cf906bf8898dfb676f1130a2c3e2b270d15f41
2
+ SHA256:
3
+ metadata.gz: f3579bcfc342afcfe2b398241c190fbba84cfe2c5c922576aaaecb512bab5cd8
4
+ data.tar.gz: 9387c63c0f369902cf50439b750864fc2c4f86834da46576da7e1c8dc51464c6
5
5
  SHA512:
6
- metadata.gz: d0e79ae8f96d9688bbd45cc9b38e5630fd38bcc4d52a437ed72e949f292c7c6a2f1c973250af0828a83cb09e6be138387ce49b7f064d8d58829ba3b852d8a3a3
7
- data.tar.gz: fff6e1c352190df905559ad9d53fea8dd3feb9973696e5dfbb5ce2576d67f6c2529b737ce9600ec5d78ab7a1295121445cda73f9df9a4a5b13f2611f1b1f149e
6
+ metadata.gz: 4a9bfdbb8a78a024d9c66c4cfa3d185b4156c3bd86068006ea26977db3dcb456691863a19359917cd3e5d70bf5c92f261bd4b47b977d21727608c783b6f0ce58
7
+ data.tar.gz: 29ac662c80e6b90fad991b7bb421486cf2b1a5b5a3838f342bbdfb0d26f23a6680a98cd6372077a5ed3e8e07578a9470600a4c9a427346fcc36700e735f8f9c5
data/HISTORY.md CHANGED
@@ -1,3 +1,10 @@
1
+ # v5.0
2
+
3
+ For a detailed overview of changes in 5.0 and a guide to migrating your wiki, see https://github.com/gollum/gollum/wiki/5.0-release-notes
4
+
5
+ * Removed support for Web Sequence Diagroms, PlantUML now default.
6
+ ** PlantUML users in 4.x please note: in this release PlantUML uses the server at https://plantuml.com by default, not `localhost`. Use the config option to keep using your own server.
7
+
1
8
  # v4.2.1
2
9
 
3
10
  * Performances improvements
data/gemspec.rb CHANGED
@@ -8,6 +8,7 @@ def specification(version, default_adapter, platform = nil)
8
8
  s.name = 'gollum-lib'
9
9
  s.version = version
10
10
  s.platform = platform if platform
11
+ s.date = '2018-09-17'
11
12
  s.date = '2017-04-13'
12
13
  s.rubyforge_project = 'gollum-lib'
13
14
  s.license = 'MIT'
@@ -25,19 +26,22 @@ def specification(version, default_adapter, platform = nil)
25
26
  s.extra_rdoc_files = %w(README.md LICENSE)
26
27
 
27
28
  s.add_dependency *default_adapter
28
- s.add_dependency 'rouge', '~> 2.0'
29
- s.add_dependency 'nokogiri', '~> 1.7', '>= 1.7.1'
29
+ s.add_dependency 'rouge', '~> 3.1'
30
+ s.add_dependency 'nokogiri', '~> 1.8'
30
31
  s.add_dependency 'stringex', '~> 2.6'
31
32
  s.add_dependency 'sanitize', '~> 2.1'
32
33
  s.add_dependency 'github-markup', '~> 1.6'
33
34
  s.add_dependency 'gemojione', '~> 3.2'
35
+ s.add_dependency 'twitter-text', '1.14.7'
34
36
 
35
37
  s.add_development_dependency 'org-ruby', '~> 0.9.9'
36
38
  s.add_development_dependency 'kramdown', '~> 1.13'
37
39
  s.add_development_dependency 'RedCloth', '~> 4.2.9'
38
- s.add_development_dependency 'mocha', '~> 1.1.0'
40
+ s.add_development_dependency 'mocha', '~> 1.2.0'
39
41
  s.add_development_dependency 'shoulda', '~> 3.5.0'
40
42
  s.add_development_dependency 'wikicloth', '~> 0.8.3'
43
+ s.add_development_dependency 'bibtex-ruby', '~> 4.3'
44
+ s.add_development_dependency 'citeproc-ruby', '~> 1.1'
41
45
  s.add_development_dependency 'rake', '~> 10.4.0'
42
46
  s.add_development_dependency 'pry', '~> 0.10.1'
43
47
  # required by pry
@@ -71,9 +75,11 @@ def specification(version, default_adapter, platform = nil)
71
75
  lib/gollum-lib/file.rb
72
76
  lib/gollum-lib/file_view.rb
73
77
  lib/gollum-lib/filter.rb
78
+ lib/gollum-lib/filter/bibtex.rb
74
79
  lib/gollum-lib/filter/code.rb
75
80
  lib/gollum-lib/filter/emoji.rb
76
81
  lib/gollum-lib/filter/macro.rb
82
+ lib/gollum-lib/filter/pandoc_bib.rb
77
83
  lib/gollum-lib/filter/plain_text.rb
78
84
  lib/gollum-lib/filter/plantuml.rb
79
85
  lib/gollum-lib/filter/remote_code.rb
@@ -81,7 +87,6 @@ def specification(version, default_adapter, platform = nil)
81
87
  lib/gollum-lib/filter/sanitize.rb
82
88
  lib/gollum-lib/filter/tags.rb
83
89
  lib/gollum-lib/filter/toc.rb
84
- lib/gollum-lib/filter/wsd.rb
85
90
  lib/gollum-lib/filter/yaml.rb
86
91
  lib/gollum-lib/git_access.rb
87
92
  lib/gollum-lib/helpers.rb
@@ -91,6 +96,7 @@ def specification(version, default_adapter, platform = nil)
91
96
  lib/gollum-lib/macro/global_toc.rb
92
97
  lib/gollum-lib/macro/navigation.rb
93
98
  lib/gollum-lib/macro/series.rb
99
+ lib/gollum-lib/macro/video.rb
94
100
  lib/gollum-lib/markup.rb
95
101
  lib/gollum-lib/markups.rb
96
102
  lib/gollum-lib/page.rb
@@ -5,13 +5,10 @@ require 'digest/sha1'
5
5
  require 'ostruct'
6
6
  require 'pathname'
7
7
 
8
- DEFAULT_ADAPTER = RUBY_PLATFORM == 'java' ? 'rjgit_adapter' : 'grit_adapter'
8
+ DEFAULT_ADAPTER = RUBY_PLATFORM == 'java' ? 'rjgit' : 'grit'
9
9
 
10
- if defined?(Gollum::GIT_ADAPTER)
11
- require "#{Gollum::GIT_ADAPTER.downcase}_adapter"
12
- else
13
- require DEFAULT_ADAPTER
14
- end
10
+ Gollum::GIT_ADAPTER = DEFAULT_ADAPTER if !defined?(Gollum::GIT_ADAPTER)
11
+ require "#{Gollum::GIT_ADAPTER.downcase}_adapter"
15
12
 
16
13
  # external
17
14
  require 'github/markup'
@@ -26,6 +26,13 @@ module Gollum
26
26
  path
27
27
  end
28
28
 
29
+ # Public: The SHA hash identifying this file
30
+ #
31
+ # Returns the String SHA.
32
+ def sha
33
+ @blob && @blob.id
34
+ end
35
+
29
36
  # Public: The url_path, but CGI escaped.
30
37
  #
31
38
  # Returns the String url_path
@@ -55,12 +55,12 @@ module Gollum
55
55
  @map = {}
56
56
  end
57
57
 
58
- def extract(_d)
58
+ def extract(data)
59
59
  raise RuntimeError,
60
60
  "#{self.class} has not implemented ##extract!"
61
61
  end
62
62
 
63
- def process(_d)
63
+ def process(data)
64
64
  raise RuntimeError,
65
65
  "#{self.class} has not implemented ##process!"
66
66
  end
@@ -0,0 +1,55 @@
1
+ begin
2
+ require 'bibtex'
3
+ require 'citeproc'
4
+ require 'csl'
5
+ require 'csl/styles'
6
+ rescue LoadError => error
7
+ end
8
+
9
+ # Render BibTeX files.
10
+ class Gollum::Filter::BibTeX < Gollum::Filter
11
+
12
+ def extract(data)
13
+ return data unless supported_format? && gems_available? && bib = ::BibTeX.parse(data).convert(:latex)
14
+ style = find_csl_data('csl') || ::CSL::Style.default
15
+ locale = find_csl_data('locale') || ::CSL::Locale.default
16
+
17
+ begin
18
+ style = ::CSL::Style.load(style)
19
+ ::CSL::Locale.load(locale)
20
+ rescue ::CSL::ParseError => error
21
+ log_failure(error.to_s)
22
+ return CGI.escapeHTML(data)
23
+ end
24
+
25
+ citeproc = ::CiteProc::Processor.new(style: style, locale: locale, format: 'html')
26
+ citeproc.import(bib.to_citeproc)
27
+ citeproc.bibliography.references.join('<br/>')
28
+ end
29
+
30
+ def process(data)
31
+ data
32
+ end
33
+
34
+ private
35
+
36
+ def log_failure(msg)
37
+ @markup.metadata = {} unless @markup.metadata
38
+ @markup.metadata['errors'] = [] unless @markup.metadata['errors']
39
+ @markup.metadata['errors'] << "Could not render the bibliography because no valid CSL or locale file was found in the wiki or in the CSL directory. Please commited a valid file, or install the csl-styles gem. The message from the parser was: #{msg.to_s}."
40
+ end
41
+
42
+ def supported_format?
43
+ @markup.format == :bib
44
+ end
45
+
46
+ def gems_available?
47
+ ::Gollum::Markup.formats[:bib][:enabled]
48
+ end
49
+
50
+ def find_csl_data(key)
51
+ path = @markup.metadata ? @markup.metadata[key] : nil
52
+ file = path ? @markup.wiki.file(path) : nil
53
+ file.nil? ? path : file.raw_data
54
+ end
55
+ end
@@ -6,8 +6,6 @@
6
6
  class Gollum::Filter::Code < Gollum::Filter
7
7
  def extract(data)
8
8
  case @markup.format
9
- when :txt
10
- return data
11
9
  when :asciidoc
12
10
  data.gsub!(/^(\[source,([^\r\n]*)\]\n)?----\n(.+?)\n----$/m) do
13
11
  cache_codeblock(Regexp.last_match[2], Regexp.last_match[3])
@@ -2,12 +2,15 @@
2
2
 
3
3
  # Emoji
4
4
  #
5
- # Render emoji such as :smile:
5
+ # Render an emoji tag such as ":smile:". In some rare situations, you have
6
+ # to escape emoji tags e.g. when your content contains something like
7
+ # "hh:mm:ss" or "rake app:shell:install". Prefix the leading colon with a
8
+ # backslash to disable this emoji tag e.g. "hh\:mm:ss".
6
9
  class Gollum::Filter::Emoji < Gollum::Filter
7
10
 
8
11
  EXTRACT_PATTERN = %r{
9
12
  (?<!\[{2})
10
- :(?<name>[\w-]+):
13
+ (?<escape>\\)?:(?<name>[\w-]+):
11
14
  (?!\]{^2})
12
15
  }ix
13
16
 
@@ -19,7 +22,11 @@ class Gollum::Filter::Emoji < Gollum::Filter
19
22
 
20
23
  def extract(data)
21
24
  data.gsub! EXTRACT_PATTERN do
22
- emoji_exists?($~[:name]) ? "=EEMMOOJJII=#{$~[:name]}=IIJJOOMMEE=" : $&
25
+ case
26
+ when $~[:escape] then $&[1..-1]
27
+ when emoji_exists?($~[:name]) then "=EEMMOOJJII=#{$~[:name]}=IIJJOOMMEE="
28
+ else $&
29
+ end
23
30
  end
24
31
  data
25
32
  end
@@ -0,0 +1,52 @@
1
+ require 'yaml'
2
+ require 'pathname'
3
+
4
+ # When using pandoc, put relevant bibliography metadata extracted in the YAML filter back in the document so it gets passed on to pandoc.
5
+ class Gollum::Filter::PandocBib < Gollum::Filter
6
+
7
+ BIB_PATH_KEYS = ['bibliography', 'csl']
8
+ BIB_KEYS = ['link-citations', 'nocite']
9
+ ALL_BIB_KEYS = BIB_PATH_KEYS + BIB_KEYS
10
+
11
+ def process(data)
12
+ data
13
+ end
14
+
15
+ def extract(data)
16
+ return data unless supported_format? && bibliography_metadata_present?
17
+ bib_metadata = {}
18
+ bib_metadata.merge!(@markup.metadata.select {|key, _value| BIB_KEYS.include?(key)})
19
+
20
+ BIB_PATH_KEYS.each do |bibliography_key|
21
+ if path = @markup.metadata[bibliography_key]
22
+ next unless file = @markup.wiki.file(path)
23
+ bib_metadata[bibliography_key] = path_for_bibfile(file)
24
+ end
25
+ end
26
+ bib_metadata.empty? ? data : "#{bib_metadata.to_yaml}---\n#{data}"
27
+ end
28
+
29
+ private
30
+
31
+ def path_for_bibfile(file)
32
+ if @markup.wiki.repo_is_bare
33
+ path = Pathname.new("#{::File.join(::Dir.tmpdir, file.sha)}#{::File.extname(file.path)}")
34
+ unless path.exist?
35
+ path.open('w') do |copy_file|
36
+ copy_file.write(file.raw_data)
37
+ end
38
+ end
39
+ path.to_s
40
+ else
41
+ ::File.expand_path(::File.join(@markup.wiki.path, file.path))
42
+ end
43
+ end
44
+
45
+ def supported_format?
46
+ @markup.format == :markdown
47
+ end
48
+
49
+ def bibliography_metadata_present?
50
+ @markup.metadata && @markup.metadata.keys.any? {|key| ALL_BIB_KEYS.include?(key)}
51
+ end
52
+ end
@@ -6,6 +6,10 @@
6
6
 
7
7
  class Gollum::Filter::PlainText < Gollum::Filter
8
8
 
9
+ def do_process(_d)
10
+ skip? ? _d : process(_d)
11
+ end
12
+
9
13
  def extract(data)
10
14
  @markup.format == :txt ? "<pre>#{CGI.escapeHTML(data)}</pre>" : data
11
15
  end
@@ -37,7 +37,7 @@ require 'zlib'
37
37
  #
38
38
  class Gollum::Filter::PlantUML < Gollum::Filter
39
39
 
40
- DEFAULT_URL = "http://localhost:8080/plantuml/png"
40
+ DEFAULT_URL = "http://www.plantuml.com/plantuml/png"
41
41
 
42
42
  # Configuration class used to change the behaviour of the PlatnUML filter.
43
43
  #
@@ -69,7 +69,6 @@ class Gollum::Filter::PlantUML < Gollum::Filter
69
69
  # Extract all sequence diagram blocks into the map and replace with
70
70
  # placeholders.
71
71
  def extract(data)
72
- return data if @markup.format == :txt
73
72
  data.gsub(/(@startuml\r?\n.+?\r?\n@enduml\r?$)/m) do
74
73
  id = Digest::SHA1.hexdigest($1)
75
74
  @map[id] = { :code => $1 }
@@ -115,9 +114,9 @@ class Gollum::Filter::PlantUML < Gollum::Filter
115
114
  # Transcoder class in the PlantUML java code.
116
115
  def gen_url(text)
117
116
  result = ""
118
- compressedData = Zlib::Deflate.deflate(text)
117
+ compressedData = Zlib::Deflate.new(nil, -Zlib::MAX_WBITS).deflate(text, Zlib::FINISH)
118
+
119
119
  compressedData.chars.each_slice(3) do |bytes|
120
- #print bytes[0], ' ' , bytes[1] , ' ' , bytes[2]
121
120
  b1 = bytes[0].nil? ? 0 : (bytes[0].ord & 0xFF)
122
121
  b2 = bytes[1].nil? ? 0 : (bytes[1].ord & 0xFF)
123
122
  b3 = bytes[2].nil? ? 0 : (bytes[2].ord & 0xFF)
@@ -13,7 +13,6 @@ require 'open-uri'
13
13
  #
14
14
  class Gollum::Filter::RemoteCode < Gollum::Filter
15
15
  def extract(data)
16
- return data if @markup.format == :txt
17
16
  data.gsub(/^[ \t]*``` ?([^:\n\r]+):((http)?[^`\n\r]+)```/) do
18
17
  language = Regexp.last_match[1]
19
18
  uri = Regexp.last_match[2]
@@ -10,7 +10,7 @@ class Gollum::Filter::Sanitize < Gollum::Filter
10
10
  doc = Nokogiri::HTML::DocumentFragment.parse(data)
11
11
  doc = @markup.sanitize.clean_node!(doc)
12
12
 
13
- doc.to_xml(@markup.to_xml_opts)
13
+ doc.to_xml(@markup.to_xml_opts).gsub(/<p><\/p>/, '')
14
14
  else
15
15
  data
16
16
  end
@@ -4,7 +4,6 @@
4
4
  class Gollum::Filter::Tags < Gollum::Filter
5
5
  # Extract all tags into the tagmap and replace with placeholders.
6
6
  def extract(data)
7
- return data if @markup.format == :txt || @markup.format == :asciidoc
8
7
  data.gsub!(/(.?)\[\[(.+?)\]\]([^\[]?)/) do
9
8
  if Regexp.last_match[1] == "'" && Regexp.last_match[3] != "'"
10
9
  "[[#{Regexp.last_match[2]}]]#{Regexp.last_match[3]}"
@@ -28,12 +27,6 @@ class Gollum::Filter::Tags < Gollum::Filter
28
27
  data
29
28
  end
30
29
 
31
- def register_tag(tag)
32
- id = "TAG#{Digest::SHA1.hexdigest(tag)}TAG"
33
- @map[id] = tag
34
- id
35
- end
36
-
37
30
  # Process all text nodes from the doc and replace the placeholders with the
38
31
  # final markup.
39
32
  def process(rendered_data)
@@ -60,6 +53,13 @@ class Gollum::Filter::Tags < Gollum::Filter
60
53
  private
61
54
 
62
55
  PREFORMATTED_TAGS = %w(code tt)
56
+ INCLUDE_TAG = 'include:'
57
+
58
+ def register_tag(tag)
59
+ id = "TAG#{Digest::SHA1.hexdigest(tag)}TAG"
60
+ @map[id] = tag
61
+ id
62
+ end
63
63
 
64
64
  def is_preformatted?(node)
65
65
  node && (PREFORMATTED_TAGS.include?(node.name) ||
@@ -73,20 +73,43 @@ class Gollum::Filter::Tags < Gollum::Filter
73
73
  #
74
74
  # Returns the String HTML version of the tag.
75
75
  def process_tag(tag)
76
- if tag =~ /^_TOC_/
76
+ link_part, extra = parse_tag_parts(tag)
77
+ return generate_link('', nil, nil, :page_absent) if link_part.nil?
78
+ img_args = extra ? [extra, link_part] : [link_part]
79
+ mime = MIME::Types.type_for(::File.extname(img_args.first.to_s)).first
80
+
81
+ result = if tag =~ /^_TOC_/
77
82
  %{[[#{tag}]]}
78
- elsif tag =~ /^_$/
83
+ elsif link_part =~ /^_$/
79
84
  %{<div class="clearfloats"></div>}
80
- elsif (html = process_include_tag(tag))
81
- html
82
- elsif (html = process_image_tag(tag))
83
- html
84
- elsif (html = process_external_link_tag(tag))
85
- html
86
- elsif (html = process_file_link_tag(tag))
87
- html
85
+ elsif link_part =~ /^#{INCLUDE_TAG}/
86
+ process_include_tag(link_part)
87
+ elsif mime && mime.content_type =~ /^image/
88
+ process_image_tag(*img_args)
89
+ elsif external = process_external_link_tag(link_part, extra)
90
+ external
91
+ end
92
+ result ? result : process_link_tag(link_part, extra)
93
+ end
94
+
95
+ # Process the tag parts as an internal link to a File or Page.
96
+ def process_link_tag(link_part, pretty_name)
97
+ process_file_link_tag(link_part, pretty_name) || process_page_link_tag(link_part, pretty_name)
98
+ end
99
+
100
+ # Parse the tag (stuff between the double brackets) into a link part and additional information (a pretty name, description, or image options).
101
+ #
102
+ # tag - The String tag contents (the stuff inside the double
103
+ # brackets).
104
+ #
105
+ # Returns an Array of the form [link_part, extra], where both elements are Strings and the second element may be nil.
106
+ def parse_tag_parts(tag)
107
+ parts = tag.split('|').map(&:strip)[0..1]
108
+ parts.reverse! if @markup.reverse_links?
109
+ if parts[1]
110
+ return parts[1], parts[0]
88
111
  else
89
- process_page_link_tag(tag)
112
+ return parts[0], nil
90
113
  end
91
114
  end
92
115
 
@@ -94,16 +117,14 @@ class Gollum::Filter::Tags < Gollum::Filter
94
117
  #
95
118
  # tag - The String tag contents (the stuff inside the double brackets).
96
119
  #
97
- # Returns the String HTML if the tag is a valid image tag or nil
98
- # if it is not.
99
- #
120
+ # Returns the String HTML if the tag includes a valid page or an error message if the page could not be found.
100
121
  def process_include_tag(tag)
101
- return unless /^include:/.match(tag)
102
- page_name = tag[8..-1]
103
- resolved_page_name = ::File.expand_path(page_name, "/"+@markup.dir)
104
-
122
+ len = INCLUDE_TAG.length
123
+ return html_error('Cannot process include directive: no page name given') if tag.length <= len
124
+ page_name = tag[len..-1]
125
+ resolved_page_name = ::File.expand_path(page_name, "#{::File::SEPARATOR}#{@markup.dir}")
105
126
  if @markup.include_levels > 0
106
- page = find_page_from_name(resolved_page_name)
127
+ page = find_page_from_path(resolved_page_name)
107
128
  if page
108
129
  page.formatted_data(@markup.encoding, @markup.include_levels-1)
109
130
  else
@@ -116,110 +137,42 @@ class Gollum::Filter::Tags < Gollum::Filter
116
137
 
117
138
  # Attempt to process the tag as an image tag.
118
139
  #
119
- # tag - The String tag contents (the stuff inside the double brackets).
140
+ # path - The String path to the image.
141
+ # options - The String of options for the image (the stuff after the '|'). Optional.
120
142
  #
121
143
  # Returns the String HTML if the tag is a valid image tag or nil
122
144
  # if it is not.
123
- def process_image_tag(tag)
124
- parts = tag.split('|')
125
- return if parts.size.zero?
126
-
127
- name = parts[0].strip
128
- if (file = @markup.find_file(name))
129
- path = ::File.join @markup.wiki.base_path, file.path
130
- elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
131
- path = name
132
- elsif name =~ /.+(jpg|png|gif|svg|bmp)$/i
133
- # If is image, file not found and no link, then populate with empty String
134
- # We can than add an image not found alt attribute for this later
135
- path = ""
136
- end
137
-
138
- if path
139
- opts = parse_image_tag_options(tag)
140
-
141
- containered = false
142
-
143
- classes = [] # applied to whatever the outermost container is
144
- attrs = [] # applied to the image
145
-
146
- align = opts['align']
147
- if opts['float']
148
- containered = true
149
- align ||= 'left'
150
- if %w{left right}.include?(align)
151
- classes << "float-#{align}"
152
- end
153
- elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align)
154
- attrs << %{align="#{align}"}
155
- elsif align
156
- if %w{left center right}.include?(align)
157
- containered = true
158
- classes << "align-#{align}"
159
- end
160
- end
161
-
162
- if (width = opts['width'])
163
- if width =~ /^\d+(\.\d+)?(em|px)$/
164
- attrs << %{width="#{width}"}
165
- end
166
- end
167
-
168
- if (height = opts['height'])
169
- if height =~ /^\d+(\.\d+)?(em|px)$/
170
- attrs << %{height="#{height}"}
171
- end
172
- end
173
-
174
- if path != "" && (alt = opts['alt'])
175
- attrs << %{alt="#{alt}"}
176
- elsif path == ""
177
- attrs << %{alt="Image not found"}
178
- end
179
-
180
- attr_string = attrs.size > 0 ? attrs.join(' ') + ' ' : ''
181
-
182
- if opts['frame'] || containered
183
- classes << 'frame' if opts['frame']
184
- %{<span class="#{classes.join(' ')}">} +
185
- %{<span>} +
186
- %{<img src="#{path}" #{attr_string}/>} +
187
- (alt ? %{<span>#{alt}</span>} : '') +
188
- %{</span>} +
189
- %{</span>}
190
- else
191
- %{<img src="#{path}" #{attr_string}/>}
192
- end
145
+ def process_image_tag(path, options = nil)
146
+ opts = parse_image_tag_options(options)
147
+ if path =~ /^https?:\/\/.+$/i
148
+ generate_image(path, opts)
149
+ elsif file = @markup.find_file(path)
150
+ generate_image(generate_href_for_path(file.path), opts)
151
+ else
152
+ generate_image('', opts)
193
153
  end
194
154
  end
195
155
 
196
- # Parse any options present on the image tag and extract them into a
156
+ # Parse any options present on the image tag (comma separated) and extract them into a
197
157
  # Hash of option names and values.
198
158
  #
199
- # tag - The String tag contents (the stuff inside the double brackets).
159
+ # options - The String image options (the stuff in the after '|').
200
160
  #
201
161
  # Returns the options Hash:
202
162
  # key - The String option name.
203
163
  # val - The String option value or true if it is a binary option.
204
- def parse_image_tag_options(tag)
205
- tag.split('|')[1..-1].inject({}) do |memo, attr|
206
- parts = attr.split('=').map { |x| x.strip }
207
- memo[parts[0]] = (parts.size == 1 ? true : parts[1])
164
+ def parse_image_tag_options(options)
165
+ return {} if options.nil?
166
+ options.split(',').inject({}) do |memo, attr|
167
+ parts = attr.split('=').map { |x| x.strip }
168
+ memo[parts[0].to_sym] = (parts.size == 1 ? true : parts[1])
208
169
  memo
209
170
  end
210
171
  end
211
172
 
212
173
  # Return the String HTML if the tag is a valid external link tag or
213
174
  # nil if it is not.
214
- def process_external_link_tag(tag)
215
- parts = tag.split('|')
216
- parts.reverse! if @markup.reverse_links?
217
- return if parts.size.zero?
218
- if parts.size == 1
219
- url = parts[0].strip
220
- else
221
- name, url = *parts.compact.map(&:strip)
222
- end
175
+ def process_external_link_tag(url, pretty_name = nil)
223
176
  accepted_protocols = @markup.wiki.sanitization.protocols['a']['href'].dup
224
177
  if accepted_protocols.include?(:relative)
225
178
  accepted_protocols.select!{|protocol| protocol != :relative}
@@ -228,40 +181,22 @@ class Gollum::Filter::Tags < Gollum::Filter
228
181
  regexp = %r{^((#{accepted_protocols.join("|")}):)}
229
182
  end
230
183
  if url =~ regexp
231
- if name.nil?
232
- %{<a href="#{url}">#{url}</a>}
233
- else
234
- %{<a href="#{url}">#{name}</a>}
235
- end
184
+ generate_link(url, pretty_name, nil, :external)
236
185
  else
237
186
  nil
238
187
  end
239
-
240
188
  end
241
189
 
242
190
  # Attempt to process the tag as a file link tag.
243
191
  #
244
- # tag - The String tag contents (the stuff inside the double
245
- # brackets).
192
+ # link_part - The String part of the tag containing the link
193
+ # pretty_name - The String name for the link (optional)
246
194
  #
247
195
  # Returns the String HTML if the tag is a valid file link tag or nil
248
196
  # if it is not.
249
- def process_file_link_tag(tag)
250
- parts = tag.split('|')
251
- return if parts.size.zero?
252
-
253
- name = parts[0].strip
254
- path = parts[1] && parts[1].strip
255
- if path && file = @markup.find_file(path)
256
- path = ::File.join @markup.wiki.base_path, file.path
257
- else
258
- path = nil
259
- end
260
-
261
- if name && path && file
262
- %{<a href="#{::File.join @markup.wiki.base_path, file.path}">#{name}</a>}
263
- elsif name && path
264
- %{<a href="#{path}">#{name}</a>}
197
+ def process_file_link_tag(link_part, pretty_name)
198
+ if file = @markup.find_file(link_part)
199
+ generate_link(file.path, pretty_name, nil, :file)
265
200
  else
266
201
  nil
267
202
  end
@@ -269,59 +204,147 @@ class Gollum::Filter::Tags < Gollum::Filter
269
204
 
270
205
  # Attempt to process the tag as a page link tag.
271
206
  #
272
- # tag - The String tag contents (the stuff inside the double
273
- # brackets).
207
+ # link_part - The String part of the tag containing the link
208
+ # pretty_name - The String name for the link (optional)
274
209
  #
275
210
  # Returns the String HTML if the tag is a valid page link tag or nil
276
211
  # if it is not.
277
- def process_page_link_tag(tag)
278
- parts = tag.split('|')
279
- parts.reverse! if @markup.reverse_links?
212
+ def process_page_link_tag(link_part, pretty_name = nil)
213
+ presence = :page_absent
214
+ link = link_part
215
+ page = find_page_from_path(link)
216
+
217
+ # If no match yet, try finding page with anchor removed
218
+ if (page.nil? && pos = link.rindex('#'))
219
+ extra = link[pos..-1]
220
+ link = link[0...pos]
221
+ page = find_page_from_path(link)
222
+ end
223
+ presence = :page_present if page
224
+
225
+ name = pretty_name ? pretty_name : link
226
+ link = page ? page.escaped_url_path : CGI.escape(link)
227
+ generate_link(link, name, extra, presence)
228
+ end
280
229
 
281
- name, page_name = *parts.compact.map(&:strip)
282
- cname = page_name ? page_name : name.to_s
230
+ # Find a page from a given path
231
+ #
232
+ # path - The String path to search for.
233
+ #
234
+ # Returns a Gollum::Page instance if a page is found, or nil otherwise
235
+ def find_page_from_path(path)
236
+ slash = path.rindex('/')
283
237
 
284
- presence = "absent"
285
- link_name = cname
286
- page, extra = find_page_from_name(cname)
287
- if page
288
- link_name = page.name
289
- presence = "present"
238
+ unless slash.nil?
239
+ name = path[slash+1..-1]
240
+ path = path[0..slash]
241
+ @markup.wiki.paged(name, path)
242
+ else
243
+ @markup.wiki.page(path)
290
244
  end
291
- link = ::File.join(@markup.wiki.base_path, page ? page.escaped_url_path : CGI.escape(link_name))
292
-
293
- # //page is invalid
294
- # strip all duplicate forward slashes using helpers.rb trim_leading_slash
295
- # //page => /page
296
- link = trim_leading_slash link
245
+ end
297
246
 
298
- %{<a class="internal #{presence}" href="#{link}#{extra}">#{name}</a>}
247
+ # Generate an HTML link tag.
248
+ #
249
+ # path - The String path (href) to construct a link to.
250
+ # name - The String name of the link (text inside the link tag). Optional.
251
+ # extra - The String anchor to add the link. Optional.
252
+ # kind - A Symbol indicating whether this is a Page, File, or External link.
253
+ #
254
+ # Returns a String HTML link tag.
255
+ def generate_link(path, name = nil, extra = nil, kind = nil)
256
+ url = kind == :external ? path : generate_href_for_path(path, extra)
257
+ %{<a #{css_options_for_link(kind)} href="#{url}">#{name || path}</a>}
299
258
  end
300
259
 
301
- # Find a page from a given cname. If the page has an anchor (#) and has
302
- # no match, strip the anchor and try again.
260
+ # Generate a normalized href for a path, taking into consideration the wiki's path settings.
303
261
  #
304
- # cname - The String canonical page name including path.
262
+ # path - The String path to generate an href for.
263
+ # extra - The String anchor to add to the href. Optional.
305
264
  #
306
- # Returns a Gollum::Page instance if a page is found, or an Array of
307
- # [Gollum::Page, String extra] if a page without the extra anchor data
308
- # is found.
309
- def find_page_from_name(cname)
310
- slash = cname.rindex('/')
265
+ # Returns a String href.
266
+ def generate_href_for_path(path, extra = nil)
267
+ "#{trim_leading_slash(::File.join(@markup.wiki.base_path, path))}#{extra}"
268
+ end
311
269
 
312
- unless slash.nil?
313
- name = cname[slash+1..-1]
314
- path = cname[0..slash]
315
- page = @markup.wiki.paged(name, path)
270
+ # Construct a CSS class and attribute string for different kinds of links: internal Pages (absent or present) and Files, and External links.
271
+ #
272
+ # kind - The Symbol indicating the kind of link. Can be one of: :page_absent, :page_present, :file, :external.
273
+ #
274
+ # Returns the String CSS class and attributes.
275
+ def css_options_for_link(kind)
276
+ case kind
277
+ when :page_absent
278
+ 'class="internal absent"'
279
+ when :page_present
280
+ 'class="internal present"'
281
+ when :file
282
+ nil
283
+ when :external
284
+ nil
285
+ else
286
+ nil
287
+ end
288
+ end
289
+
290
+ # Generate an HTML image tag.
291
+ #
292
+ # path - The String path (href) of the image.
293
+ # options - The Hash of parsed image options.
294
+ #
295
+ # Returns a String HTML img tag.
296
+ def generate_image(path, options = nil)
297
+ classes, attrs, containered = generate_image_attributes(options)
298
+ attrs[:alt] = 'Image not found' if path.empty?
299
+ attr_string = attrs.map {|key, value| "#{key}=\"#{value}\""}.join(' ')
300
+
301
+ if containered
302
+ %{<span class="#{classes.join(' ')}">} +
303
+ %{<span>} +
304
+ %{<img src="#{path}" #{attr_string}/>} +
305
+ (attrs[:alt] ? %{<span>#{attrs[:alt]}</span>} : '') +
306
+ %{</span>} +
307
+ %{</span>}
316
308
  else
317
- page = @markup.wiki.paged(cname, '/') || @markup.wiki.page(cname)
309
+ %{<img src="#{path}" #{attr_string}/>}
318
310
  end
311
+ end
319
312
 
320
- if page
321
- return page
313
+ # Helper method to generate the styling attributes and elements for an image tag.
314
+ #
315
+ # options - The Hash of parsed image options.
316
+ #
317
+ # Returns an Array of CSS classes, a Hash of CSS attributes, and a Boolean indicating whether or not the image is containered.
318
+ def generate_image_attributes(options)
319
+ containered = false
320
+ classes = [] # applied to whatever the outermost container is
321
+ attrs = {} # applied to the image
322
+
323
+ align = options[:align]
324
+ if options[:float]
325
+ containered = true
326
+ align ||= 'left'
327
+ if %w{left right}.include?(align)
328
+ classes << "float-#{align}"
329
+ end
330
+ elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align)
331
+ attrs[:align] = align
332
+ elsif align
333
+ if %w{left center right}.include?(align)
334
+ containered = true
335
+ classes << "align-#{align}"
336
+ end
322
337
  end
323
- if (pos = cname.index('#'))
324
- [@markup.wiki.page(cname[0...pos]), cname[pos..-1]]
338
+
339
+ if options[:frame]
340
+ containered = true
341
+ classes << 'frame'
325
342
  end
343
+
344
+ attrs[:alt] = options[:alt] if options[:alt]
345
+ attrs[:width] = options[:width] if options[:width] =~ /^\d+(\.\d+)?(em|px)$/
346
+ attrs[:height] = options[:height] if options[:height] =~ /^\d+(\.\d+)?(em|px)$/
347
+
348
+ return classes, attrs, containered
326
349
  end
327
350
  end