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
data/lib/gollum/page.rb
ADDED
@@ -0,0 +1,430 @@
|
|
1
|
+
module Gollum
|
2
|
+
class Page
|
3
|
+
include Pagination
|
4
|
+
|
5
|
+
Wiki.page_class = self
|
6
|
+
|
7
|
+
VALID_PAGE_RE = /^(.+)\.(md|mkdn?|mdown|markdown|textile|rdoc|org|creole|re?st(\.txt)?|asciidoc|pod|(media)?wiki)$/i
|
8
|
+
FORMAT_NAMES = { :markdown => "Markdown",
|
9
|
+
:textile => "Textile",
|
10
|
+
:rdoc => "RDoc",
|
11
|
+
:org => "Org-mode",
|
12
|
+
:creole => "Creole",
|
13
|
+
:rest => "reStructuredText",
|
14
|
+
:asciidoc => "AsciiDoc",
|
15
|
+
:mediawiki => "MediaWiki",
|
16
|
+
:pod => "Pod" }
|
17
|
+
|
18
|
+
# Sets a Boolean determing whether this page is a historical version.
|
19
|
+
#
|
20
|
+
# Returns nothing.
|
21
|
+
attr_writer :historical
|
22
|
+
|
23
|
+
# Checks if a filename has a valid extension understood by GitHub::Markup.
|
24
|
+
#
|
25
|
+
# filename - String filename, like "Home.md".
|
26
|
+
#
|
27
|
+
# Returns the matching String basename of the file without the extension.
|
28
|
+
def self.valid_filename?(filename)
|
29
|
+
filename && filename.to_s =~ VALID_PAGE_RE && $1
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks if a filename has a valid extension understood by GitHub::Markup.
|
33
|
+
# Also, checks if the filename has no "_" in the front (such as
|
34
|
+
# _Footer.md).
|
35
|
+
#
|
36
|
+
# filename - String filename, like "Home.md".
|
37
|
+
#
|
38
|
+
# Returns the matching String basename of the file without the extension.
|
39
|
+
def self.valid_page_name?(filename)
|
40
|
+
match = valid_filename?(filename)
|
41
|
+
filename =~ /^_/ ? false : match
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: The format of a given filename.
|
45
|
+
#
|
46
|
+
# filename - The String filename.
|
47
|
+
#
|
48
|
+
# Returns the Symbol format of the page. One of:
|
49
|
+
# [ :markdown | :textile | :rdoc | :org | :rest | :asciidoc | :pod |
|
50
|
+
# :roff ]
|
51
|
+
def self.format_for(filename)
|
52
|
+
case filename.to_s
|
53
|
+
when /\.(md|mkdn?|mdown|markdown)$/i
|
54
|
+
:markdown
|
55
|
+
when /\.(textile)$/i
|
56
|
+
:textile
|
57
|
+
when /\.(rdoc)$/i
|
58
|
+
:rdoc
|
59
|
+
when /\.(org)$/i
|
60
|
+
:org
|
61
|
+
when /\.(creole)$/i
|
62
|
+
:creole
|
63
|
+
when /\.(re?st(\.txt)?)$/i
|
64
|
+
:rest
|
65
|
+
when /\.(asciidoc)$/i
|
66
|
+
:asciidoc
|
67
|
+
when /\.(pod)$/i
|
68
|
+
:pod
|
69
|
+
when /\.(\d)$/i
|
70
|
+
:roff
|
71
|
+
when /\.(media)?wiki$/i
|
72
|
+
:mediawiki
|
73
|
+
else
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Reusable filter to turn a filename (without path) into a canonical name.
|
79
|
+
# Strips extension, converts dashes to spaces.
|
80
|
+
#
|
81
|
+
# Returns the filtered String.
|
82
|
+
def self.canonicalize_filename(filename)
|
83
|
+
strip_filename(filename).gsub('-', ' ')
|
84
|
+
end
|
85
|
+
|
86
|
+
# Reusable filter to strip extension and path from filename
|
87
|
+
#
|
88
|
+
# filename - The string path or filename to strip
|
89
|
+
#
|
90
|
+
# Returns the stripped String.
|
91
|
+
def self.strip_filename(filename)
|
92
|
+
::File.basename(filename, ::File.extname(filename))
|
93
|
+
end
|
94
|
+
|
95
|
+
# Public: Initialize a page.
|
96
|
+
#
|
97
|
+
# wiki - The Gollum::Wiki in question.
|
98
|
+
#
|
99
|
+
# Returns a newly initialized Gollum::Page.
|
100
|
+
def initialize(wiki)
|
101
|
+
@wiki = wiki
|
102
|
+
@blob = @footer = @sidebar = nil
|
103
|
+
end
|
104
|
+
|
105
|
+
# Public: The on-disk filename of the page including extension.
|
106
|
+
#
|
107
|
+
# Returns the String name.
|
108
|
+
def filename
|
109
|
+
@blob && @blob.name
|
110
|
+
end
|
111
|
+
|
112
|
+
# Public: The on-disk filename of the page with extension stripped.
|
113
|
+
#
|
114
|
+
# Returns the String name.
|
115
|
+
def filename_stripped
|
116
|
+
self.class.strip_filename(filename)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Public: The canonical page name without extension, and dashes converted
|
120
|
+
# to spaces.
|
121
|
+
#
|
122
|
+
# Returns the String name.
|
123
|
+
def name
|
124
|
+
self.class.canonicalize_filename(filename)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Public: If the first element of a formatted page is an <h1> tag it can
|
128
|
+
# be considered the title of the page and used in the display. If the
|
129
|
+
# first element is NOT an <h1> tag, the title will be constructed from the
|
130
|
+
# filename by stripping the extension and replacing any dashes with
|
131
|
+
# spaces.
|
132
|
+
#
|
133
|
+
# Returns the fully sanitized String title.
|
134
|
+
def title
|
135
|
+
doc = Nokogiri::HTML(%{<div id="gollum-root">} + self.formatted_data + %{</div>})
|
136
|
+
|
137
|
+
header =
|
138
|
+
case self.format
|
139
|
+
when :asciidoc
|
140
|
+
doc.css("div#gollum-root > div#header > h1:first-child")
|
141
|
+
when :org
|
142
|
+
doc.css("div#gollum-root > p.title:first-child")
|
143
|
+
when :pod
|
144
|
+
doc.css("div#gollum-root > a.dummyTopAnchor:first-child + h1")
|
145
|
+
when :rest
|
146
|
+
doc.css("div#gollum-root > div > div > h1:first-child")
|
147
|
+
else
|
148
|
+
doc.css("div#gollum-root > h1:first-child")
|
149
|
+
end
|
150
|
+
|
151
|
+
if !header.empty?
|
152
|
+
Sanitize.clean(header.to_html)
|
153
|
+
else
|
154
|
+
Sanitize.clean(name)
|
155
|
+
end.strip
|
156
|
+
end
|
157
|
+
|
158
|
+
# Public: The path of the page within the repo.
|
159
|
+
#
|
160
|
+
# Returns the String path.
|
161
|
+
attr_reader :path
|
162
|
+
|
163
|
+
# Public: The raw contents of the page.
|
164
|
+
#
|
165
|
+
# Returns the String data.
|
166
|
+
def raw_data
|
167
|
+
@blob && @blob.data
|
168
|
+
end
|
169
|
+
|
170
|
+
# Public: A text data encoded in specified encoding.
|
171
|
+
#
|
172
|
+
# encoding - An Encoding or nil
|
173
|
+
#
|
174
|
+
# Returns a character encoding aware String.
|
175
|
+
def text_data(encoding=nil)
|
176
|
+
if raw_data.respond_to?(:encoding)
|
177
|
+
raw_data.force_encoding(encoding || Encoding::UTF_8)
|
178
|
+
else
|
179
|
+
raw_data
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Public: The formatted contents of the page.
|
184
|
+
#
|
185
|
+
# encoding - Encoding Constant or String.
|
186
|
+
#
|
187
|
+
# Returns the String data.
|
188
|
+
def formatted_data(encoding = nil, &block)
|
189
|
+
@blob && markup_class.render(historical?, encoding, &block)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Public: The format of the page.
|
193
|
+
#
|
194
|
+
# Returns the Symbol format of the page. One of:
|
195
|
+
# [ :markdown | :textile | :rdoc | :org | :rest | :asciidoc | :pod |
|
196
|
+
# :roff ]
|
197
|
+
def format
|
198
|
+
self.class.format_for(@blob.name)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Gets the Gollum::Markup instance that will render this page's content.
|
202
|
+
#
|
203
|
+
# Returns a Gollum::Markup instance.
|
204
|
+
def markup_class
|
205
|
+
@markup_class ||= @wiki.markup_classes[format].new(self)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Public: The current version of the page.
|
209
|
+
#
|
210
|
+
# Returns the Grit::Commit.
|
211
|
+
attr_reader :version
|
212
|
+
|
213
|
+
# Public: All of the versions that have touched the Page.
|
214
|
+
#
|
215
|
+
# options - The options Hash:
|
216
|
+
# :page - The Integer page number (default: 1).
|
217
|
+
# :per_page - The Integer max count of items to return.
|
218
|
+
# :follow - Follow's a file across renames, but falls back
|
219
|
+
# to a slower Grit native call. (default: false)
|
220
|
+
#
|
221
|
+
# Returns an Array of Grit::Commit.
|
222
|
+
def versions(options = {})
|
223
|
+
if options[:follow]
|
224
|
+
options[:pretty] = 'raw'
|
225
|
+
options.delete :max_count
|
226
|
+
options.delete :skip
|
227
|
+
log = @wiki.repo.git.native "log", options, @wiki.ref, "--", @path
|
228
|
+
Grit::Commit.list_from_string(@wiki.repo, log)
|
229
|
+
else
|
230
|
+
@wiki.repo.log(@wiki.ref, @path, log_pagination_options(options))
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Public: The footer Page.
|
235
|
+
#
|
236
|
+
# Returns the footer Page or nil if none exists.
|
237
|
+
def footer
|
238
|
+
@footer ||= find_sub_page(:footer)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Public: The sidebar Page.
|
242
|
+
#
|
243
|
+
# Returns the sidebar Page or nil if none exists.
|
244
|
+
def sidebar
|
245
|
+
@sidebar ||= find_sub_page(:sidebar)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Gets a Boolean determining whether this page is a historical version.
|
249
|
+
# Historical pages are pulled using exact SHA hashes and format all links
|
250
|
+
# with rel="nofollow"
|
251
|
+
#
|
252
|
+
# Returns true if the page is pulled from a named branch or tag, or false.
|
253
|
+
def historical?
|
254
|
+
!!@historical
|
255
|
+
end
|
256
|
+
|
257
|
+
#########################################################################
|
258
|
+
#
|
259
|
+
# Class Methods
|
260
|
+
#
|
261
|
+
#########################################################################
|
262
|
+
|
263
|
+
# Convert a human page name into a canonical page name.
|
264
|
+
#
|
265
|
+
# name - The String human page name.
|
266
|
+
# char_white_sub - Substitution for whitespace
|
267
|
+
# char_other_sub - Substitution for other special chars
|
268
|
+
#
|
269
|
+
# Examples
|
270
|
+
#
|
271
|
+
# Page.cname("Bilbo Baggins")
|
272
|
+
# # => 'Bilbo-Baggins'
|
273
|
+
#
|
274
|
+
# Page.cname("Bilbo Baggins",'_')
|
275
|
+
# # => 'Bilbo_Baggins'
|
276
|
+
#
|
277
|
+
# Returns the String canonical name.
|
278
|
+
def self.cname(name, char_white_sub = '-', char_other_sub = '-')
|
279
|
+
name.respond_to?(:gsub) ?
|
280
|
+
name.gsub(%r{\s},char_white_sub).gsub(%r{[/<>+]}, char_other_sub) :
|
281
|
+
''
|
282
|
+
end
|
283
|
+
|
284
|
+
# Convert a format Symbol into an extension String.
|
285
|
+
#
|
286
|
+
# format - The format Symbol.
|
287
|
+
#
|
288
|
+
# Returns the String extension (no leading period).
|
289
|
+
def self.format_to_ext(format)
|
290
|
+
case format
|
291
|
+
when :markdown then 'md'
|
292
|
+
when :textile then 'textile'
|
293
|
+
when :rdoc then 'rdoc'
|
294
|
+
when :org then 'org'
|
295
|
+
when :creole then 'creole'
|
296
|
+
when :rest then 'rest'
|
297
|
+
when :asciidoc then 'asciidoc'
|
298
|
+
when :pod then 'pod'
|
299
|
+
when :mediawiki then 'mediawiki'
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
#########################################################################
|
304
|
+
#
|
305
|
+
# Internal Methods
|
306
|
+
#
|
307
|
+
#########################################################################
|
308
|
+
|
309
|
+
# The underlying wiki repo.
|
310
|
+
#
|
311
|
+
# Returns the Gollum::Wiki containing the page.
|
312
|
+
attr_reader :wiki
|
313
|
+
|
314
|
+
# Set the Grit::Commit version of the page.
|
315
|
+
#
|
316
|
+
# Returns nothing.
|
317
|
+
attr_writer :version
|
318
|
+
|
319
|
+
# Find a page in the given Gollum repo.
|
320
|
+
#
|
321
|
+
# name - The human or canonical String page name to find.
|
322
|
+
# version - The String version ID to find.
|
323
|
+
#
|
324
|
+
# Returns a Gollum::Page or nil if the page could not be found.
|
325
|
+
def find(name, version)
|
326
|
+
map = @wiki.tree_map_for(version.to_s)
|
327
|
+
if page = find_page_in_tree(map, name)
|
328
|
+
page.version = version.is_a?(Grit::Commit) ?
|
329
|
+
version : @wiki.commit_for(version)
|
330
|
+
page.historical = page.version.to_s == version.to_s
|
331
|
+
page
|
332
|
+
end
|
333
|
+
rescue Grit::GitRuby::Repository::NoSuchShaFound
|
334
|
+
end
|
335
|
+
|
336
|
+
# Find a page in a given tree.
|
337
|
+
#
|
338
|
+
# map - The Array tree map from Wiki#tree_map.
|
339
|
+
# name - The canonical String page name.
|
340
|
+
# checked_dir - Optional String of the directory a matching page needs
|
341
|
+
# to be in. The string should
|
342
|
+
#
|
343
|
+
# Returns a Gollum::Page or nil if the page could not be found.
|
344
|
+
def find_page_in_tree(map, name, checked_dir = nil)
|
345
|
+
return nil if !map || name.to_s.empty?
|
346
|
+
if checked_dir = BlobEntry.normalize_dir(checked_dir)
|
347
|
+
checked_dir.downcase!
|
348
|
+
end
|
349
|
+
|
350
|
+
map.each do |entry|
|
351
|
+
next if entry.name.to_s.empty?
|
352
|
+
next unless checked_dir.nil? || entry.dir.downcase == checked_dir
|
353
|
+
next unless page_match(name, entry.name)
|
354
|
+
return entry.page(@wiki, @version)
|
355
|
+
end
|
356
|
+
|
357
|
+
return nil # nothing was found
|
358
|
+
end
|
359
|
+
|
360
|
+
# Populate the Page with information from the Blob.
|
361
|
+
#
|
362
|
+
# blob - The Grit::Blob that contains the info.
|
363
|
+
# path - The String directory path of the page file.
|
364
|
+
#
|
365
|
+
# Returns the populated Gollum::Page.
|
366
|
+
def populate(blob, path=nil)
|
367
|
+
@blob = blob
|
368
|
+
@path = "#{path}/#{blob.name}"[1..-1]
|
369
|
+
self
|
370
|
+
end
|
371
|
+
|
372
|
+
# The full directory path for the given tree.
|
373
|
+
#
|
374
|
+
# treemap - The Hash treemap containing parentage information.
|
375
|
+
# tree - The Grit::Tree for which to compute the path.
|
376
|
+
#
|
377
|
+
# Returns the String path.
|
378
|
+
def tree_path(treemap, tree)
|
379
|
+
if ptree = treemap[tree]
|
380
|
+
tree_path(treemap, ptree) + '/' + tree.name
|
381
|
+
else
|
382
|
+
''
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# Compare the canonicalized versions of the two names.
|
387
|
+
#
|
388
|
+
# name - The human or canonical String page name.
|
389
|
+
# filename - the String filename on disk (including extension).
|
390
|
+
#
|
391
|
+
# Returns a Boolean.
|
392
|
+
def page_match(name, filename)
|
393
|
+
if match = self.class.valid_filename?(filename)
|
394
|
+
@wiki.ws_subs.each do |sub|
|
395
|
+
return true if Page.cname(name).downcase == Page.cname(match, sub).downcase
|
396
|
+
end
|
397
|
+
end
|
398
|
+
false
|
399
|
+
end
|
400
|
+
|
401
|
+
# Loads a sub page. Sub page nanes (footers) are prefixed with
|
402
|
+
# an underscore to distinguish them from other Pages.
|
403
|
+
#
|
404
|
+
# name - String page name.
|
405
|
+
#
|
406
|
+
# Returns the Page or nil if none exists.
|
407
|
+
def find_sub_page(name)
|
408
|
+
return nil unless self.version
|
409
|
+
return nil if self.filename =~ /^_/
|
410
|
+
name = "_#{name.to_s.capitalize}"
|
411
|
+
return nil if page_match(name, self.filename)
|
412
|
+
|
413
|
+
dirs = self.path.split('/')
|
414
|
+
dirs.pop
|
415
|
+
map = @wiki.tree_map_for(self.version.id)
|
416
|
+
while !dirs.empty?
|
417
|
+
if page = find_page_in_tree(map, name, dirs.join('/'))
|
418
|
+
return page
|
419
|
+
end
|
420
|
+
dirs.pop
|
421
|
+
end
|
422
|
+
|
423
|
+
find_page_in_tree(map, name, '')
|
424
|
+
end
|
425
|
+
|
426
|
+
def inspect
|
427
|
+
%(#<#{self.class.name}:#{object_id} #{name} (#{format}) @wiki=#{@wiki.repo.path.inspect}>)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Gollum
|
2
|
+
module Pagination
|
3
|
+
def self.included(klass)
|
4
|
+
klass.extend ClassMethods
|
5
|
+
class << klass
|
6
|
+
# Default Integer max count of items to return in git commands.
|
7
|
+
attr_accessor :per_page
|
8
|
+
end
|
9
|
+
klass.per_page = 30
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# Turns a page number into an offset number for the git skip option.
|
14
|
+
#
|
15
|
+
# page - Integer page number.
|
16
|
+
#
|
17
|
+
# Returns an Integer.
|
18
|
+
def page_to_skip(page)
|
19
|
+
([1, page.to_i].max - 1) * per_page
|
20
|
+
end
|
21
|
+
|
22
|
+
# Fills in git-specific options for the log command using simple
|
23
|
+
# pagination options.
|
24
|
+
#
|
25
|
+
# options - Hash of options:
|
26
|
+
# page - Optional Integer page number (default: 1)
|
27
|
+
# per_page - Optional Integer max count of items to return.
|
28
|
+
# Defaults to #per_class class method.
|
29
|
+
#
|
30
|
+
# Returns Hash with :max_count and :skip keys.
|
31
|
+
def log_pagination_options(options = {})
|
32
|
+
skip = page_to_skip(options.delete(:page))
|
33
|
+
options[:max_count] = [options.delete(:per_page).to_i, per_page].max
|
34
|
+
options[:skip] = skip if skip > 0
|
35
|
+
options
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Turns a page number into an offset number for the git skip option.
|
40
|
+
#
|
41
|
+
# page - Integer page number.
|
42
|
+
#
|
43
|
+
# Returns an Integer.
|
44
|
+
def page_to_skip(page)
|
45
|
+
self.class.page_to_skip(page)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Fills in git-specific options for the log command using simple
|
49
|
+
# pagination options.
|
50
|
+
#
|
51
|
+
# options - Hash of options:
|
52
|
+
# page - Optional Integer page number (default: 1)
|
53
|
+
# per_page - Optional Integer max count of items to return.
|
54
|
+
# Defaults to #per_class class method.
|
55
|
+
#
|
56
|
+
# Returns Hash with :max_count and :skip keys.
|
57
|
+
def log_pagination_options(options = {})
|
58
|
+
self.class.log_pagination_options(options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|