read-only-gollum 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/HISTORY.md +102 -0
- data/Home.md +3 -0
- data/LICENSE +21 -0
- data/README.md +477 -0
- data/Rakefile +142 -0
- data/bin/read-only-gollum +126 -0
- data/docs/sanitization.md +32 -0
- data/lib/gollum.rb +41 -0
- data/lib/gollum/blob_entry.rb +78 -0
- data/lib/gollum/committer.rb +218 -0
- data/lib/gollum/file.rb +64 -0
- data/lib/gollum/frontend/app.rb +225 -0
- data/lib/gollum/frontend/public/css/dialog.css +141 -0
- data/lib/gollum/frontend/public/css/editor.css +537 -0
- data/lib/gollum/frontend/public/css/gollum.css +660 -0
- data/lib/gollum/frontend/public/css/ie7.css +69 -0
- data/lib/gollum/frontend/public/css/template.css +381 -0
- data/lib/gollum/frontend/public/images/icon-sprite.png +0 -0
- data/lib/gollum/frontend/public/javascript/editor/gollum.editor.js +1096 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/asciidoc.js +167 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/creole.js +104 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/markdown.js +211 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/org.js +173 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/pod.js +111 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/rdoc.js +74 -0
- data/lib/gollum/frontend/public/javascript/editor/langs/textile.js +175 -0
- data/lib/gollum/frontend/public/javascript/gollum.dialog.js +263 -0
- data/lib/gollum/frontend/public/javascript/gollum.js +161 -0
- data/lib/gollum/frontend/public/javascript/gollum.placeholder.js +54 -0
- data/lib/gollum/frontend/public/javascript/jquery.color.js +123 -0
- data/lib/gollum/frontend/public/javascript/jquery.js +7179 -0
- data/lib/gollum/frontend/templates/compare.mustache +38 -0
- data/lib/gollum/frontend/templates/create.mustache +17 -0
- data/lib/gollum/frontend/templates/edit.mustache +17 -0
- data/lib/gollum/frontend/templates/editor.mustache +116 -0
- data/lib/gollum/frontend/templates/error.mustache +8 -0
- data/lib/gollum/frontend/templates/history.mustache +58 -0
- data/lib/gollum/frontend/templates/layout.mustache +28 -0
- data/lib/gollum/frontend/templates/page.mustache +37 -0
- data/lib/gollum/frontend/templates/pages.mustache +35 -0
- data/lib/gollum/frontend/templates/search.mustache +36 -0
- data/lib/gollum/frontend/templates/searchbar.mustache +10 -0
- data/lib/gollum/frontend/views/compare.rb +94 -0
- data/lib/gollum/frontend/views/create.rb +48 -0
- data/lib/gollum/frontend/views/edit.rb +52 -0
- data/lib/gollum/frontend/views/editable.rb +13 -0
- data/lib/gollum/frontend/views/error.rb +7 -0
- data/lib/gollum/frontend/views/history.rb +44 -0
- data/lib/gollum/frontend/views/layout.rb +20 -0
- data/lib/gollum/frontend/views/page.rb +57 -0
- data/lib/gollum/frontend/views/pages.rb +19 -0
- data/lib/gollum/frontend/views/search.rb +20 -0
- data/lib/gollum/git_access.rb +248 -0
- data/lib/gollum/markup.rb +489 -0
- data/lib/gollum/page.rb +430 -0
- data/lib/gollum/pagination.rb +61 -0
- data/lib/gollum/sanitization.rb +174 -0
- data/lib/gollum/tex.rb +89 -0
- data/lib/gollum/web_sequence_diagram.rb +43 -0
- data/lib/gollum/wiki.rb +636 -0
- data/read-only-gollum.gemspec +224 -0
- data/templates/formatting.html +92 -0
- data/test/examples/empty.git/HEAD +1 -0
- data/test/examples/empty.git/config +5 -0
- data/test/examples/empty.git/description +1 -0
- data/test/examples/empty.git/hooks/applypatch-msg.sample +15 -0
- data/test/examples/empty.git/hooks/commit-msg.sample +24 -0
- data/test/examples/empty.git/hooks/post-commit.sample +8 -0
- data/test/examples/empty.git/hooks/post-receive.sample +15 -0
- data/test/examples/empty.git/hooks/post-update.sample +8 -0
- data/test/examples/empty.git/hooks/pre-applypatch.sample +14 -0
- data/test/examples/empty.git/hooks/pre-commit.sample +46 -0
- data/test/examples/empty.git/hooks/pre-rebase.sample +169 -0
- data/test/examples/empty.git/hooks/prepare-commit-msg.sample +36 -0
- data/test/examples/empty.git/hooks/update.sample +128 -0
- data/test/examples/empty.git/info/exclude +6 -0
- data/test/examples/empty.git/objects/info/.gitkeep +0 -0
- data/test/examples/empty.git/objects/pack/.gitkeep +0 -0
- data/test/examples/empty.git/refs/heads/.gitkeep +0 -0
- data/test/examples/lotr.git/COMMIT_EDITMSG +1 -0
- data/test/examples/lotr.git/HEAD +1 -0
- data/test/examples/lotr.git/ORIG_HEAD +1 -0
- data/test/examples/lotr.git/config +12 -0
- data/test/examples/lotr.git/description +1 -0
- data/test/examples/lotr.git/index +0 -0
- data/test/examples/lotr.git/info/exclude +6 -0
- data/test/examples/lotr.git/logs/HEAD +3 -0
- data/test/examples/lotr.git/logs/refs/heads/master +3 -0
- data/test/examples/lotr.git/objects/06/131480411710c92a82fe2d1e76932c70feb2e5 +0 -0
- data/test/examples/lotr.git/objects/0a/de1e2916346d4c1f2fb63b863fd3c16808fe44 +0 -0
- data/test/examples/lotr.git/objects/0e/d8cbe0a25235bd867e65193c7d837c66b328ef +3 -0
- data/test/examples/lotr.git/objects/12/629d666c5e3178f82f533f543d61b53dc78c0b +0 -0
- data/test/examples/lotr.git/objects/1d/b89ebba7e2c14d93b94ff98cfa3708a4f0d4e3 +2 -0
- data/test/examples/lotr.git/objects/24/49c2681badfd3c189e8ed658dacffe8ba48fe5 +0 -0
- data/test/examples/lotr.git/objects/25/4bdc1ba27d8b8a794538a8522d9a2b56ec2dd9 +0 -0
- data/test/examples/lotr.git/objects/2c/b9156ad383914561a8502fc70f5a1d887e48ad +4 -0
- data/test/examples/lotr.git/objects/5d/cac289a8603188d2c5caf481dcba2985126aaa +0 -0
- data/test/examples/lotr.git/objects/60/f12f4254f58801b9ee7db7bca5fa8aeefaa56b +0 -0
- data/test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f +0 -0
- data/test/examples/lotr.git/objects/84/0ec5b1ba1320e8ec443f28f99566f615d5af10 +0 -0
- data/test/examples/lotr.git/objects/93/6b83ee0dd8837adb82511e40d5e4ebe59bb675 +0 -0
- data/test/examples/lotr.git/objects/94/523d7ae48aeba575099dd12926420d8fd0425d +2 -0
- data/test/examples/lotr.git/objects/96/97dc65e095658bbd1b8e8678e08881e86d32f1 +0 -0
- data/test/examples/lotr.git/objects/a3/1ca2a7c352c92531a8b99815d15843b259e814 +0 -0
- data/test/examples/lotr.git/objects/a6/59b3763b822dd97544621fd0beef162ea37b14 +4 -0
- data/test/examples/lotr.git/objects/a8/ad3c09dd842a3517085bfadd37718856dee813 +0 -0
- data/test/examples/lotr.git/objects/aa/b61fe89d56f8614c0a8151da34f939dcedfa68 +0 -0
- data/test/examples/lotr.git/objects/bc/4b5fc0ce2c2ba3acef6647e4f67256ee45ab60 +0 -0
- data/test/examples/lotr.git/objects/c3/b43e9f08966b088e7a0192e436b7a884542e05 +0 -0
- data/test/examples/lotr.git/objects/dc/596d6b2dd89ab05c66f4abd7d5eb706bc17f19 +0 -0
- data/test/examples/lotr.git/objects/ec/da3205bee14520aab5a7bb307392064b938e83 +0 -0
- data/test/examples/lotr.git/objects/f4/84ebb1f40f8eb20d1bcd8d1d71934d2b8ae961 +0 -0
- data/test/examples/lotr.git/objects/fa/e7ef5344202bba4129abdc13060d9297d99465 +3 -0
- data/test/examples/lotr.git/objects/info/packs +2 -0
- data/test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.idx +0 -0
- data/test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.pack +0 -0
- data/test/examples/lotr.git/packed-refs +2 -0
- data/test/examples/lotr.git/refs/heads/master +1 -0
- data/test/examples/lotr.git/refs/remotes/origin/HEAD +1 -0
- data/test/examples/page_file_dir.git/COMMIT_EDITMSG +1 -0
- data/test/examples/page_file_dir.git/HEAD +1 -0
- data/test/examples/page_file_dir.git/config +6 -0
- data/test/examples/page_file_dir.git/description +1 -0
- data/test/examples/page_file_dir.git/index +0 -0
- data/test/examples/page_file_dir.git/info/exclude +6 -0
- data/test/examples/page_file_dir.git/logs/HEAD +1 -0
- data/test/examples/page_file_dir.git/logs/refs/heads/master +1 -0
- data/test/examples/page_file_dir.git/objects/0c/7d27db1f575263efdcab3dc650f4502a2dbcbf +0 -0
- data/test/examples/page_file_dir.git/objects/22/b404803c966dd92865614d86ff22ca12e50c1e +0 -0
- data/test/examples/page_file_dir.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 +0 -0
- data/test/examples/page_file_dir.git/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 +0 -0
- data/test/examples/page_file_dir.git/objects/5b/43e14e0a15fb6f08feab1773d1c0991e9f71e2 +0 -0
- data/test/examples/page_file_dir.git/refs/heads/master +1 -0
- data/test/examples/revert.git/COMMIT_EDITMSG +1 -0
- data/test/examples/revert.git/HEAD +1 -0
- data/test/examples/revert.git/config +12 -0
- data/test/examples/revert.git/description +1 -0
- data/test/examples/revert.git/index +0 -0
- data/test/examples/revert.git/info/exclude +6 -0
- data/test/examples/revert.git/logs/HEAD +2 -0
- data/test/examples/revert.git/logs/refs/heads/master +2 -0
- data/test/examples/revert.git/objects/20/2ced67cea93c7b6bd2928aa1daef8d1d55a20d +0 -0
- data/test/examples/revert.git/objects/41/76394bfa11222363c66ce7e84b5f154095b6d9 +0 -0
- data/test/examples/revert.git/objects/6a/69f92020f5df77af6e8813ff1232493383b708 +0 -0
- data/test/examples/revert.git/objects/b4/785957bc986dc39c629de9fac9df46972c00fc +0 -0
- data/test/examples/revert.git/objects/f4/03b791119f8232b7cb0ba455c624ac6435f433 +0 -0
- data/test/examples/revert.git/objects/info/packs +2 -0
- data/test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.idx +0 -0
- data/test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.pack +0 -0
- data/test/examples/revert.git/packed-refs +2 -0
- data/test/examples/revert.git/refs/heads/master +1 -0
- data/test/examples/revert.git/refs/remotes/origin/HEAD +1 -0
- data/test/examples/yubiwa.git/HEAD +1 -0
- data/test/examples/yubiwa.git/config +5 -0
- data/test/examples/yubiwa.git/description +1 -0
- data/test/examples/yubiwa.git/info/exclude +6 -0
- data/test/examples/yubiwa.git/objects/10/fa2ddc4e3b4009d8a453aace10bd6148c1ad00 +0 -0
- data/test/examples/yubiwa.git/objects/52/4b82874327ea7cbf730389964ba7cb3de966de +0 -0
- data/test/examples/yubiwa.git/objects/58/3fc201cb457fb3f1480f3e1e5999b119633835 +0 -0
- data/test/examples/yubiwa.git/objects/87/bc1dd46ab3d3874d4e898d45dd512cc20a7cc8 +1 -0
- data/test/examples/yubiwa.git/objects/89/64ed1b4e21aa90e831763bbce9034bfda81b70 +0 -0
- data/test/examples/yubiwa.git/objects/9f/f6dd0660da5fba2d3374adb2b84fa653bb538b +0 -0
- data/test/examples/yubiwa.git/objects/ac/e97abf2b177815a1972d7db22f229f58c83309 +0 -0
- data/test/examples/yubiwa.git/objects/b1/f443863a4816628807fbf86141ebef055dda34 +0 -0
- data/test/examples/yubiwa.git/refs/heads/master +1 -0
- data/test/helper.rb +66 -0
- data/test/test_app.rb +169 -0
- data/test/test_committer.rb +64 -0
- data/test/test_file.rb +27 -0
- data/test/test_git_access.rb +52 -0
- data/test/test_markup.rb +628 -0
- data/test/test_page.rb +166 -0
- data/test/test_page_revert.rb +45 -0
- data/test/test_wiki.rb +462 -0
- metadata +470 -0
@@ -0,0 +1,489 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'cgi'
|
3
|
+
require 'pygments'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
module Gollum
|
7
|
+
|
8
|
+
class Markup
|
9
|
+
# Initialize a new Markup object.
|
10
|
+
#
|
11
|
+
# page - The Gollum::Page.
|
12
|
+
#
|
13
|
+
# Returns a new Gollum::Markup object, ready for rendering.
|
14
|
+
def initialize(page)
|
15
|
+
@wiki = page.wiki
|
16
|
+
@name = page.filename
|
17
|
+
@data = page.text_data
|
18
|
+
@version = page.version.id if page.version
|
19
|
+
@format = page.format
|
20
|
+
@dir = ::File.dirname(page.path)
|
21
|
+
@tagmap = {}
|
22
|
+
@codemap = {}
|
23
|
+
@texmap = {}
|
24
|
+
@wsdmap = {}
|
25
|
+
@premap = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Render the content with Gollum wiki syntax on top of the file's own
|
29
|
+
# markup language.
|
30
|
+
#
|
31
|
+
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
32
|
+
# <a> tags.
|
33
|
+
# encoding - Encoding Constant or String.
|
34
|
+
#
|
35
|
+
# Returns the formatted String content.
|
36
|
+
def render(no_follow = false, encoding = nil)
|
37
|
+
sanitize = no_follow ?
|
38
|
+
@wiki.history_sanitizer :
|
39
|
+
@wiki.sanitizer
|
40
|
+
|
41
|
+
data = extract_tex(@data.dup)
|
42
|
+
data = extract_code(data)
|
43
|
+
data = extract_wsd(data)
|
44
|
+
data = extract_tags(data)
|
45
|
+
begin
|
46
|
+
data = GitHub::Markup.render(@name, data)
|
47
|
+
if data.nil?
|
48
|
+
raise "There was an error converting #{@name} to HTML."
|
49
|
+
end
|
50
|
+
rescue Object => e
|
51
|
+
data = %{<p class="gollum-error">#{e.message}</p>}
|
52
|
+
end
|
53
|
+
data = process_tags(data)
|
54
|
+
data = process_code(data, encoding)
|
55
|
+
if sanitize || block_given?
|
56
|
+
doc = Nokogiri::HTML::DocumentFragment.parse(data)
|
57
|
+
doc = sanitize.clean_node!(doc) if sanitize
|
58
|
+
yield doc if block_given?
|
59
|
+
data = doc.to_html
|
60
|
+
end
|
61
|
+
data = process_tex(data)
|
62
|
+
data = process_wsd(data)
|
63
|
+
data.gsub!(/<p><\/p>/, '')
|
64
|
+
data
|
65
|
+
end
|
66
|
+
|
67
|
+
#########################################################################
|
68
|
+
#
|
69
|
+
# TeX
|
70
|
+
#
|
71
|
+
#########################################################################
|
72
|
+
|
73
|
+
# Extract all TeX into the texmap and replace with placeholders.
|
74
|
+
#
|
75
|
+
# data - The raw String data.
|
76
|
+
#
|
77
|
+
# Returns the placeholder'd String data.
|
78
|
+
def extract_tex(data)
|
79
|
+
data.gsub(/\\\[\s*(.*?)\s*\\\]/m) do
|
80
|
+
tag = CGI.escapeHTML($1)
|
81
|
+
id = Digest::SHA1.hexdigest(tag)
|
82
|
+
@texmap[id] = [:block, tag]
|
83
|
+
id
|
84
|
+
end.gsub(/\\\(\s*(.*?)\s*\\\)/m) do
|
85
|
+
tag = CGI.escapeHTML($1)
|
86
|
+
id = Digest::SHA1.hexdigest(tag)
|
87
|
+
@texmap[id] = [:inline, tag]
|
88
|
+
id
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Process all TeX from the texmap and replace the placeholders with the
|
93
|
+
# final markup.
|
94
|
+
#
|
95
|
+
# data - The String data (with placeholders).
|
96
|
+
#
|
97
|
+
# Returns the marked up String data.
|
98
|
+
def process_tex(data)
|
99
|
+
@texmap.each do |id, spec|
|
100
|
+
type, tex = *spec
|
101
|
+
out = %{<img src="#{::File.join(@wiki.base_path, '_tex.png')}?type=#{type}&data=#{Base64.encode64(tex).chomp}" alt="#{CGI.escapeHTML(tex)}">}
|
102
|
+
data.gsub!(id, out)
|
103
|
+
end
|
104
|
+
data
|
105
|
+
end
|
106
|
+
|
107
|
+
#########################################################################
|
108
|
+
#
|
109
|
+
# Tags
|
110
|
+
#
|
111
|
+
#########################################################################
|
112
|
+
|
113
|
+
# Extract all tags into the tagmap and replace with placeholders.
|
114
|
+
#
|
115
|
+
# data - The raw String data.
|
116
|
+
#
|
117
|
+
# Returns the placeholder'd String data.
|
118
|
+
def extract_tags(data)
|
119
|
+
data.gsub!(/(.?)\[\[(.+?)\]\]([^\[]?)/m) do
|
120
|
+
if $1 == "'" && $3 != "'"
|
121
|
+
"[[#{$2}]]#{$3}"
|
122
|
+
elsif $2.include?('][')
|
123
|
+
if $2[0..4] == 'file:'
|
124
|
+
pre = $1
|
125
|
+
post = $3
|
126
|
+
parts = $2.split('][')
|
127
|
+
parts[0][0..4] = ""
|
128
|
+
link = "#{parts[1]}|#{parts[0].sub(/\.org/,'')}"
|
129
|
+
id = Digest::SHA1.hexdigest(link)
|
130
|
+
@tagmap[id] = link
|
131
|
+
"#{pre}#{id}#{post}"
|
132
|
+
else
|
133
|
+
$&
|
134
|
+
end
|
135
|
+
else
|
136
|
+
id = Digest::SHA1.hexdigest($2)
|
137
|
+
@tagmap[id] = $2
|
138
|
+
"#{$1}#{id}#{$3}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
data
|
142
|
+
end
|
143
|
+
|
144
|
+
# Process all tags from the tagmap and replace the placeholders with the
|
145
|
+
# final markup.
|
146
|
+
#
|
147
|
+
# data - The String data (with placeholders).
|
148
|
+
#
|
149
|
+
# Returns the marked up String data.
|
150
|
+
def process_tags(data)
|
151
|
+
@tagmap.each do |id, tag|
|
152
|
+
data.gsub!(id, process_tag(tag))
|
153
|
+
end
|
154
|
+
data
|
155
|
+
end
|
156
|
+
|
157
|
+
# Process a single tag into its final HTML form.
|
158
|
+
#
|
159
|
+
# tag - The String tag contents (the stuff inside the double
|
160
|
+
# brackets).
|
161
|
+
#
|
162
|
+
# Returns the String HTML version of the tag.
|
163
|
+
def process_tag(tag)
|
164
|
+
if html = process_image_tag(tag)
|
165
|
+
html
|
166
|
+
elsif html = process_file_link_tag(tag)
|
167
|
+
html
|
168
|
+
else
|
169
|
+
process_page_link_tag(tag)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Attempt to process the tag as an image tag.
|
174
|
+
#
|
175
|
+
# tag - The String tag contents (the stuff inside the double brackets).
|
176
|
+
#
|
177
|
+
# Returns the String HTML if the tag is a valid image tag or nil
|
178
|
+
# if it is not.
|
179
|
+
def process_image_tag(tag)
|
180
|
+
parts = tag.split('|')
|
181
|
+
return if parts.size.zero?
|
182
|
+
|
183
|
+
name = parts[0].strip
|
184
|
+
path = if file = find_file(name)
|
185
|
+
::File.join @wiki.base_path, file.path
|
186
|
+
elsif name =~ /^https?:\/\/.+(jpg|png|gif|svg|bmp)$/i
|
187
|
+
name
|
188
|
+
end
|
189
|
+
|
190
|
+
if path
|
191
|
+
opts = parse_image_tag_options(tag)
|
192
|
+
|
193
|
+
containered = false
|
194
|
+
|
195
|
+
classes = [] # applied to whatever the outermost container is
|
196
|
+
attrs = [] # applied to the image
|
197
|
+
|
198
|
+
align = opts['align']
|
199
|
+
if opts['float']
|
200
|
+
containered = true
|
201
|
+
align ||= 'left'
|
202
|
+
if %w{left right}.include?(align)
|
203
|
+
classes << "float-#{align}"
|
204
|
+
end
|
205
|
+
elsif %w{top texttop middle absmiddle bottom absbottom baseline}.include?(align)
|
206
|
+
attrs << %{align="#{align}"}
|
207
|
+
elsif align
|
208
|
+
if %w{left center right}.include?(align)
|
209
|
+
containered = true
|
210
|
+
classes << "align-#{align}"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
if width = opts['width']
|
215
|
+
if width =~ /^\d+(\.\d+)?(em|px)$/
|
216
|
+
attrs << %{width="#{width}"}
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
if height = opts['height']
|
221
|
+
if height =~ /^\d+(\.\d+)?(em|px)$/
|
222
|
+
attrs << %{height="#{height}"}
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
if alt = opts['alt']
|
227
|
+
attrs << %{alt="#{alt}"}
|
228
|
+
end
|
229
|
+
|
230
|
+
attr_string = attrs.size > 0 ? attrs.join(' ') + ' ' : ''
|
231
|
+
|
232
|
+
if opts['frame'] || containered
|
233
|
+
classes << 'frame' if opts['frame']
|
234
|
+
%{<span class="#{classes.join(' ')}">} +
|
235
|
+
%{<span>} +
|
236
|
+
%{<img src="#{path}" #{attr_string}/>} +
|
237
|
+
(alt ? %{<span>#{alt}</span>} : '') +
|
238
|
+
%{</span>} +
|
239
|
+
%{</span>}
|
240
|
+
else
|
241
|
+
%{<img src="#{path}" #{attr_string}/>}
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Parse any options present on the image tag and extract them into a
|
247
|
+
# Hash of option names and values.
|
248
|
+
#
|
249
|
+
# tag - The String tag contents (the stuff inside the double brackets).
|
250
|
+
#
|
251
|
+
# Returns the options Hash:
|
252
|
+
# key - The String option name.
|
253
|
+
# val - The String option value or true if it is a binary option.
|
254
|
+
def parse_image_tag_options(tag)
|
255
|
+
tag.split('|')[1..-1].inject({}) do |memo, attr|
|
256
|
+
parts = attr.split('=').map { |x| x.strip }
|
257
|
+
memo[parts[0]] = (parts.size == 1 ? true : parts[1])
|
258
|
+
memo
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Attempt to process the tag as a file link tag.
|
263
|
+
#
|
264
|
+
# tag - The String tag contents (the stuff inside the double
|
265
|
+
# brackets).
|
266
|
+
#
|
267
|
+
# Returns the String HTML if the tag is a valid file link tag or nil
|
268
|
+
# if it is not.
|
269
|
+
def process_file_link_tag(tag)
|
270
|
+
parts = tag.split('|')
|
271
|
+
return if parts.size.zero?
|
272
|
+
|
273
|
+
name = parts[0].strip
|
274
|
+
path = parts[1] && parts[1].strip
|
275
|
+
path = if path && file = find_file(path)
|
276
|
+
::File.join @wiki.base_path, file.path
|
277
|
+
elsif path =~ %r{^https?://}
|
278
|
+
path
|
279
|
+
else
|
280
|
+
nil
|
281
|
+
end
|
282
|
+
|
283
|
+
if name && path && file
|
284
|
+
%{<a href="#{::File.join @wiki.base_path, file.path}">#{name}</a>}
|
285
|
+
elsif name && path
|
286
|
+
%{<a href="#{path}">#{name}</a>}
|
287
|
+
else
|
288
|
+
nil
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Attempt to process the tag as a page link tag.
|
293
|
+
#
|
294
|
+
# tag - The String tag contents (the stuff inside the double
|
295
|
+
# brackets).
|
296
|
+
#
|
297
|
+
# Returns the String HTML if the tag is a valid page link tag or nil
|
298
|
+
# if it is not.
|
299
|
+
def process_page_link_tag(tag)
|
300
|
+
parts = tag.split('|')
|
301
|
+
parts.reverse! if @format == :mediawiki
|
302
|
+
|
303
|
+
name, page_name = *parts.compact.map(&:strip)
|
304
|
+
cname = @wiki.page_class.cname(page_name || name)
|
305
|
+
|
306
|
+
if name =~ %r{^https?://} && page_name.nil?
|
307
|
+
%{<a href="#{name}">#{name}</a>}
|
308
|
+
else
|
309
|
+
presence = "absent"
|
310
|
+
link_name = cname
|
311
|
+
page, extra = find_page_from_name(cname)
|
312
|
+
if page
|
313
|
+
link_name = @wiki.page_class.cname(page.name)
|
314
|
+
presence = "present"
|
315
|
+
end
|
316
|
+
link = ::File.join(@wiki.base_path, CGI.escape(link_name))
|
317
|
+
%{<a class="internal #{presence}" href="#{link}#{extra}">#{name}</a>}
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
# Find the given file in the repo.
|
322
|
+
#
|
323
|
+
# name - The String absolute or relative path of the file.
|
324
|
+
#
|
325
|
+
# Returns the Gollum::File or nil if none was found.
|
326
|
+
def find_file(name)
|
327
|
+
if name =~ /^\//
|
328
|
+
@wiki.file(name[1..-1], @version)
|
329
|
+
else
|
330
|
+
path = @dir == '.' ? name : ::File.join(@dir, name)
|
331
|
+
@wiki.file(path, @version)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Find a page from a given cname. If the page has an anchor (#) and has
|
336
|
+
# no match, strip the anchor and try again.
|
337
|
+
#
|
338
|
+
# cname - The String canonical page name.
|
339
|
+
#
|
340
|
+
# Returns a Gollum::Page instance if a page is found, or an Array of
|
341
|
+
# [Gollum::Page, String extra] if a page without the extra anchor data
|
342
|
+
# is found.
|
343
|
+
def find_page_from_name(cname)
|
344
|
+
if page = @wiki.page(cname)
|
345
|
+
return page
|
346
|
+
end
|
347
|
+
if pos = cname.index('#')
|
348
|
+
[@wiki.page(cname[0...pos]), cname[pos..-1]]
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
#########################################################################
|
353
|
+
#
|
354
|
+
# Code
|
355
|
+
#
|
356
|
+
#########################################################################
|
357
|
+
|
358
|
+
# Extract all code blocks into the codemap and replace with placeholders.
|
359
|
+
#
|
360
|
+
# data - The raw String data.
|
361
|
+
#
|
362
|
+
# Returns the placeholder'd String data.
|
363
|
+
def extract_code(data)
|
364
|
+
data.gsub!(/^([ \t]*)``` ?([^\r\n]+)?\r?\n(.+?)\r?\n\1```\r?$/m) do
|
365
|
+
id = Digest::SHA1.hexdigest("#{$2}.#{$3}")
|
366
|
+
cached = check_cache(:code, id)
|
367
|
+
@codemap[id] = cached ?
|
368
|
+
{ :output => cached } :
|
369
|
+
{ :lang => $2, :code => $3, :indent => $1 }
|
370
|
+
"#{$1}#{id}" # print the SHA1 ID with the proper indentation
|
371
|
+
end
|
372
|
+
data
|
373
|
+
end
|
374
|
+
|
375
|
+
# Remove the leading space from a code block. Leading space
|
376
|
+
# is only removed if every single line in the block has leading
|
377
|
+
# whitespace.
|
378
|
+
#
|
379
|
+
# code - The code block to remove spaces from
|
380
|
+
# regex - A regex to match whitespace
|
381
|
+
def remove_leading_space(code, regex)
|
382
|
+
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ regex }
|
383
|
+
code.gsub!(regex, '')
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
# Process all code from the codemap and replace the placeholders with the
|
388
|
+
# final HTML.
|
389
|
+
#
|
390
|
+
# data - The String data (with placeholders).
|
391
|
+
# encoding - Encoding Constant or String.
|
392
|
+
#
|
393
|
+
# Returns the marked up String data.
|
394
|
+
def process_code(data, encoding = nil)
|
395
|
+
return data if data.nil? || data.size.zero? || @codemap.size.zero?
|
396
|
+
|
397
|
+
blocks = []
|
398
|
+
@codemap.each do |id, spec|
|
399
|
+
next if spec[:output] # cached
|
400
|
+
|
401
|
+
code = spec[:code]
|
402
|
+
|
403
|
+
remove_leading_space(code, /^#{spec[:indent]}/m)
|
404
|
+
remove_leading_space(code, /^( |\t)/m)
|
405
|
+
|
406
|
+
blocks << [spec[:lang], code]
|
407
|
+
end
|
408
|
+
|
409
|
+
highlighted = begin
|
410
|
+
encoding ||= 'utf-8'
|
411
|
+
blocks.map { |lang, code|
|
412
|
+
Pygments.highlight(code, :lexer => lang, :options => {:encoding => encoding.to_s})
|
413
|
+
}
|
414
|
+
rescue ::RubyPython::PythonError
|
415
|
+
[]
|
416
|
+
end
|
417
|
+
|
418
|
+
@codemap.each do |id, spec|
|
419
|
+
body = spec[:output] || begin
|
420
|
+
if (body = highlighted.shift.to_s).size > 0
|
421
|
+
update_cache(:code, id, body)
|
422
|
+
body
|
423
|
+
else
|
424
|
+
"<pre><code>#{CGI.escapeHTML(spec[:code])}</code></pre>"
|
425
|
+
end
|
426
|
+
end
|
427
|
+
data.gsub!(id, body)
|
428
|
+
end
|
429
|
+
|
430
|
+
data
|
431
|
+
end
|
432
|
+
|
433
|
+
#########################################################################
|
434
|
+
#
|
435
|
+
# Sequence Diagrams
|
436
|
+
#
|
437
|
+
#########################################################################
|
438
|
+
|
439
|
+
# Extract all sequence diagram blocks into the wsdmap and replace with
|
440
|
+
# placeholders.
|
441
|
+
#
|
442
|
+
# data - The raw String data.
|
443
|
+
#
|
444
|
+
# Returns the placeholder'd String data.
|
445
|
+
def extract_wsd(data)
|
446
|
+
data.gsub(/^\{\{\{ ?(.+?)\r?\n(.+?)\r?\n\}\}\}\r?$/m) do
|
447
|
+
id = Digest::SHA1.hexdigest($2)
|
448
|
+
@wsdmap[id] = { :style => $1, :code => $2 }
|
449
|
+
id
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
# Process all diagrams from the wsdmap and replace the placeholders with
|
454
|
+
# the final HTML.
|
455
|
+
#
|
456
|
+
# data - The String data (with placeholders).
|
457
|
+
#
|
458
|
+
# Returns the marked up String data.
|
459
|
+
def process_wsd(data)
|
460
|
+
@wsdmap.each do |id, spec|
|
461
|
+
style = spec[:style]
|
462
|
+
code = spec[:code]
|
463
|
+
data.gsub!(id, Gollum::WebSequenceDiagram.new(code, style).to_tag)
|
464
|
+
end
|
465
|
+
data
|
466
|
+
end
|
467
|
+
|
468
|
+
# Hook for getting the formatted value of extracted tag data.
|
469
|
+
#
|
470
|
+
# type - Symbol value identifying what type of data is being extracted.
|
471
|
+
# id - String SHA1 hash of original extracted tag data.
|
472
|
+
#
|
473
|
+
# Returns the String cached formatted data, or nil.
|
474
|
+
def check_cache(type, id)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Hook for caching the formatted value of extracted tag data.
|
478
|
+
#
|
479
|
+
# type - Symbol value identifying what type of data is being extracted.
|
480
|
+
# id - String SHA1 hash of original extracted tag data.
|
481
|
+
# data - The String formatted value to be cached.
|
482
|
+
#
|
483
|
+
# Returns nothing.
|
484
|
+
def update_cache(type, id, data)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
MarkupGFM = Markup
|
489
|
+
end
|