Merge pull request #393 from nature/dir_support

Add Directory Support.
This commit is contained in:
bootstraponline
2012-06-21 09:39:12 -07:00
25 changed files with 476 additions and 128 deletions
+97 -51
View File
@@ -6,11 +6,13 @@ require 'useragent'
require 'gollum/frontend/views/layout' require 'gollum/frontend/views/layout'
require 'gollum/frontend/views/editable' require 'gollum/frontend/views/editable'
require 'gollum/frontend/views/has_page'
require File.expand_path '../uri_encode_component', __FILE__ require File.expand_path '../uri_encode_component', __FILE__
require File.expand_path '../helpers', __FILE__
# Run the frontend, based on Sinatra # Run the frontend, based on Sinatra
# #
# There are a number of wiki options that can be set for the frontend # There are a number of wiki options that can be set for the frontend
# #
# Example # Example
@@ -23,6 +25,7 @@ require File.expand_path '../uri_encode_component', __FILE__
module Precious module Precious
class App < Sinatra::Base class App < Sinatra::Base
register Mustache::Sinatra register Mustache::Sinatra
include Precious::Helpers
dir = File.dirname(File.expand_path(__FILE__)) dir = File.dirname(File.expand_path(__FILE__))
@@ -30,7 +33,7 @@ module Precious
@@supported_browsers = ['Firefox', 'Chrome', 'Safari'] @@supported_browsers = ['Firefox', 'Chrome', 'Safari']
Browser = Struct.new(:browser, :version) Browser = Struct.new(:browser, :version)
@@ie9 = Browser.new('Internet Explorer', '9.0') @@ie9 = Browser.new('Internet Explorer', '9.0')
def supported_useragent?(user_agent) def supported_useragent?(user_agent)
ua = UserAgent.parse(user_agent) ua = UserAgent.parse(user_agent)
return true if ua >= @@ie9 return true if ua >= @@ie9
@@ -69,19 +72,28 @@ module Precious
end end
get '/data/*' do get '/data/*' do
@name = params[:splat].first @path = extract_path(params[:splat].first)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @name = extract_name(params[:splat].first)
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
if page = wiki.page(@name) if page = wiki.page(@name)
page.raw_data page.raw_data
end end
end end
get '/edit/*' do get '/edit/*' do
@name = params[:splat].first @path = extract_path(params[:splat].first)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @name = extract_name(params[:splat].first)
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
if page = wiki.page(@name) if page = wiki.page(@name)
if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent) if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent)
redirect '/livepreview/index.html?page=' + encodeURIComponent(@name) live_preview_url = '/livepreview/index.html?page=' + encodeURIComponent(@name)
if @path
live_preview_url << '&path=' + encodeURIComponent(@path)
end
redirect live_preview_url
else else
@page = page @page = page
@page.version = wiki.repo.log(wiki.ref, @page.path).first @page.version = wiki.repo.log(wiki.ref, @page.path).first
@@ -94,31 +106,37 @@ module Precious
end end
post '/edit/*' do post '/edit/*' do
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) path = sanitize_empty_params(params[:path])
page = wiki.page(params[:splat].first) wiki_options = settings.wiki_options.merge({ :page_file_dir => path })
name = params[:rename] || page.name wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
committer = Gollum::Committer.new(wiki, commit_message) page = wiki.page(CGI.unescape(params[:page]))
commit = {:committer => committer} name = params[:rename] || page.name
committer = Gollum::Committer.new(wiki, commit_message)
commit = {:committer => committer}
update_wiki_page(wiki, page, params[:content], commit, name, update_wiki_page(wiki, page, params[:content], commit, name, params[:format])
params[:format])
update_wiki_page(wiki, page.header, params[:header], commit) if params[:header] update_wiki_page(wiki, page.header, params[:header], commit) if params[:header]
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer] update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar] update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
committer.commit committer.commit
redirect "/#{CGI.escape(Gollum::Page.cname(name))}" page = wiki.page(params[:rename]) if params[:rename]
redirect "/#{page.escaped_url_path}"
end end
post '/create' do post '/create' do
name = params[:page] name = params[:page]
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) path = sanitize_empty_params(params[:path])
format = params[:format].intern
format = params[:format].intern wiki_options = settings.wiki_options.merge({ :page_file_dir => path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
begin begin
wiki.write_page(name, format, params[:content], commit_message) wiki.write_page(name, format, params[:content], commit_message)
redirect "/#{CGI.escape(Gollum::Page.cname(name))}" page = wiki.page(name)
redirect "/#{page.escaped_url_path}"
rescue Gollum::DuplicatePageError => e rescue Gollum::DuplicatePageError => e
@message = "Duplicate page: #{e.message}" @message = "Duplicate page: #{e.message}"
mustache :error mustache :error
@@ -126,15 +144,17 @@ module Precious
end end
post '/revert/:page/*' do post '/revert/:page/*' do
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @path = extract_path(params[:page])
@name = params[:page] @name = params[:page]
@page = wiki.page(@name) wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
shas = params[:splat].first.split("/") wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
sha1 = shas.shift @page = wiki.page(@name)
sha2 = shas.shift shas = params[:splat].first.split("/")
sha1 = shas.shift
sha2 = shas.shift
if wiki.revert_page(@page, sha1, sha2, commit_message) if wiki.revert_page(@page, sha1, sha2, commit_message)
redirect "/#{CGI.escape(@name)}" redirect "/#{@page.escaped_url_path}"
else else
sha2, sha1 = sha1, "#{sha1}^" if !sha2 sha2, sha1 = sha1, "#{sha1}^" if !sha2
@versions = [sha1, sha2] @versions = [sha1, sha2]
@@ -156,34 +176,46 @@ module Precious
mustache :page mustache :page
end end
get '/history/:name' do get '/history/*' do
@name = params[:name] @path = extract_path(params[:splat].first)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) @name = extract_name(params[:splat].first)
@page = wiki.page(@name) wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
@page_num = [params[:page].to_i, 1].max wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
@versions = @page.versions :page => @page_num @page = wiki.page(@name)
@page_num = [params[:page].to_i, 1].max
@versions = @page.versions :page => @page_num
mustache :history mustache :history
end end
post '/compare/:name' do post '/compare/*' do
@file = params[:splat].first
@versions = params[:versions] || [] @versions = params[:versions] || []
if @versions.size < 2 if @versions.size < 2
redirect "/history/#{CGI.escape(params[:name])}" redirect "/history/#{@file}"
else else
redirect "/compare/%s/%s...%s" % [ redirect "/compare/%s/%s...%s" % [
CGI.escape(params[:name]), @file,
@versions.last, @versions.last,
@versions.first] @versions.first]
end end
end end
get '/compare/:name/:version_list' do get %r{
@name = params[:name] /compare/ # match any URL beginning with /compare/
@versions = params[:version_list].split(/\.{2,3}/) (.+) # extract the full path (including any directories)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) / # match the final slash
@page = wiki.page(@name) ([^.]+) # match the first SHA1
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path) \.{2,3} # match .. or ...
@diff = diffs.first (.+) # match the second SHA1
}x do |path, start_version, end_version|
@path = extract_path(path)
@name = extract_name(path)
@versions = [start_version, end_version]
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
@page = wiki.page(@name)
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
@diff = diffs.first
mustache :compare mustache :compare
end end
@@ -198,8 +230,11 @@ module Precious
end end
get %r{/(.+?)/([0-9a-f]{40})} do get %r{/(.+?)/([0-9a-f]{40})} do
name = params[:captures][0] file_path = params[:captures][0]
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) path = extract_path(file_path)
name = extract_name(file_path)
wiki_options = settings.wiki_options.merge({ :page_file_dir => path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
if page = wiki.page(name, params[:captures][1]) if page = wiki.page(name, params[:captures][1])
@page = page @page = page
@name = name @name = name
@@ -219,10 +254,17 @@ module Precious
mustache :search mustache :search
end end
get '/pages' do get %r{
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) /pages # match any URL beginning with /pages
@results = wiki.pages (?: # begin an optional non-capturing group
@ref = wiki.ref /(.+) # capture any path after the "/pages" excluding the leading slash
)? # end the optional non-capturing group
}x do |path|
@path = extract_path(path) if path
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
@results = wiki.pages
@ref = wiki.ref
mustache :pages mustache :pages
end end
@@ -237,8 +279,12 @@ module Precious
show_page_or_file(params[:splat].first) show_page_or_file(params[:splat].first)
end end
def show_page_or_file(name) def show_page_or_file(fullpath)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) path = extract_path(fullpath)
name = extract_name(fullpath)
wiki_options = settings.wiki_options.merge({ :page_file_dir => path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
if page = wiki.page(name) if page = wiki.page(name)
@page = page @page = page
@name = name @name = name
@@ -248,7 +294,7 @@ module Precious
@mathjax = wiki.mathjax @mathjax = wiki.mathjax
mustache :page mustache :page
elsif file = wiki.file(name) elsif file = wiki.file(fullpath)
content_type file.mime_type content_type file.mime_type
file.raw_data file.raw_data
else else
+20
View File
@@ -0,0 +1,20 @@
module Precious
module Helpers
# Extract the path string that Gollum::Wiki expects
def extract_path(file_path)
last_slash = file_path.rindex("/")
if last_slash
file_path[0, last_slash]
end
end
# Extract the 'page' name from the file_path
def extract_name(file_path)
::File.basename(file_path)
end
def sanitize_empty_params(param)
[nil,''].include?(param) ? nil : CGI.unescape(param)
end
end
end
@@ -94,7 +94,7 @@ a:hover, a:visited {
float:left; float:left;
margin-bottom: 20px; margin-bottom: 20px;
min-width: 33%; min-width: 33%;
border-radius: 0.5em; border-radius: 0.5em;
-moz-border-radius: 0.5em; -moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em; -webkit-border-radius: 0.5em;
@@ -681,3 +681,36 @@ ul.actions {
background-position: -431px -28px; background-position: -431px -28px;
padding: 0; padding: 0;
} }
/* @section pages */
#pages {
font-size: 1.2em;
margin-bottom: 20px;
}
#pages ul {
list-style: none;
margin: 0;
padding: 0;
}
#pages li a.file,
#pages li a.folder {
background-image: url(/images/fileview/document.png);
background-position: 0 1px;
background-repeat: no-repeat;
padding-left: 20px;
}
#pages li a.folder {
background-image: url(/images/fileview/folder-horizontal.png);
}
#pages .breadcrumb {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0;
padding: 0.25em;
}
@@ -65,8 +65,13 @@ $.key = function( key ) {
// True if &create=true // True if &create=true
var create = $.key( 'create' ); var create = $.key( 'create' );
// The name of the page being edited. // The path and name of the page being edited.
var pageName = $.key( 'page' ); var pageName = $.key( 'page' );
var pathName = $.key( 'path' );
if (pathName === 0) {
pathName = undefined;
}
defaultCommitMessage = function() { defaultCommitMessage = function() {
var msg = pageName + ' (markdown)'; var msg = pageName + ' (markdown)';
@@ -88,14 +93,19 @@ $.save = function( commitMessage ) {
var markdown = 'markdown'; var markdown = 'markdown';
var txt = editorSession.getValue(); var txt = editorSession.getValue();
var msg = defaultCommitMessage(); var msg = defaultCommitMessage();
var newLocation = location.protocol + '//' + location.host + '/' + pageName;
var newLocation = location.protocol + '//' + location.host;
if (pathName) {
newLocation += '/' + pathName;
}
newLocation += '/' + pageName;
// if &create=true then handle create instead of edit. // if &create=true then handle create instead of edit.
if ( create ) { if ( create ) {
jQuery.ajax( { jQuery.ajax( {
type: POST, type: POST,
url: '/create', url: '/create',
data: { page: pageName, format: markdown, content: txt, message: commitMessage || msg }, data: { path: pathName, page: pageName, format: markdown, content: txt, message: commitMessage || msg },
success: function() { success: function() {
win.location = newLocation; win.location = newLocation;
} }
@@ -104,7 +114,7 @@ $.save = function( commitMessage ) {
jQuery.ajax( { jQuery.ajax( {
type: POST, type: POST,
url: '/edit/' + pageName, url: '/edit/' + pageName,
data: { format: markdown, content: txt, message: commitMessage || msg }, data: { path: pathName, page: pageName, format: markdown, content: txt, message: commitMessage || msg },
success: function() { success: function() {
win.location = newLocation; win.location = newLocation;
} }
@@ -325,7 +335,7 @@ var applyTimeout = function () {
editorSession.setValue( data ); editorSession.setValue( data );
} }
}); });
$( '#save' ).click( function() { $( '#save' ).click( function() {
$.save(); $.save();
}); });
@@ -378,10 +388,10 @@ var applyTimeout = function () {
var widthFourth = widthHalf / 2; var widthFourth = widthHalf / 2;
var height = $( win ).height(); var height = $( win ).height();
var heightHalf = height / 2; var heightHalf = height / 2;
// height minus 50 so the end of document text doesn't flow off the page. // height minus 50 so the end of document text doesn't flow off the page.
var editorContainerStyle = 'width:' + widthHalf + 'px;' + var editorContainerStyle = 'width:' + widthHalf + 'px;' +
'height:' + (height - 50) + 'px;' + 'height:' + (height - 50) + 'px;' +
'left:' + (leftRight === false ? widthHalf + 'px;' : '0px;') + 'left:' + (leftRight === false ? widthHalf + 'px;' : '0px;') +
'top:' + '40px;'; // use 40px for tool menu 'top:' + '40px;'; // use 40px for tool menu
cssSet( editorContainer, editorContainerStyle ); cssSet( editorContainer, editorContainerStyle );
@@ -1,16 +1,16 @@
<div id="wiki-wrapper" class="compare"> <div id="wiki-wrapper" class="compare">
<div id="head"> <div id="head">
<h1>History for <strong>{{path}}</strong></h1> <h1>History for <strong>{{path}}</strong></h1>
<ul class="actions"> <ul class="actions">
<li class="minibutton"> <li class="minibutton">
{{>searchbar}} {{>searchbar}}
</li> </li>
<li class="minibutton"><a href="/{{escaped_name}}" <li class="minibutton"><a href="/{{escaped_url_path}}"
class="action-view-page">View Page</a></li> class="action-view-page">View Page</a></li>
<li class="minibutton"><a href="/edit/{{escaped_name}}" <li class="minibutton"><a href="/edit/{{escaped_url_path}}"
class="action-edit-page">Edit Page</a></li> class="action-edit-page">Edit Page</a></li>
<li class="minibutton"><a href="/history/{{escaped_name}}" <li class="minibutton"><a href="/history/{{escaped_url_path}}"
class="action-page-history">Page History</a></li> class="action-page-history">Page History</a></li>
</ul> </ul>
</div> </div>
@@ -20,19 +20,19 @@
{{/message}} {{/message}}
<div id="compare-content"> <div id="compare-content">
{{#show_revert}} {{#show_revert}}
<ul class="actions"> <ul class="actions">
<li class="minibutton"><a href="/history/{{escaped_name}}" <li class="minibutton"><a href="/history/{{escaped_url_path}}"
class="action-page-history">Back to Page History</a></li> class="action-page-history">Back to Page History</a></li>
<li class="minibutton"> <li class="minibutton">
<form name="gollum-revert" action="/revert/{{escaped_name}}/{{before}}/{{after}}" method="post" id="gollum-revert-form"> <form name="gollum-revert" action="/revert/{{escaped_url_path}}/{{before}}/{{after}}" method="post" id="gollum-revert-form">
<a href="#" class="gollum-revert-button">Revert Changes</a> <a href="#" class="gollum-revert-button">Revert Changes</a>
</form> </form>
</li> </li>
</ul> </ul>
{{/show_revert}} {{/show_revert}}
<div class="data highlight"> <div class="data highlight">
<table cellpadding="0" cellspacing="0"> <table cellpadding="0" cellspacing="0">
{{#lines}} {{#lines}}
@@ -49,7 +49,7 @@
</div> </div>
<div id="footer"> <div id="footer">
<ul class="actions"> <ul class="actions">
<li class="minibutton"><a href="/history/{{escaped_name}}" <li class="minibutton"><a href="/history/{{escaped_url_path}}"
class="action-page-history">Back to Page History</a></li> class="action-page-history">Back to Page History</a></li>
{{#show_revert}} {{#show_revert}}
<li class="minibutton"> <li class="minibutton">
+2 -2
View File
@@ -2,9 +2,9 @@
<div id="head"> <div id="head">
<h1>Editing <strong>{{title}}</strong></h1> <h1>Editing <strong>{{title}}</strong></h1>
<ul class="actions"> <ul class="actions">
<li class="minibutton"><a href="/{{escaped_name}}" <li class="minibutton"><a href="/{{escaped_url_path}}"
class="action-view-page">View Page</a></li> class="action-view-page">View Page</a></li>
<li class="minibutton"><a href="/history/{{escaped_name}}" <li class="minibutton"><a href="/history/{{escaped_url_path}}"
class="action-page-history">Page History</a></li> class="action-page-history">Page History</a></li>
</ul> </ul>
</div> </div>
@@ -15,6 +15,7 @@
{{#is_edit_page}} {{#is_edit_page}}
<input type="hidden" name="page" id="gollum-editor-page-title" value="{{page_name}}"> <input type="hidden" name="page" id="gollum-editor-page-title" value="{{page_name}}">
{{/is_edit_page}} {{/is_edit_page}}
<input type="hidden" name="path" id="gollum-editor-page-path" value="{{path}}">
<div id="gollum-editor-function-bar"> <div id="gollum-editor-function-bar">
<div id="gollum-editor-function-buttons"> <div id="gollum-editor-function-buttons">
<a href="#" id="function-bold" class="function-button"> <a href="#" id="function-bold" class="function-button">
@@ -30,7 +31,7 @@
<span>Ordered List</span></a> <span>Ordered List</span></a>
<a href="#" id="function-blockquote" class="function-button"> <a href="#" id="function-blockquote" class="function-button">
<span>Blockquote</span></a> <span>Blockquote</span></a>
<a href="#" id="function-hr" class="function-button"> <a href="#" id="function-hr" class="function-button">
<span>Horizontal Rule</span></a> <span>Horizontal Rule</span></a>
<span class="function-divider">&nbsp;</span> <span class="function-divider">&nbsp;</span>
@@ -49,8 +50,8 @@
<a href="#" id="function-help" class="function-button"> <a href="#" id="function-help" class="function-button">
<span>Help</span></a> <span>Help</span></a>
</div> </div>
<div id="gollum-editor-format-selector"> <div id="gollum-editor-format-selector">
<select id="wiki_format" name="format"> <select id="wiki_format" name="format">
{{#formats}} {{#formats}}
<option {{#selected}}selected="selected" {{/selected}}value="{{id}}"> <option {{#selected}}selected="selected" {{/selected}}value="{{id}}">
@@ -85,7 +86,7 @@
</div> </div>
<textarea id="gollum-editor-body" <textarea id="gollum-editor-body"
data-markup-lang="{{format}}" name="content">{{content}}</textarea> data-markup-lang="{{format}}" name="content">{{content}}</textarea>
{{#header}} {{#header}}
<div id="gollum-editor-edit-header" class="collapsed"> <div id="gollum-editor-edit-header" class="collapsed">
<a href="#" class="button"><span>Expand/Collapse</span></a> <a href="#" class="button"><span>Expand/Collapse</span></a>
@@ -93,7 +94,7 @@
<textarea id="gollum-editor-header" name="header">{{header}}</textarea> <textarea id="gollum-editor-header" name="header">{{header}}</textarea>
</div> </div>
{{/header}} {{/header}}
{{#footer}} {{#footer}}
<div id="gollum-editor-edit-footer" class="collapsed"> <div id="gollum-editor-edit-footer" class="collapsed">
<a href="#" class="button"><span>Expand/Collapse</span></a> <a href="#" class="button"><span>Expand/Collapse</span></a>
@@ -101,7 +102,7 @@
<textarea id="gollum-editor-footer" name="footer">{{footer}}</textarea> <textarea id="gollum-editor-footer" name="footer">{{footer}}</textarea>
</div> </div>
{{/footer}} {{/footer}}
{{#sidebar}} {{#sidebar}}
<div id="gollum-editor-edit-sidebar" class="collapsed"> <div id="gollum-editor-edit-sidebar" class="collapsed">
<a href="#" class="button"><span>Expand/Collapse</span></a> <a href="#" class="button"><span>Expand/Collapse</span></a>
@@ -109,7 +110,7 @@
<textarea id="gollum-editor-sidebar" name="sidebar">{{sidebar}}</textarea> <textarea id="gollum-editor-sidebar" name="sidebar">{{sidebar}}</textarea>
</div> </div>
{{/sidebar}} {{/sidebar}}
<div id="gollum-editor-edit-summary" class="singleline"> <div id="gollum-editor-edit-summary" class="singleline">
<label for="message" class="jaws">Edit message:</label> <label for="message" class="jaws">Edit message:</label>
{{#is_create_page}} {{#is_create_page}}
@@ -119,7 +120,7 @@
<input type="text" name="message" id="gollum-editor-message-field" value="Updated {{page_name}} ({{format}})"> <input type="text" name="message" id="gollum-editor-message-field" value="Updated {{page_name}} ({{format}})">
{{/is_edit_page}} {{/is_edit_page}}
</div> </div>
<span class="jaws"><br></span> <span class="jaws"><br></span>
<input type="submit" id="gollum-editor-submit" value="Save" title="Save current changes"> <input type="submit" id="gollum-editor-submit" value="Save" title="Save current changes">
<a href="/preview" id="gollum-editor-preview" class="minibutton" title="Preview this Page">Preview</a> <a href="/preview" id="gollum-editor-preview" class="minibutton" title="Preview this Page">Preview</a>
@@ -5,25 +5,25 @@
<li class="minibutton"> <li class="minibutton">
{{>searchbar}} {{>searchbar}}
</li> </li>
<li class="minibutton"><a href="/{{escaped_name}}" <li class="minibutton"><a href="/{{escaped_url_path}}"
class="action-view-page">View Page</a></li> class="action-view-page">View Page</a></li>
<li class="minibutton"><a href="/edit/{{escaped_name}}" <li class="minibutton"><a href="/edit/{{escaped_url_path}}"
class="action-edit-page">Edit Page</a></li> class="action-edit-page">Edit Page</a></li>
</ul> </ul>
</div> </div>
<div id="wiki-history"> <div id="wiki-history">
<ul class="actions"> <ul class="actions">
<li class="minibutton"><a href="javascript:void(0);" <li class="minibutton"><a href="javascript:void(0);"
class="action-compare-revision">Compare Revisions</a></li> class="action-compare-revision">Compare Revisions</a></li>
</ul> </ul>
<form name="compare-versions" id="version-form" method="post" <form name="compare-versions" id="version-form" method="post"
action="/compare/{{escaped_name}}"> action="/compare/{{escaped_url_path}}">
<fieldset> <fieldset>
<table> <table>
<tbody> <tbody>
{{#versions}} {{#versions}}
<tr> <tr>
<td class="checkbox"> <td class="checkbox">
@@ -39,11 +39,11 @@
<td class="commit-name"> <td class="commit-name">
<span class="time-elapsed">{{date}}:</span>&nbsp; <span class="time-elapsed">{{date}}:</span>&nbsp;
{{message}} {{message}}
[<a href="/{{escaped_name}}/{{id}}" title="View commit">{{id7}}</a>] [<a href="/{{escaped_url_path}}/{{id}}" title="View commit">{{id7}}</a>]
</td> </td>
</tr> </tr>
{{/versions}} {{/versions}}
</tbody> </tbody>
</table> </table>
</fieldset> </fieldset>
@@ -53,7 +53,7 @@
<ul class="actions"> <ul class="actions">
<li class="minibutton"><a href="javascript:void(0);" <li class="minibutton"><a href="javascript:void(0);"
class="action-compare-revision">Compare Revisions</a></li> class="action-compare-revision">Compare Revisions</a></li>
<!-- only show this button if we have more than 20 revisions --> <!-- only show this button if we have more than 20 revisions -->
<li class="minibutton"><a href="#" <li class="minibutton"><a href="#"
class="action-back-to-top">Back to Top</a></li> class="action-back-to-top">Back to Top</a></li>
+2 -2
View File
@@ -12,10 +12,10 @@
<li class="minibutton" class="jaws"> <li class="minibutton" class="jaws">
<a href="#" id="minibutton-new-page">New Page</a></li> <a href="#" id="minibutton-new-page">New Page</a></li>
{{#editable}} {{#editable}}
<li class="minibutton"><a href="/edit/{{escaped_name}}" <li class="minibutton"><a href="/edit/{{escaped_url_path}}"
class="action-edit-page">Edit Page</a></li> class="action-edit-page">Edit Page</a></li>
{{/editable}} {{/editable}}
<li class="minibutton"><a href="/history/{{escaped_name}}" <li class="minibutton"><a href="/history/{{escaped_url_path}}"
class="action-page-history">Page History</a></li> class="action-page-history">Page History</a></li>
</ul> </ul>
</div> </div>
+9 -8
View File
@@ -9,16 +9,17 @@
class="action-edit-page">Home</a></li> class="action-edit-page">Home</a></li>
</ul> </ul>
</div> </div>
<div id="results"> <div id="pages">
{{#has_results}} {{#has_results}}
<ul> <div id="file-browser">
{{#results}} <div class="breadcrumb">
<li> {{{breadcrumb}}}
<a href="/{{name}}">{{name}}</a> </div>
</li> <ul>
{{/results}} {{{files_folders}}}
</ul> </ul>
</div>
{{/has_results}} {{/has_results}}
{{#no_results}} {{#no_results}}
+2 -4
View File
@@ -1,16 +1,14 @@
module Precious module Precious
module Views module Views
class Compare < Layout class Compare < Layout
include HasPage
attr_reader :page, :diff, :versions, :message attr_reader :page, :diff, :versions, :message
def title def title
"Comparison of #{@page.title}" "Comparison of #{@page.title}"
end end
def path
@page.path
end
def before def before
@versions[0][0..6] @versions[0][0..6]
end end
+1
View File
@@ -2,6 +2,7 @@ module Precious
module Views module Views
class Edit < Layout class Edit < Layout
include Editable include Editable
include HasPage
attr_reader :page, :content attr_reader :page, :content
+15
View File
@@ -0,0 +1,15 @@
module Precious
module HasPage
def path
@page.path
end
def escaped_url_path
@page.escaped_url_path
end
def format
@page.format.to_s
end
end
end
+2
View File
@@ -1,6 +1,8 @@
module Precious module Precious
module Views module Views
class History < Layout class History < Layout
include HasPage
attr_reader :page, :page_num attr_reader :page, :page_num
def title def title
+1 -1
View File
@@ -6,7 +6,7 @@ module Precious
include Rack::Utils include Rack::Utils
alias_method :h, :escape_html alias_method :h, :escape_html
attr_reader :name attr_reader :name, :path
def escaped_name def escaped_name
CGI.escape(@name) CGI.escape(@name)
+3 -5
View File
@@ -1,16 +1,14 @@
module Precious module Precious
module Views module Views
class Page < Layout class Page < Layout
include HasPage
attr_reader :content, :page, :header, :footer attr_reader :content, :page, :header, :footer
DATE_FORMAT = "%Y-%m-%d %H:%M:%S" DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
DEFAULT_AUTHOR = 'you' DEFAULT_AUTHOR = 'you'
def title def title
@page.title @page.url_path.gsub("-", " ")
end
def format
@page.format.to_s
end end
def author def author
+48
View File
@@ -1,3 +1,5 @@
require "pathname"
module Precious module Precious
module Views module Views
class Pages < Layout class Pages < Layout
@@ -7,6 +9,52 @@ module Precious
"All pages in #{@ref}" "All pages in #{@ref}"
end end
def breadcrumb
if @path
path = Pathname.new(@path)
breadcrumb = [%{<a href="/pages/">Home</a>}]
path.descend do |crumb|
title = crumb.basename
if title == path.basename
breadcrumb << title
else
breadcrumb << %{<a href="/pages/#{crumb}/">#{title}</a>}
end
end
breadcrumb.join(" / ")
else
"Home"
end
end
def files_folders
if has_results
folder_links = []
@results.map { |page|
page_path = page.path.sub(/^#{@path}\//,'')
if page_path.include?('/')
folder = page_path.split('/').first
folder_path = @path ? "#{@path}/#{folder}" : folder
folder_link = %{<li><a href="/pages/#{folder_path}/" class="folder">#{folder}</a></li>}
unless folder_links.include?(folder_link)
folder_links << folder_link
folder_link
end
elsif page_path != ".gitkeep"
%{<li><a href="/#{page.escaped_url_path}" class="file">#{page.name}</a></li>}
end
}.compact.join("\n")
else
""
end
end
def has_results def has_results
!@results.empty? !@results.empty?
end end
+22 -1
View File
@@ -153,6 +153,27 @@ module Gollum
# Returns the String path. # Returns the String path.
attr_reader :path attr_reader :path
# Public: The url path required to reach this page within the repo.
#
# Returns the String url_path
def url_path
path = if self.path.include?('/')
self.path.sub(/\/.+$/, '/')
else
''
end
path << Page.cname(self.name, '-', '-')
path
end
# Public: The url_path, but CGI escaped.
#
# Returns the String url_path
def escaped_url_path
CGI.escape(self.url_path).gsub('%2F','/')
end
# Public: The raw contents of the page. # Public: The raw contents of the page.
# #
# Returns the String data. # Returns the String data.
@@ -179,7 +200,7 @@ module Gollum
# #
# Returns the String data. # Returns the String data.
def formatted_data(encoding = nil, &block) def formatted_data(encoding = nil, &block)
@blob && markup_class.render(historical?, encoding) do |doc| @blob && markup_class.render(historical?, encoding) do |doc|
@doc = doc @doc = doc
yield doc if block_given? yield doc if block_given?
end end
+1 -1
View File
@@ -470,7 +470,7 @@ module Gollum
@repo.git.grep(*args).split("\n").map! do |line| @repo.git.grep(*args).split("\n").map! do |line|
result = line.split(':') result = line.split(':')
file_name = Gollum::Page.canonicalize_filename(::File.basename(result[1])) file_name = result[1].gsub( ::File.extname(result[1]), '' )
{ {
:count => result[2].to_i, :count => result[2].to_i,
+113 -17
View File
@@ -18,7 +18,7 @@ context "Frontend" do
test "retain edit information" do test "retain edit information" do
page1 = 'page1' page1 = 'page1'
user1 = 'user1' user1 = 'user1'
@wiki.write_page(page1, :markdown, '', @wiki.write_page(page1, :markdown, '',
{ :name => user1, :email => user1 }); { :name => user1, :email => user1 });
get page1 get page1
@@ -26,7 +26,7 @@ context "Frontend" do
page2 = 'page2' page2 = 'page2'
user2 = 'user2' user2 = 'user2'
@wiki.write_page(page2, :markdown, '', @wiki.write_page(page2, :markdown, '',
{ :name => user2, :email => user2 }); { :name => user2, :email => user2 });
get page2 get page2
@@ -38,7 +38,7 @@ context "Frontend" do
test "edits page" do test "edits page" do
page_1 = @wiki.page('A') page_1 = @wiki.page('A')
post "/edit/A", :content => 'abc', post "/edit/A", :content => 'abc', :page => 'A',
:format => page_1.format, :message => 'def' :format => page_1.format, :message => 'def'
follow_redirect! follow_redirect!
assert last_response.ok? assert last_response.ok?
@@ -85,7 +85,7 @@ context "Frontend" do
test "renames page" do test "renames page" do
page_1 = @wiki.page('B') page_1 = @wiki.page('B')
post "/edit/B", :content => 'abc', post "/edit/B", :content => 'abc',
:rename => "C", :rename => "C", :page => 'B',
:format => page_1.format, :message => 'def' :format => page_1.format, :message => 'def'
follow_redirect! follow_redirect!
assert_equal "/C", last_request.fullpath assert_equal "/C", last_request.fullpath
@@ -150,7 +150,6 @@ context "Frontend" do
assert last_response.ok? assert last_response.ok?
end end
test "reverts single commit" do test "reverts single commit" do
page1 = @wiki.page('B') page1 = @wiki.page('B')
@@ -193,31 +192,128 @@ context "Frontend" do
end end
end end
context "Frontend with page-file-dir" do # WTF? Surely this test is wrong...
# In this test repo there is already a file called 'bar.md'.
# This SHOULD raise a Duplicate Page error, no?
# context "Frontend with page-file-dir" do
# include Rack::Test::Methods
# setup do
# @path = cloned_testpath("examples/page_file_dir.git")
# @wiki = Gollum::Wiki.new(@path, { :page_file_dir => "docs" })
# Precious::App.set(:gollum_path, @path)
# Precious::App.set(:wiki_options, { :page_file_dir => "docs" })
# end
# teardown do
# FileUtils.rm_rf(@path)
# end
# test "open existing parent" do
# get "/"
# assert last_response.ok?
# post "/create", :content => "asdf", :page => "bar",
# :format => 'markdown'
# follow_redirect!
# assert last_response.ok?
# # Assert not match.
# assert_equal true, /Duplicate page/.match(last_response.body) == nil
# end
# def app
# Precious::App
# end
# end
context "Frontend with lotr" do
include Rack::Test::Methods include Rack::Test::Methods
setup do setup do
@path = cloned_testpath("examples/page_file_dir.git") @path = cloned_testpath("examples/lotr.git")
@wiki = Gollum::Wiki.new(@path, { :page_file_dir => "docs" }) @wiki = Gollum::Wiki.new(@path)
Precious::App.set(:gollum_path, @path) Precious::App.set(:gollum_path, @path)
Precious::App.set(:wiki_options, { :page_file_dir => "docs" }) Precious::App.set(:wiki_options, {})
end end
teardown do teardown do
FileUtils.rm_rf(@path) FileUtils.rm_rf(@path)
end end
test "open existing parent" do # Here's the dir structure of lotr.git
get "/" #
# .
# ├── Bilbo-Baggins.md
# ├── Data.csv
# ├── Gondor
# │   ├── Boromir.md
# │   ├── _Footer.md
# │   ├── _Header.md
# │   └── _Sidebar.md
# ├── Home.textile
# ├── Mordor
# │   ├── Eye-Of-Sauron.md
# │   ├── _Footer.md
# │   ├── _Header.md
# │   ├── _Sidebar.md
# │   ├── eye.jpg
# │   └── todo.txt
# ├── My-Precious.md
# ├── Samwise\ Gamgee.mediawiki
# ├── _Footer.md
# ├── _Header.md
# └── _Sidebar.md
#
test "/pages" do
get "/pages"
assert last_response.ok? assert last_response.ok?
post "/create", :content => "asdf", :page => "bar", body = last_response.body
:format => 'markdown'
follow_redirect!
assert last_response.ok?
# Assert not match. assert body.include?("Bilbo Baggins"), "/pages should include the page 'Bilbo Baggins'"
assert_equal true, /Duplicate page/.match(last_response.body) == nil assert body.include?("Gondor"), "/pages should include the folder 'Gondor'"
assert !body.include?("Boromir"), "/pages should NOT include the page 'Boromir'"
assert body.include?("Mordor"), "/pages should include the folder 'Mordor'"
assert !body.include?("Eye Of Sauron"), "/pages should NOT include the page 'Eye Of Sauron'"
end
test "/pages/Mordor/" do
get "/pages/Mordor/"
assert last_response.ok?, "/pages/Mordor/ did not respond ok"
body = last_response.body
assert !body.include?("Bilbo Baggins"), "/pages/Mordor/ should NOT include the page 'Bilbo Baggins'"
assert body.include?("Eye Of Sauron"), "/pages/Mordor/ should include the page 'Eye Of Sauron'"
end
test "create pages within sub-directories" do
post "/create", :content => 'big smelly creatures', :page => 'Orc',
:path => 'Mordor', :format => 'markdown', :message => 'oooh, scary'
assert_equal 'http://example.org/Mordor/Orc', last_response.headers['Location']
get "/Mordor/Orc"
assert_match /big smelly creatures/, last_response.body
post "/create", :content => 'really big smelly creatures', :page => 'Orc/Uruk-hai',
:path => 'Mordor', :format => 'markdown', :message => 'oooh, very scary'
assert_equal 'http://example.org/Mordor/Orc-Uruk-hai', last_response.headers['Location']
get "/Mordor/Orc-Uruk-hai"
assert_match /really big smelly creatures/, last_response.body
end
test "edit pages within sub-directories" do
post "/create", :content => 'big smelly creatures', :page => 'Orc',
:path => 'Mordor', :format => 'markdown', :message => 'oooh, scary'
assert_equal 'http://example.org/Mordor/Orc', last_response.headers['Location']
post "/edit/Mordor/Orc", :content => 'not so big smelly creatures',
:page => 'Orc', :path => 'Mordor', :message => 'minor edit'
assert_equal 'http://example.org/Mordor/Orc', last_response.headers['Location']
get "/Mordor/Orc"
assert_match /not so big smelly creatures/, last_response.body
end end
def app def app
+13
View File
@@ -0,0 +1,13 @@
# ~*~ encoding: utf-8 ~*~
require File.expand_path(File.join(File.dirname(__FILE__), "helper"))
context "Precious::Helpers" do
include Precious::Helpers
test "extracting paths from URLs" do
assert_nil extract_path('Eye-Of-Sauron')
assert_equal 'Mordor', extract_path('Mordor/Sauron')
assert_equal 'Mordor/Sauron', extract_path('Mordor/Sauron/Evil')
end
end
+10
View File
@@ -51,6 +51,16 @@ context "Page" do
assert_equal 'Mordor/Eye-Of-Sauron.md', page.path assert_equal 'Mordor/Eye-Of-Sauron.md', page.path
end end
test "url_path" do
page = @wiki.page('Bilbo Baggins')
assert_equal 'Bilbo-Baggins', page.url_path
end
test "nested url_path" do
page = @wiki.page('Eye Of Sauron')
assert_equal 'Mordor/Eye-Of-Sauron', page.url_path
end
test "page versions" do test "page versions" do
page = @wiki.page('Bilbo Baggins') page = @wiki.page('Bilbo Baggins')
assert_equal ["f25eccd98e9b667f9e22946f3e2f945378b8a72d", "5bc1aaec6149e854078f1d0f8b71933bbc6c2e43"], assert_equal ["f25eccd98e9b667f9e22946f3e2f945378b8a72d", "5bc1aaec6149e854078f1d0f8b71933bbc6c2e43"],
+35
View File
@@ -0,0 +1,35 @@
# ~*~ encoding: utf-8 ~*~
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
require File.expand_path '../../lib/gollum/frontend/views/pages', __FILE__
FakeResult = Struct.new(:path) do
def name
File.basename(path, File.extname(path)).gsub("-", " ")
end
def escaped_url_path
CGI.escape(path).gsub(/\..+$/, "").gsub("%2F", "/")
end
end
context "Precious::Views::Pages" do
setup do
@page = Precious::Views::Pages.new
end
test "breadcrumb" do
@page.instance_variable_set("@path", "Mordor/Eye-Of-Sauron/Saruman")
assert_equal '<a href="/pages/">Home</a> / <a href="/pages/Mordor/">Mordor</a> / <a href="/pages/Mordor/Eye-Of-Sauron/">Eye-Of-Sauron</a> / Saruman', @page.breadcrumb
end
test "breadcrumb with no path" do
assert_equal 'Home', @page.breadcrumb
end
test "files_folders" do
@page.instance_variable_set("@path", "Mordor")
results = [FakeResult.new("Mordor/Eye-Of-Sauron.md"), FakeResult.new("Mordor/Orc/Saruman.md"), FakeResult.new("Mordor/.gitkeep")]
@page.instance_variable_set("@results", results)
assert_equal %{<li><a href="/Mordor/Eye-Of-Sauron" class="file">Eye Of Sauron</a></li>\n<li><a href="/pages/Mordor/Orc/" class="folder">Orc</a></li>}, @page.files_folders
end
end
+2 -2
View File
@@ -75,7 +75,7 @@ context "Frontend Unicode support" do
page = @wiki.page('PG') page = @wiki.page('PG')
assert_equal '다른 text', utf8(page.raw_data) assert_equal '다른 text', utf8(page.raw_data)
post '/edit/PG', :content => '바뀐 text', :message => 'ghi' post '/edit/PG', :page => 'PG', :content => '바뀐 text', :message => 'ghi'
follow_redirect! follow_redirect!
assert last_response.ok? assert last_response.ok?
@@ -96,7 +96,7 @@ context "Frontend Unicode support" do
page = @wiki.page('한글') page = @wiki.page('한글')
assert_equal '다른 text', utf8(page.raw_data) assert_equal '다른 text', utf8(page.raw_data)
post '/edit/' + CGI.escape('한글'), :content => '바뀐 text', post '/edit/' + CGI.escape('한글'), :page => '한글', :content => '바뀐 text',
:format => 'markdown', :message => 'ghi' :format => 'markdown', :message => 'ghi'
follow_redirect! follow_redirect!
assert last_response.ok? assert last_response.ok?
+1 -1
View File
@@ -434,7 +434,7 @@ context "page_file_dir option" do
test "search results should be restricted in page filer dir" do test "search results should be restricted in page filer dir" do
results = @wiki.search("foo") results = @wiki.search("foo")
assert_equal 1, results.size assert_equal 1, results.size
assert_equal "foo", results[0][:name] assert_equal "docs/foo", results[0][:name]
end end
teardown do teardown do