diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index c4742705..1327e051 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -6,11 +6,13 @@ require 'useragent' require 'gollum/frontend/views/layout' require 'gollum/frontend/views/editable' +require 'gollum/frontend/views/has_page' require File.expand_path '../uri_encode_component', __FILE__ +require File.expand_path '../helpers', __FILE__ # Run the frontend, based on Sinatra -# +# # There are a number of wiki options that can be set for the frontend # # Example @@ -23,6 +25,7 @@ require File.expand_path '../uri_encode_component', __FILE__ module Precious class App < Sinatra::Base register Mustache::Sinatra + include Precious::Helpers dir = File.dirname(File.expand_path(__FILE__)) @@ -30,7 +33,7 @@ module Precious @@supported_browsers = ['Firefox', 'Chrome', 'Safari'] Browser = Struct.new(:browser, :version) @@ie9 = Browser.new('Internet Explorer', '9.0') - + def supported_useragent?(user_agent) ua = UserAgent.parse(user_agent) return true if ua >= @@ie9 @@ -69,19 +72,28 @@ module Precious end get '/data/*' do - @name = params[:splat].first - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) + @path = extract_path(params[:splat].first) + @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) page.raw_data end end get '/edit/*' do - @name = params[:splat].first - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) + @path = extract_path(params[:splat].first) + @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 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 @page = page @page.version = wiki.repo.log(wiki.ref, @page.path).first @@ -94,31 +106,37 @@ module Precious end post '/edit/*' do - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) - page = wiki.page(params[:splat].first) - name = params[:rename] || page.name - committer = Gollum::Committer.new(wiki, commit_message) - commit = {:committer => committer} + path = sanitize_empty_params(params[:path]) + wiki_options = settings.wiki_options.merge({ :page_file_dir => path }) + wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options) + page = wiki.page(CGI.unescape(params[:page])) + name = params[:rename] || page.name + committer = Gollum::Committer.new(wiki, commit_message) + commit = {:committer => committer} - update_wiki_page(wiki, page, params[:content], commit, name, - params[:format]) + update_wiki_page(wiki, page, params[:content], commit, name, params[:format]) 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.sidebar, params[:sidebar], commit) if params[:sidebar] committer.commit - redirect "/#{CGI.escape(Gollum::Page.cname(name))}" + page = wiki.page(params[:rename]) if params[:rename] + + redirect "/#{page.escaped_url_path}" end post '/create' do - name = params[:page] - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) + name = CGI.unescape(params[:page]) + 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 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 @message = "Duplicate page: #{e.message}" mustache :error @@ -126,15 +144,17 @@ module Precious end post '/revert/:page/*' do - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) - @name = params[:page] - @page = wiki.page(@name) - shas = params[:splat].first.split("/") - sha1 = shas.shift - sha2 = shas.shift + @path = extract_path(params[:page]) + @name = params[:page] + wiki_options = settings.wiki_options.merge({ :page_file_dir => @path }) + wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options) + @page = wiki.page(@name) + shas = params[:splat].first.split("/") + sha1 = shas.shift + sha2 = shas.shift if wiki.revert_page(@page, sha1, sha2, commit_message) - redirect "/#{CGI.escape(@name)}" + redirect "/#{@page.escaped_url_path}" else sha2, sha1 = sha1, "#{sha1}^" if !sha2 @versions = [sha1, sha2] @@ -156,34 +176,39 @@ module Precious mustache :page end - get '/history/:name' do - @name = params[:name] - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) - @page = wiki.page(@name) - @page_num = [params[:page].to_i, 1].max - @versions = @page.versions :page => @page_num + get '/history/*' do + @path = extract_path(params[:splat].first) + @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) + @page = wiki.page(@name) + @page_num = [params[:page].to_i, 1].max + @versions = @page.versions :page => @page_num mustache :history end - post '/compare/:name' do + post '/compare/*' do + @file = params[:splat].first @versions = params[:versions] || [] if @versions.size < 2 - redirect "/history/#{CGI.escape(params[:name])}" + redirect "/history/#{CGI.escape(@file)}" else redirect "/compare/%s/%s...%s" % [ - CGI.escape(params[:name]), + CGI.escape(@file), @versions.last, @versions.first] end end get '/compare/:name/:version_list' do - @name = params[:name] - @versions = params[:version_list].split(/\.{2,3}/) - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) - @page = wiki.page(@name) - diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path) - @diff = diffs.first + @path = extract_path(params[:name].dup) + @name = extract_name(params[:name]) + @versions = params[:version_list].split(/\.{2,3}/) + 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 end @@ -198,8 +223,11 @@ module Precious end get %r{/(.+?)/([0-9a-f]{40})} do - name = params[:captures][0] - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) + file_path = params[:captures][0] + 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]) @page = page @name = name @@ -219,10 +247,17 @@ module Precious mustache :search end - get '/pages' do - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) - @results = wiki.pages - @ref = wiki.ref + get %r{ + /pages # match any URL beginning with /pages + (?: # begin an optional non-capturing group + /(.+) # 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 end @@ -237,8 +272,12 @@ module Precious show_page_or_file(params[:splat].first) end - def show_page_or_file(name) - wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options) + def show_page_or_file(fullpath) + 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) @page = page @name = name @@ -248,7 +287,7 @@ module Precious @mathjax = wiki.mathjax mustache :page - elsif file = wiki.file(name) + elsif file = wiki.file(fullpath) content_type file.mime_type file.raw_data else diff --git a/lib/gollum/frontend/helpers.rb b/lib/gollum/frontend/helpers.rb new file mode 100644 index 00000000..1e78f617 --- /dev/null +++ b/lib/gollum/frontend/helpers.rb @@ -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 diff --git a/lib/gollum/frontend/public/gollum/css/gollum.css b/lib/gollum/frontend/public/gollum/css/gollum.css index 687b6ffd..96381b3b 100755 --- a/lib/gollum/frontend/public/gollum/css/gollum.css +++ b/lib/gollum/frontend/public/gollum/css/gollum.css @@ -94,7 +94,7 @@ a:hover, a:visited { float:left; margin-bottom: 20px; min-width: 33%; - + border-radius: 0.5em; -moz-border-radius: 0.5em; -webkit-border-radius: 0.5em; @@ -681,3 +681,36 @@ ul.actions { background-position: -431px -28px; 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; +} + diff --git a/lib/gollum/frontend/public/gollum/livepreview/js/livepreview/livepreview.js b/lib/gollum/frontend/public/gollum/livepreview/js/livepreview/livepreview.js index 1131901d..848b5d2f 100644 --- a/lib/gollum/frontend/public/gollum/livepreview/js/livepreview/livepreview.js +++ b/lib/gollum/frontend/public/gollum/livepreview/js/livepreview/livepreview.js @@ -65,8 +65,13 @@ $.key = function( key ) { // True if &create=true 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 pathName = $.key( 'path' ); + +if (pathName === 0) { + pathName = undefined; +} defaultCommitMessage = function() { var msg = pageName + ' (markdown)'; @@ -88,14 +93,19 @@ $.save = function( commitMessage ) { var markdown = 'markdown'; var txt = editorSession.getValue(); 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 ) { jQuery.ajax( { type: POST, 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() { win.location = newLocation; } @@ -104,7 +114,7 @@ $.save = function( commitMessage ) { jQuery.ajax( { type: POST, 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() { win.location = newLocation; } @@ -325,7 +335,7 @@ var applyTimeout = function () { editorSession.setValue( data ); } }); - + $( '#save' ).click( function() { $.save(); }); @@ -378,10 +388,10 @@ var applyTimeout = function () { var widthFourth = widthHalf / 2; var height = $( win ).height(); var heightHalf = height / 2; - + // height minus 50 so the end of document text doesn't flow off the page. var editorContainerStyle = 'width:' + widthHalf + 'px;' + - 'height:' + (height - 50) + 'px;' + + 'height:' + (height - 50) + 'px;' + 'left:' + (leftRight === false ? widthHalf + 'px;' : '0px;') + 'top:' + '40px;'; // use 40px for tool menu cssSet( editorContainer, editorContainerStyle ); diff --git a/lib/gollum/frontend/templates/compare.mustache b/lib/gollum/frontend/templates/compare.mustache index c06eadf6..4595f20e 100644 --- a/lib/gollum/frontend/templates/compare.mustache +++ b/lib/gollum/frontend/templates/compare.mustache @@ -1,16 +1,16 @@