gollum-lib 4.0.3-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 +15 -0
- data/Gemfile +3 -0
- data/HISTORY.md +11 -0
- data/LICENSE +21 -0
- data/README.md +286 -0
- data/Rakefile +187 -0
- data/docs/sanitization.md +33 -0
- data/gemspec.rb +100 -0
- data/gollum-lib.gemspec +4 -0
- data/gollum-lib_java.gemspec +4 -0
- data/lib/gollum-lib.rb +64 -0
- data/lib/gollum-lib/blob_entry.rb +95 -0
- data/lib/gollum-lib/committer.rb +243 -0
- data/lib/gollum-lib/file.rb +158 -0
- data/lib/gollum-lib/file_view.rb +155 -0
- data/lib/gollum-lib/filter.rb +78 -0
- data/lib/gollum-lib/filter/code.rb +145 -0
- data/lib/gollum-lib/filter/macro.rb +57 -0
- data/lib/gollum-lib/filter/metadata.rb +29 -0
- data/lib/gollum-lib/filter/plain_text.rb +16 -0
- data/lib/gollum-lib/filter/remote_code.rb +63 -0
- data/lib/gollum-lib/filter/render.rb +20 -0
- data/lib/gollum-lib/filter/sanitize.rb +18 -0
- data/lib/gollum-lib/filter/tags.rb +320 -0
- data/lib/gollum-lib/filter/toc.rb +109 -0
- data/lib/gollum-lib/filter/wsd.rb +54 -0
- data/lib/gollum-lib/git_access.rb +247 -0
- data/lib/gollum-lib/gitcode.rb +48 -0
- data/lib/gollum-lib/helpers.rb +13 -0
- data/lib/gollum-lib/hook.rb +35 -0
- data/lib/gollum-lib/macro.rb +43 -0
- data/lib/gollum-lib/macro/all_pages.rb +11 -0
- data/lib/gollum-lib/markup.rb +197 -0
- data/lib/gollum-lib/markups.rb +20 -0
- data/lib/gollum-lib/page.rb +491 -0
- data/lib/gollum-lib/pagination.rb +62 -0
- data/lib/gollum-lib/sanitization.rb +176 -0
- data/lib/gollum-lib/version.rb +5 -0
- data/lib/gollum-lib/wiki.rb +925 -0
- data/licenses/licenses.txt +6 -0
- metadata +410 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
module Gollum
|
3
|
+
class Hook
|
4
|
+
@hooks = {}
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def register(type, id, &block)
|
8
|
+
type_hooks = @hooks[type] ||= {}
|
9
|
+
type_hooks[id] = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def unregister(type, id)
|
13
|
+
type_hooks = @hooks[type]
|
14
|
+
if type_hooks
|
15
|
+
type_hooks.delete(id)
|
16
|
+
@hooks.delete(type) if type_hooks.empty?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(type, id)
|
21
|
+
@hooks.fetch(type, {})[id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute(type, *args)
|
25
|
+
type_hooks = @hooks[type]
|
26
|
+
if type_hooks
|
27
|
+
type_hooks.each_value do |block|
|
28
|
+
block.call(*args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Gollum
|
2
|
+
class Macro
|
3
|
+
# Find the macro named, create an instance of that, and return it
|
4
|
+
def self.instance(macro_name, wiki, page)
|
5
|
+
begin
|
6
|
+
self.const_get(macro_name).new(wiki, page)
|
7
|
+
rescue NameError
|
8
|
+
Unknown_Macro.new(macro_name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(wiki, page)
|
13
|
+
@wiki = wiki
|
14
|
+
@page = page
|
15
|
+
end
|
16
|
+
|
17
|
+
def render(*_args)
|
18
|
+
raise ArgumentError,
|
19
|
+
"#{self.class} does not implement #render. "+
|
20
|
+
"This is a bug in #{self.class}."
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def html_error(s)
|
25
|
+
"<p class=\"gollum-error\">#{s}</p>"
|
26
|
+
end
|
27
|
+
|
28
|
+
# The special class we reserve for only the finest of screwups. The
|
29
|
+
# underscore is to make sure nobody can define a real, callable macro
|
30
|
+
# with the same name, because that would be... exciting.
|
31
|
+
class Unknown_Macro < Macro
|
32
|
+
def initialize(macro_name)
|
33
|
+
@macro_name = macro_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def render(*_args)
|
37
|
+
"!!!Unknown macro: #{@macro_name}!!!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Dir[File.expand_path('../macro/*.rb', __FILE__)].each { |f| require f }
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'cgi'
|
4
|
+
require 'rouge'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
require File.expand_path '../helpers', __FILE__
|
8
|
+
|
9
|
+
# Use pygments if it's installed
|
10
|
+
begin
|
11
|
+
require 'pygments'
|
12
|
+
Pygments.start
|
13
|
+
rescue Exception
|
14
|
+
end
|
15
|
+
|
16
|
+
module Gollum
|
17
|
+
|
18
|
+
class Markup
|
19
|
+
include Helpers
|
20
|
+
|
21
|
+
@formats = {}
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Only use the formats that are specified in config.rb
|
26
|
+
def formats
|
27
|
+
if defined? Gollum::Page::FORMAT_NAMES
|
28
|
+
@formats.select { |_, value| Gollum::Page::FORMAT_NAMES.values.include? value[:name] }
|
29
|
+
else
|
30
|
+
@formats
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Register a file extension and associated markup type
|
35
|
+
#
|
36
|
+
# ext - The file extension
|
37
|
+
# name - The name of the markup type
|
38
|
+
# options - Hash of options:
|
39
|
+
# regexp - Regexp to match against.
|
40
|
+
# Defaults to exact match of ext.
|
41
|
+
#
|
42
|
+
# If given a block, that block will be registered with GitHub::Markup to
|
43
|
+
# render any matching pages
|
44
|
+
def register(ext, name, options = {}, &block)
|
45
|
+
regexp = options[:regexp] || Regexp.new(ext.to_s)
|
46
|
+
@formats[ext] = { :name => name, :regexp => regexp }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_accessor :toc
|
51
|
+
attr_accessor :metadata
|
52
|
+
attr_reader :encoding
|
53
|
+
attr_reader :sanitize
|
54
|
+
attr_reader :format
|
55
|
+
attr_reader :wiki
|
56
|
+
attr_reader :page
|
57
|
+
attr_reader :parent_page
|
58
|
+
attr_reader :sub_page
|
59
|
+
attr_reader :name
|
60
|
+
attr_reader :include_levels
|
61
|
+
attr_reader :to_xml_opts
|
62
|
+
attr_reader :dir
|
63
|
+
|
64
|
+
# Initialize a new Markup object.
|
65
|
+
#
|
66
|
+
# page - The Gollum::Page.
|
67
|
+
#
|
68
|
+
# Returns a new Gollum::Markup object, ready for rendering.
|
69
|
+
def initialize(page)
|
70
|
+
if page
|
71
|
+
@wiki = page.wiki
|
72
|
+
@name = page.filename
|
73
|
+
@data = page.text_data
|
74
|
+
@version = page.version.id if page.version
|
75
|
+
@format = page.format
|
76
|
+
@sub_page = page.sub_page
|
77
|
+
@parent_page = page.parent_page
|
78
|
+
@page = page
|
79
|
+
@dir = ::File.dirname(page.path)
|
80
|
+
end
|
81
|
+
@metadata = nil
|
82
|
+
@to_xml_opts = { :save_with => Nokogiri::XML::Node::SaveOptions::DEFAULT_XHTML ^ 1, :indent => 0, :encoding => 'UTF-8' }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Render data using default chain in the target format.
|
86
|
+
#
|
87
|
+
# data - the data to render
|
88
|
+
# format - format to use as a symbol
|
89
|
+
# name - name using the extension of the format
|
90
|
+
#
|
91
|
+
# Returns the processed data
|
92
|
+
def render_default data, format=:markdown, name='render_default.md'
|
93
|
+
# set instance vars so we're able to render data without a wiki or page.
|
94
|
+
@format = format
|
95
|
+
@name = name
|
96
|
+
|
97
|
+
chain = [:Metadata, :PlainText, :TOC, :RemoteCode, :Code, :Sanitize, :WSD, :Tags, :Render]
|
98
|
+
|
99
|
+
filter_chain = chain.map do |r|
|
100
|
+
Gollum::Filter.const_get(r).new(self)
|
101
|
+
end
|
102
|
+
|
103
|
+
process_chain data, filter_chain
|
104
|
+
end
|
105
|
+
|
106
|
+
# Process the filter chain
|
107
|
+
#
|
108
|
+
# data - the data to send through the chain
|
109
|
+
# filter_chain - the chain to process
|
110
|
+
#
|
111
|
+
# Returns the formatted data
|
112
|
+
def process_chain(data, filter_chain)
|
113
|
+
# First we extract the data through the chain...
|
114
|
+
filter_chain.each do |filter|
|
115
|
+
data = filter.extract(data)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Then we process the data through the chain *backwards*
|
119
|
+
filter_chain.reverse.each do |filter|
|
120
|
+
data = filter.process(data)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Finally, a little bit of cleanup, just because
|
124
|
+
data.gsub!(/<p><\/p>/) do
|
125
|
+
''
|
126
|
+
end
|
127
|
+
|
128
|
+
data
|
129
|
+
end
|
130
|
+
|
131
|
+
# Render the content with Gollum wiki syntax on top of the file's own
|
132
|
+
# markup language.
|
133
|
+
#
|
134
|
+
# no_follow - Boolean that determines if rel="nofollow" is added to all
|
135
|
+
# <a> tags.
|
136
|
+
# encoding - Encoding Constant or String.
|
137
|
+
#
|
138
|
+
# Returns the formatted String content.
|
139
|
+
def render(no_follow = false, encoding = nil, include_levels = 10)
|
140
|
+
@sanitize = no_follow ?
|
141
|
+
@wiki.history_sanitizer :
|
142
|
+
@wiki.sanitizer
|
143
|
+
|
144
|
+
@encoding = encoding
|
145
|
+
@include_levels = include_levels
|
146
|
+
|
147
|
+
data = @data.dup
|
148
|
+
filter_chain = @wiki.filter_chain.map do |r|
|
149
|
+
Gollum::Filter.const_get(r).new(self)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Since the last 'extract' action in our chain *should* be the markup
|
153
|
+
# to HTML converter, we now have HTML which we can parse and yield, for
|
154
|
+
# anyone who wants it
|
155
|
+
if block_given?
|
156
|
+
yield Nokogiri::HTML::DocumentFragment.parse(data)
|
157
|
+
end
|
158
|
+
|
159
|
+
process_chain data, filter_chain
|
160
|
+
end
|
161
|
+
|
162
|
+
# Find the given file in the repo.
|
163
|
+
#
|
164
|
+
# name - The String absolute or relative path of the file.
|
165
|
+
#
|
166
|
+
# Returns the Gollum::File or nil if none was found.
|
167
|
+
def find_file(name, version=@version)
|
168
|
+
if name =~ /^\//
|
169
|
+
@wiki.file(name[1..-1], version)
|
170
|
+
else
|
171
|
+
path = @dir == '.' ? name : ::File.join(@dir, name)
|
172
|
+
@wiki.file(path, version)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Hook for getting the formatted value of extracted tag data.
|
177
|
+
#
|
178
|
+
# type - Symbol value identifying what type of data is being extracted.
|
179
|
+
# id - String SHA1 hash of original extracted tag data.
|
180
|
+
#
|
181
|
+
# Returns the String cached formatted data, or nil.
|
182
|
+
def check_cache(type, id)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Hook for caching the formatted value of extracted tag data.
|
186
|
+
#
|
187
|
+
# type - Symbol value identifying what type of data is being extracted.
|
188
|
+
# id - String SHA1 hash of original extracted tag data.
|
189
|
+
# data - The String formatted value to be cached.
|
190
|
+
#
|
191
|
+
# Returns nothing.
|
192
|
+
def update_cache(type, id, data)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
MarkupGFM = Markup
|
197
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
module Gollum
|
3
|
+
class Markup
|
4
|
+
|
5
|
+
GitHub::Markup::Markdown::MARKDOWN_GEMS['kramdown'] = proc { |content|
|
6
|
+
Kramdown::Document.new(content, :auto_ids => false, :input => "markdown").to_html
|
7
|
+
}
|
8
|
+
|
9
|
+
register(:markdown, "Markdown", :regexp => /md|mkdn?|mdown|markdown/)
|
10
|
+
register(:textile, "Textile")
|
11
|
+
register(:rdoc, "RDoc")
|
12
|
+
register(:org, "Org-mode")
|
13
|
+
register(:creole, "Creole")
|
14
|
+
register(:rest, "reStructuredText", :regexp => /re?st(\.txt)?/)
|
15
|
+
register(:asciidoc, "AsciiDoc")
|
16
|
+
register(:mediawiki, "MediaWiki", :regexp => /(media)?wiki/)
|
17
|
+
register(:pod, "Pod")
|
18
|
+
register(:txt, "Plain Text")
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,491 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
module Gollum
|
3
|
+
class Page
|
4
|
+
include Pagination
|
5
|
+
|
6
|
+
Wiki.page_class = self
|
7
|
+
|
8
|
+
# Sets a Boolean determing whether this page is a historical version.
|
9
|
+
#
|
10
|
+
# Returns nothing.
|
11
|
+
attr_writer :historical
|
12
|
+
|
13
|
+
# Parent page if this is a sub page
|
14
|
+
#
|
15
|
+
# Returns a Page
|
16
|
+
attr_accessor :parent_page
|
17
|
+
|
18
|
+
|
19
|
+
# Checks a filename against the registered markup extensions
|
20
|
+
#
|
21
|
+
# filename - String filename, like "Home.md"
|
22
|
+
#
|
23
|
+
# Returns e.g. ["Home", :markdown], or [] if the extension is unregistered
|
24
|
+
def self.parse_filename(filename)
|
25
|
+
return [] unless filename =~ /^(.+)\.([a-zA-Z]\w*)$/i
|
26
|
+
pref, ext = $1, $2
|
27
|
+
|
28
|
+
Gollum::Markup.formats.each_pair do |name, format|
|
29
|
+
return [pref, name] if ext =~ format[:regexp]
|
30
|
+
end
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks if a filename has a valid, registered extension
|
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_filename?(filename)
|
40
|
+
self.parse_filename(filename).first
|
41
|
+
end
|
42
|
+
|
43
|
+
# Checks if a filename has a valid extension understood by GitHub::Markup.
|
44
|
+
# Also, checks if the filename has no "_" in the front (such as
|
45
|
+
# _Footer.md).
|
46
|
+
#
|
47
|
+
# filename - String filename, like "Home.md".
|
48
|
+
#
|
49
|
+
# Returns the matching String basename of the file without the extension.
|
50
|
+
def self.valid_page_name?(filename)
|
51
|
+
match = valid_filename?(filename)
|
52
|
+
filename =~ /^_/ ? false : match
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: The format of a given filename.
|
56
|
+
#
|
57
|
+
# filename - The String filename.
|
58
|
+
#
|
59
|
+
# Returns the Symbol format of the page; one of the registered format types
|
60
|
+
def self.format_for(filename)
|
61
|
+
self.parse_filename(filename).last
|
62
|
+
end
|
63
|
+
|
64
|
+
# Reusable filter to turn a filename (without path) into a canonical name.
|
65
|
+
# Strips extension, converts dashes to spaces.
|
66
|
+
#
|
67
|
+
# Returns the filtered String.
|
68
|
+
def self.canonicalize_filename(filename)
|
69
|
+
strip_filename(filename).gsub('-', ' ')
|
70
|
+
end
|
71
|
+
|
72
|
+
# Reusable filter to strip extension and path from filename
|
73
|
+
#
|
74
|
+
# filename - The string path or filename to strip
|
75
|
+
#
|
76
|
+
# Returns the stripped String.
|
77
|
+
def self.strip_filename(filename)
|
78
|
+
::File.basename(filename, ::File.extname(filename))
|
79
|
+
end
|
80
|
+
|
81
|
+
# Public: Initialize a page.
|
82
|
+
#
|
83
|
+
# wiki - The Gollum::Wiki in question.
|
84
|
+
#
|
85
|
+
# Returns a newly initialized Gollum::Page.
|
86
|
+
def initialize(wiki)
|
87
|
+
@wiki = wiki
|
88
|
+
@blob = @header = @footer = @sidebar = nil
|
89
|
+
@formatted_data = nil
|
90
|
+
@doc = nil
|
91
|
+
@parent_page = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
# Public: The on-disk filename of the page including extension.
|
95
|
+
#
|
96
|
+
# Returns the String name.
|
97
|
+
def filename
|
98
|
+
@blob && @blob.name
|
99
|
+
end
|
100
|
+
|
101
|
+
# Public: The on-disk filename of the page with extension stripped.
|
102
|
+
#
|
103
|
+
# Returns the String name.
|
104
|
+
def filename_stripped
|
105
|
+
self.class.strip_filename(filename)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Public: The canonical page name without extension, and dashes converted
|
109
|
+
# to spaces.
|
110
|
+
#
|
111
|
+
# Returns the String name.
|
112
|
+
def name
|
113
|
+
self.class.canonicalize_filename(filename)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Public: The title will be constructed from the
|
117
|
+
# filename by stripping the extension and replacing any dashes with
|
118
|
+
# spaces.
|
119
|
+
#
|
120
|
+
# Returns the fully sanitized String title.
|
121
|
+
def title
|
122
|
+
Sanitize.clean(name).strip
|
123
|
+
end
|
124
|
+
|
125
|
+
# Public: Determines if this is a sub-page
|
126
|
+
# Sub-pages have filenames beginning with an underscore
|
127
|
+
#
|
128
|
+
# Returns true or false.
|
129
|
+
def sub_page
|
130
|
+
filename =~ /^_/
|
131
|
+
end
|
132
|
+
|
133
|
+
# Public: The path of the page within the repo.
|
134
|
+
#
|
135
|
+
# Returns the String path.
|
136
|
+
attr_reader :path
|
137
|
+
|
138
|
+
# Public: The url path required to reach this page within the repo.
|
139
|
+
#
|
140
|
+
# Returns the String url_path
|
141
|
+
def url_path
|
142
|
+
path = if self.path.include?('/')
|
143
|
+
self.path.sub(/\/[^\/]+$/, '/')
|
144
|
+
else
|
145
|
+
''
|
146
|
+
end
|
147
|
+
|
148
|
+
path << Page.cname(self.name, '-', '-')
|
149
|
+
path
|
150
|
+
end
|
151
|
+
|
152
|
+
# Public: The display form of the url path required to reach this page within the repo.
|
153
|
+
#
|
154
|
+
# Returns the String url_path
|
155
|
+
def url_path_display
|
156
|
+
url_path.gsub("-", " ")
|
157
|
+
end
|
158
|
+
|
159
|
+
# Public: Defines title for page.rb
|
160
|
+
#
|
161
|
+
# Returns the String title
|
162
|
+
def url_path_title
|
163
|
+
metadata_title || url_path_display
|
164
|
+
end
|
165
|
+
|
166
|
+
# Public: Metadata title
|
167
|
+
#
|
168
|
+
# Set with <!-- --- title: New Title --> in page content
|
169
|
+
#
|
170
|
+
# Returns the String title or nil if not defined
|
171
|
+
def metadata_title
|
172
|
+
if metadata
|
173
|
+
title = metadata['title']
|
174
|
+
return title unless title.nil?
|
175
|
+
end
|
176
|
+
|
177
|
+
nil
|
178
|
+
end
|
179
|
+
|
180
|
+
# Public: The url_path, but CGI escaped.
|
181
|
+
#
|
182
|
+
# Returns the String url_path
|
183
|
+
def escaped_url_path
|
184
|
+
CGI.escape(self.url_path).gsub('%2F', '/')
|
185
|
+
end
|
186
|
+
|
187
|
+
# Public: The raw contents of the page.
|
188
|
+
#
|
189
|
+
# Returns the String data.
|
190
|
+
def raw_data
|
191
|
+
return nil unless @blob
|
192
|
+
|
193
|
+
if !@wiki.repo.bare && @blob.is_symlink
|
194
|
+
new_path = @blob.symlink_target(::File.join(@wiki.repo.path, '..', self.path))
|
195
|
+
return IO.read(new_path) if new_path
|
196
|
+
end
|
197
|
+
|
198
|
+
@blob.data
|
199
|
+
end
|
200
|
+
|
201
|
+
# Public: A text data encoded in specified encoding.
|
202
|
+
#
|
203
|
+
# encoding - An Encoding or nil
|
204
|
+
#
|
205
|
+
# Returns a character encoding aware String.
|
206
|
+
def text_data(encoding=nil)
|
207
|
+
if raw_data.respond_to?(:encoding)
|
208
|
+
raw_data.force_encoding(encoding || Encoding::UTF_8)
|
209
|
+
else
|
210
|
+
raw_data
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Public: The formatted contents of the page.
|
215
|
+
#
|
216
|
+
# encoding - Encoding Constant or String.
|
217
|
+
#
|
218
|
+
# Returns the String data.
|
219
|
+
def formatted_data(encoding = nil, include_levels = 10, &block)
|
220
|
+
return nil unless @blob
|
221
|
+
|
222
|
+
if @formatted_data && @doc then
|
223
|
+
yield @doc if block_given?
|
224
|
+
else
|
225
|
+
@formatted_data = markup_class.render(historical?, encoding, include_levels) do |doc|
|
226
|
+
@doc = doc
|
227
|
+
yield doc if block_given?
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
@formatted_data
|
232
|
+
end
|
233
|
+
|
234
|
+
# Public: The table of contents of the page.
|
235
|
+
#
|
236
|
+
# formatted_data - page already marked up in html.
|
237
|
+
#
|
238
|
+
# Returns the String data.
|
239
|
+
def toc_data()
|
240
|
+
return @parent_page.toc_data if @parent_page and @sub_page
|
241
|
+
formatted_data if markup_class.toc == nil
|
242
|
+
markup_class.toc
|
243
|
+
end
|
244
|
+
|
245
|
+
# Public: Embedded metadata.
|
246
|
+
#
|
247
|
+
# Returns Hash of metadata.
|
248
|
+
def metadata()
|
249
|
+
formatted_data if markup_class.metadata == nil
|
250
|
+
markup_class.metadata
|
251
|
+
end
|
252
|
+
|
253
|
+
# Public: The format of the page.
|
254
|
+
#
|
255
|
+
# Returns the Symbol format of the page; one of the registered format types
|
256
|
+
def format
|
257
|
+
self.class.format_for(@blob.name)
|
258
|
+
end
|
259
|
+
|
260
|
+
# Gets the Gollum::Markup instance that will render this page's content.
|
261
|
+
#
|
262
|
+
# Returns a Gollum::Markup instance.
|
263
|
+
def markup_class
|
264
|
+
@markup_class ||= @wiki.markup_classes[format].new(self)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Public: The current version of the page.
|
268
|
+
#
|
269
|
+
# Returns the Gollum::Git::Commit.
|
270
|
+
attr_reader :version
|
271
|
+
|
272
|
+
# Public: All of the versions that have touched the Page.
|
273
|
+
#
|
274
|
+
# options - The options Hash:
|
275
|
+
# :page - The Integer page number (default: 1).
|
276
|
+
# :per_page - The Integer max count of items to return.
|
277
|
+
# :follow - Follow's a file across renames, slower. (default: false)
|
278
|
+
#
|
279
|
+
# Returns an Array of Gollum::Git::Commit.
|
280
|
+
def versions(options = {})
|
281
|
+
@wiki.repo.git.versions_for_path(@path, @wiki.ref, log_pagination_options(options))
|
282
|
+
end
|
283
|
+
|
284
|
+
# Public: The first 7 characters of the current version.
|
285
|
+
#
|
286
|
+
# Returns the first 7 characters of the current version.
|
287
|
+
def version_short
|
288
|
+
version.to_s[0, 7]
|
289
|
+
end
|
290
|
+
|
291
|
+
# Public: The header Page.
|
292
|
+
#
|
293
|
+
# Returns the header Page or nil if none exists.
|
294
|
+
def header
|
295
|
+
@header ||= find_sub_page(:header)
|
296
|
+
end
|
297
|
+
|
298
|
+
# Public: The footer Page.
|
299
|
+
#
|
300
|
+
# Returns the footer Page or nil if none exists.
|
301
|
+
def footer
|
302
|
+
@footer ||= find_sub_page(:footer)
|
303
|
+
end
|
304
|
+
|
305
|
+
# Public: The sidebar Page.
|
306
|
+
#
|
307
|
+
# Returns the sidebar Page or nil if none exists.
|
308
|
+
def sidebar
|
309
|
+
@sidebar ||= find_sub_page(:sidebar)
|
310
|
+
end
|
311
|
+
|
312
|
+
# Gets a Boolean determining whether this page is a historical version.
|
313
|
+
# Historical pages are pulled using exact SHA hashes and format all links
|
314
|
+
# with rel="nofollow"
|
315
|
+
#
|
316
|
+
# Returns true if the page is pulled from a named branch or tag, or false.
|
317
|
+
def historical?
|
318
|
+
!!@historical
|
319
|
+
end
|
320
|
+
|
321
|
+
#########################################################################
|
322
|
+
#
|
323
|
+
# Class Methods
|
324
|
+
#
|
325
|
+
#########################################################################
|
326
|
+
|
327
|
+
# Convert a human page name into a canonical page name.
|
328
|
+
#
|
329
|
+
# name - The String human page name.
|
330
|
+
# char_white_sub - Substitution for whitespace
|
331
|
+
# char_other_sub - Substitution for other special chars
|
332
|
+
#
|
333
|
+
# Examples
|
334
|
+
#
|
335
|
+
# Page.cname("Bilbo Baggins")
|
336
|
+
# # => 'Bilbo-Baggins'
|
337
|
+
#
|
338
|
+
# Page.cname("Bilbo Baggins",'_')
|
339
|
+
# # => 'Bilbo_Baggins'
|
340
|
+
#
|
341
|
+
# Returns the String canonical name.
|
342
|
+
def self.cname(name, char_white_sub = '-', char_other_sub = '-')
|
343
|
+
name.respond_to?(:gsub) ?
|
344
|
+
name.gsub(%r{\s}, char_white_sub).gsub(%r{[<>+]}, char_other_sub) :
|
345
|
+
''
|
346
|
+
end
|
347
|
+
|
348
|
+
# Convert a format Symbol into an extension String.
|
349
|
+
#
|
350
|
+
# format - The format Symbol.
|
351
|
+
#
|
352
|
+
# Returns the String extension (no leading period).
|
353
|
+
def self.format_to_ext(format)
|
354
|
+
format == :markdown ? "md" : format.to_s
|
355
|
+
end
|
356
|
+
|
357
|
+
#########################################################################
|
358
|
+
#
|
359
|
+
# Internal Methods
|
360
|
+
#
|
361
|
+
#########################################################################
|
362
|
+
|
363
|
+
# The underlying wiki repo.
|
364
|
+
#
|
365
|
+
# Returns the Gollum::Wiki containing the page.
|
366
|
+
attr_reader :wiki
|
367
|
+
|
368
|
+
# Set the Gollum::Git::Commit version of the page.
|
369
|
+
#
|
370
|
+
# Returns nothing.
|
371
|
+
attr_writer :version
|
372
|
+
|
373
|
+
# Find a page in the given Gollum repo.
|
374
|
+
#
|
375
|
+
# name - The human or canonical String page name to find.
|
376
|
+
# version - The String version ID to find.
|
377
|
+
#
|
378
|
+
# Returns a Gollum::Page or nil if the page could not be found.
|
379
|
+
def find(name, version, dir = nil, exact = false)
|
380
|
+
map = @wiki.tree_map_for(version.to_s)
|
381
|
+
if page = find_page_in_tree(map, name, dir, exact)
|
382
|
+
page.version = version.is_a?(Gollum::Git::Commit) ?
|
383
|
+
version : @wiki.commit_for(version)
|
384
|
+
page.historical = page.version.to_s == version.to_s
|
385
|
+
page
|
386
|
+
end
|
387
|
+
rescue Gollum::Git::NoSuchShaFound
|
388
|
+
end
|
389
|
+
|
390
|
+
# Find a page in a given tree.
|
391
|
+
#
|
392
|
+
# map - The Array tree map from Wiki#tree_map.
|
393
|
+
# name - The canonical String page name.
|
394
|
+
# checked_dir - Optional String of the directory a matching page needs
|
395
|
+
# to be in. The string should
|
396
|
+
#
|
397
|
+
# Returns a Gollum::Page or nil if the page could not be found.
|
398
|
+
def find_page_in_tree(map, name, checked_dir = nil, exact = false)
|
399
|
+
return nil if !map || name.to_s.empty?
|
400
|
+
|
401
|
+
checked_dir = BlobEntry.normalize_dir(checked_dir)
|
402
|
+
checked_dir = '' if exact && checked_dir.nil?
|
403
|
+
name = ::File.join(checked_dir, name) if checked_dir
|
404
|
+
|
405
|
+
map.each do |entry|
|
406
|
+
next if entry.name.to_s.empty?
|
407
|
+
path = checked_dir ? ::File.join(entry.dir, entry.name) : entry.name
|
408
|
+
next unless page_match(name, path)
|
409
|
+
return entry.page(@wiki, @version)
|
410
|
+
end
|
411
|
+
|
412
|
+
return nil # nothing was found
|
413
|
+
end
|
414
|
+
|
415
|
+
# Populate the Page with information from the Blob.
|
416
|
+
#
|
417
|
+
# blob - The Gollum::Git::Blob that contains the info.
|
418
|
+
# path - The String directory path of the page file.
|
419
|
+
#
|
420
|
+
# Returns the populated Gollum::Page.
|
421
|
+
def populate(blob, path=nil)
|
422
|
+
@blob = blob
|
423
|
+
@path = "#{path}/#{blob.name}"[1..-1]
|
424
|
+
self
|
425
|
+
end
|
426
|
+
|
427
|
+
# The full directory path for the given tree.
|
428
|
+
#
|
429
|
+
# treemap - The Hash treemap containing parentage information.
|
430
|
+
# tree - The Gollum::Git::Tree for which to compute the path.
|
431
|
+
#
|
432
|
+
# Returns the String path.
|
433
|
+
def tree_path(treemap, tree)
|
434
|
+
if ptree = treemap[tree]
|
435
|
+
tree_path(treemap, ptree) + '/' + tree.name
|
436
|
+
else
|
437
|
+
''
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
# Compare the canonicalized versions of the two names.
|
442
|
+
#
|
443
|
+
# name - The human or canonical String page name.
|
444
|
+
# path - the String path on disk (including file extension).
|
445
|
+
#
|
446
|
+
# Returns a Boolean.
|
447
|
+
def page_match(name, path)
|
448
|
+
if match = self.class.valid_filename?(path)
|
449
|
+
@wiki.ws_subs.each do |sub|
|
450
|
+
return true if Page.cname(name).downcase == Page.cname(match, sub).downcase
|
451
|
+
end
|
452
|
+
end
|
453
|
+
false
|
454
|
+
end
|
455
|
+
|
456
|
+
# Loads a sub page. Sub page names (footers, headers, sidebars) are prefixed with
|
457
|
+
# an underscore to distinguish them from other Pages. If there is not one within
|
458
|
+
# the current directory, starts walking up the directory tree to try and find one
|
459
|
+
# within parent directories.
|
460
|
+
#
|
461
|
+
# name - String page name.
|
462
|
+
#
|
463
|
+
# Returns the Page or nil if none exists.
|
464
|
+
def find_sub_page(name)
|
465
|
+
return nil unless self.version
|
466
|
+
return nil if self.filename =~ /^_/
|
467
|
+
name = "_#{name.to_s.capitalize}"
|
468
|
+
return nil if page_match(name, self.filename)
|
469
|
+
|
470
|
+
dirs = self.path.split('/')
|
471
|
+
dirs.pop
|
472
|
+
map = @wiki.tree_map_for(@wiki.ref, true)
|
473
|
+
while !dirs.empty?
|
474
|
+
if page = find_page_in_tree(map, name, dirs.join('/'))
|
475
|
+
page.parent_page = self
|
476
|
+
return page
|
477
|
+
end
|
478
|
+
dirs.pop
|
479
|
+
end
|
480
|
+
|
481
|
+
if page = find_page_in_tree(map, name, '')
|
482
|
+
page.parent_page = self
|
483
|
+
end
|
484
|
+
page
|
485
|
+
end
|
486
|
+
|
487
|
+
def inspect
|
488
|
+
%(#<#{self.class.name}:#{object_id} #{name} (#{format}) @wiki=#{@wiki.repo.path.inspect}>)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|