diff --git a/README.md b/README.md index 31266ded..c095e555 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,10 @@ Installation examples for individual systems can be seen [here](https://github.c ### Markups Gollum presently ships with support for the following markups: -* [Markdown](http://daringfireball.net/projects/markdown/syntax) +* [Markdown](http://daringfireball.net/projects/markdown/syntax) (see [below](#Markdown-flavors) for more information on Markdown flavors) * [RDoc](http://rdoc.sourceforge.net/) -Since all markups are rendered by the [github-markup](https://github.com/github/markup) gem, you can easily add support for other markups by additional installation: +You can easily activate support for other markups by installing additional renderers (any that are supported by [github-markup](https://github.com/github/markup)): * [AsciiDoc](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/) -- `[sudo] gem install asciidoctor` * [Creole](http://www.wikicreole.org/wiki/CheatSheet) -- `[sudo] gem install creole` * [MediaWiki](http://www.mediawiki.org/wiki/Help:Formatting) -- `[sudo] gem install wikicloth` @@ -92,10 +92,14 @@ Since all markups are rendered by the [github-markup](https://github.com/github/ * [Pod](http://perldoc.perl.org/perlpod.html) -- requires Perl >= 5.10 (the `perl` command must be available on your command line) * Lower versions should install `Pod::Simple` from CPAN. * [ReStructuredText](http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html) -- requires python >= 2 (the `python2` command must be available on your command line) - * Note that Gollum will also need you to install `docutils` for your Python 2. Installation procedure can, again, vary depending on operating system and package manager. + * Note that Gollum will also need you to install `docutils` for your Python 2. * [Textile](http://redcloth.org/hobix.com/textile/quick.html) -- `[sudo] gem install RedCloth` -By default, Gollum ships with the `kramdown` gem to render Markdown. However, you can use any [Markdown renderer supported by github-markup](https://github.com/github/markup/blob/master/lib/github/markup/markdown.rb). The thing to remember is that the first installed renderer from the list will be used. So, for example, `redcarpet` will NOT be used if `github/markdown` is installed. +### Markdown flavors + +By default, Gollum ships with the `kramdown` gem to render Markdown. However, you can use any [Markdown renderer supported by github-markup](https://github.com/github/markup/blob/master/lib/github/markup/markdown.rb). This includes [CommonMark](https://commonmark.org/) support via the `commonmarker` gem. The first installed renderer from the list will be used (e.g., `redcarpet` will NOT be used if `github/markdown` is installed). Just `gem install` the renderer of your choice. + +See [here](https://github.com/gollum/gollum/wiki/Custom-rendering-gems) for instructions on how to use custom rendering gems and set custom options. ## RUNNING diff --git a/bin/gollum b/bin/gollum index 1ab9526d..0de5fde6 100755 --- a/bin/gollum +++ b/bin/gollum @@ -127,7 +127,7 @@ MSG end opts.on("--allow-uploads [MODE]", [:dir, :page], "Enable file uploads.", "If set to 'dir', Gollum will store all uploads in the '/uploads/' directory.", - "If set to 'page', Gollum will store each upload at the currently edited page.") do |mode| + "If set to 'page', Gollum will store uploads per page in '/uploads/[pagename]'.") do |mode| wiki_options[:allow_uploads] = true wiki_options[:per_page_uploads] = true if mode == :page end diff --git a/lib/gollum/app.rb b/lib/gollum/app.rb index 1192cf1c..6c03fcc5 100644 --- a/lib/gollum/app.rb +++ b/lib/gollum/app.rb @@ -85,9 +85,11 @@ module Precious settings.wiki_options[:allow_editing] = settings.wiki_options.fetch(:allow_editing, true) @allow_editing = settings.wiki_options[:allow_editing] @critic_markup = settings.wiki_options[:critic_markup] + @per_page_uploads = settings.wiki_options[:per_page_uploads] + forbid unless @allow_editing || request.request_method == "GET" Precious::App.set(:mustache, {:templates => settings.wiki_options[:template_dir]}) if settings.wiki_options[:template_dir] - @base_url = url('/', false).chomp('/') + @base_url = url('/', false).chomp('/').force_encoding('utf-8') @page_dir = settings.wiki_options[:page_file_dir].to_s # above will detect base_path when it's used with map in a config.ru settings.wiki_options.merge!({ :base_path => @base_url }) @@ -167,7 +169,6 @@ module Precious wikip = wiki_page(params[:splat].first) @name = join_page_name(wikip.name, wikip.ext) @path = wikip.path - @upload_dest = find_upload_dest(@path) wiki = wikip.wiki @allow_uploads = wiki.allow_uploads @@ -181,14 +182,11 @@ module Precious end end + # AJAX calls only post '/upload_file' do + wiki = wiki_new - - unless wiki.allow_uploads - @message = "File uploads are disabled" - mustache :error - return - end + halt 405 unless wiki.allow_uploads if params[:file] fullname = params[:file][:filename] @@ -196,8 +194,21 @@ module Precious end halt 500 unless tempfile.is_a? Tempfile - # Remove page file dir prefix from upload path if necessary -- committer handles this itself - dir = wiki.per_page_uploads ? params[:upload_dest] : ::File.join([wiki.page_file_dir, 'uploads'].compact) + if wiki.per_page_uploads + # remove base_url and gollum/* subpath if necessary + dir = request.referer. + sub(request.base_url, ''). + sub(/.*gollum\/[-\w]+\//, '') + # remove file extension + dir = dir.sub(::File.extname(dir), '') + dir = ::File.join("uploads", dir) + else + # Remove page file dir prefix from upload path if necessary -- committer handles this itself + dir = ::File.join([wiki.page_file_dir, 'uploads'].compact) + end + halt 500 if dir.include?('..') + halt 500 unless Pathname(dir).relative? + ext = ::File.extname(fullname) format = ext.split('.').last || 'txt' filename = ::File.basename(fullname, ext) @@ -225,8 +236,7 @@ module Precious committer.commit redirect to(request.referer) rescue Gollum::DuplicatePageError => e - @message = "Duplicate page: #{e.message}" - mustache :error + halt 409 # Signal conflict end end @@ -309,7 +319,6 @@ module Precious @ext = wikip.ext @path = wikip.path @allow_uploads = wikip.wiki.allow_uploads - @upload_dest = find_upload_dest(@path) page_dir = settings.wiki_options[:page_file_dir].to_s unless page_dir.empty? @@ -501,7 +510,6 @@ module Precious @page = page @name = name @content = page.formatted_data - @upload_dest = find_upload_dest(path) # Extensions and layout data @editable = true @@ -578,11 +586,5 @@ module Precious commit_message end - def find_upload_dest(path) - settings.wiki_options[:allow_uploads] ? - (settings.wiki_options[:per_page_uploads] ? - "#{path}/#{@name}".sub(/^\/\//, '') : 'uploads' - ) : '' - end end end diff --git a/lib/gollum/public/gollum/javascript/editor/gollum.editor.js.erb b/lib/gollum/public/gollum/javascript/editor/gollum.editor.js.erb index 464e1948..d49dd18e 100755 --- a/lib/gollum/public/gollum/javascript/editor/gollum.editor.js.erb +++ b/lib/gollum/public/gollum/javascript/editor/gollum.editor.js.erb @@ -205,9 +205,8 @@ var file = e.dataTransfer.files[0], formData = new FormData(); - formData.append('upload_dest', uploadDest); formData.append('file', file); - + $.ajax({ url: '<%= upload_file_path %>', data: formData, @@ -228,8 +227,8 @@ } window.ace_editor.insert(text); }, - error: function(r, textStatus) { - alert('Error uploading file: ' + textStatus); + error: function(r, textStatus, errorThrown) { + alert('Error uploading file: ' + textStatus + ' ' + errorThrown); $editorBody.removeClass('uploading'); } }); diff --git a/lib/gollum/public/gollum/javascript/gollum.dialog.js b/lib/gollum/public/gollum/javascript/gollum.dialog.js index c7dcba0f..b2e9ec7f 100755 --- a/lib/gollum/public/gollum/javascript/gollum.dialog.js +++ b/lib/gollum/public/gollum/javascript/gollum.dialog.js @@ -105,8 +105,6 @@ html += '
'; - html += ''; html += ''; html += '
'; @@ -125,9 +123,9 @@ title +'' + '
' + body + '
' + '
' + - 'Cancel' + - 'OK' + '
' + ''; @@ -139,9 +137,9 @@ title +'' + '
' + body + '
' + '
' + - 'Cancel' + - 'Cancel' + + '
' + '' + diff --git a/lib/gollum/public/gollum/javascript/gollum.js.erb b/lib/gollum/public/gollum/javascript/gollum.js.erb index 0c5e6542..4d17c20a 100755 --- a/lib/gollum/public/gollum/javascript/gollum.js.erb +++ b/lib/gollum/public/gollum/javascript/gollum.js.erb @@ -158,6 +158,7 @@ $(document).ready(function() { } }; + // ua detection if ($.browser.mozilla) { $('body').addClass('ff'); @@ -176,7 +177,7 @@ $(document).ready(function() { $('#minibutton-upload-page').parent().removeClass('jaws'); $('#minibutton-upload-page').click(function(e) { e.preventDefault(); - + $.GollumDialog.init({ title: 'Upload File', fields: [ @@ -187,9 +188,40 @@ $(document).ready(function() { } ], OK: function( res ) { - $('#upload').submit(); + $('#wiki-content').addClass('uploading'); + var formData = new FormData($('#upload').get(0)); + var endpoint = $('#upload').attr("action"); + + $.ajax({ + url: endpoint, + type: 'POST', + data: formData, + processData: false, + contentType: false, + success: function(data) { + // File successfully uploaded + $('#wiki-content').removeClass('uploading'); + }, + error: function(data, textStatus, errorThrown) { + $('#wiki-content').removeClass('uploading'); + if (data.status == 409) { + alert('This file already exists.'); + } else { + alert('Error uploading file: ' + textStatus + ' ' + errorThrown); + } + } + }); } }); + $('#gollum-dialog-action-ok').attr('disabled', true); + $('input:file').on('change', function() { + if ($(this).val()) { + news = 'Your uploaded file will be accessible at
/' + uploadDest + '/' + $('input[type=file]').val().split('\\').pop(); + $(".context").html(news); + $('#gollum-dialog-action-ok').attr('disabled', false); + + }; + }); }); } diff --git a/lib/gollum/public/gollum/stylesheets/_layout.scss b/lib/gollum/public/gollum/stylesheets/_layout.scss index b3eb339c..3d91e7c7 100644 --- a/lib/gollum/public/gollum/stylesheets/_layout.scss +++ b/lib/gollum/public/gollum/stylesheets/_layout.scss @@ -20,6 +20,12 @@ height: 1%; overflow: auto; } + + &.uploading { + opacity: 0.5; + } + + } /* @section body */ diff --git a/lib/gollum/public/gollum/stylesheets/dialog.scss b/lib/gollum/public/gollum/stylesheets/dialog.scss index 39108757..715a837d 100644 --- a/lib/gollum/public/gollum/stylesheets/dialog.scss +++ b/lib/gollum/public/gollum/stylesheets/dialog.scss @@ -29,7 +29,7 @@ display: block; } - a.minibutton { + button.minibutton { float: right; margin-right: 0.5em; width: auto; @@ -42,6 +42,12 @@ @include button-base; } + + button.minibutton:disabled { + opacity: 0.65; + cursor: not-allowed; + } + } #gollum-dialog-dialog-inner { diff --git a/lib/gollum/templates/layout.mustache b/lib/gollum/templates/layout.mustache index b24f9ea9..d517772f 100644 --- a/lib/gollum/templates/layout.mustache +++ b/lib/gollum/templates/layout.mustache @@ -15,12 +15,17 @@ {{#sprockets_javascript_tag}}app{{/sprockets_javascript_tag}} {{#use_identicon}} diff --git a/lib/gollum/views/create.rb b/lib/gollum/views/create.rb index 4f1bab80..05e78855 100755 --- a/lib/gollum/views/create.rb +++ b/lib/gollum/views/create.rb @@ -21,10 +21,6 @@ module Precious @allow_uploads end - def upload_dest - @upload_dest - end - def format @format ||= find_format.to_s.downcase end diff --git a/lib/gollum/views/edit.rb b/lib/gollum/views/edit.rb index 203b8d0f..8c67fe51 100755 --- a/lib/gollum/views/edit.rb +++ b/lib/gollum/views/edit.rb @@ -65,10 +65,6 @@ module Precious @allow_uploads end - def upload_dest - @upload_dest - end - def format @format = (@page.format || false) if @format.nil? @format.to_s.downcase diff --git a/lib/gollum/views/layout.rb b/lib/gollum/views/layout.rb index 885029b8..efa2c80b 100644 --- a/lib/gollum/views/layout.rb +++ b/lib/gollum/views/layout.rb @@ -47,6 +47,10 @@ module Precious def critic_markup @critic_markup end + + def per_page_uploads + @per_page_uploads + end end end diff --git a/lib/gollum/views/page.rb b/lib/gollum/views/page.rb index c7f0c58c..d44fe22f 100644 --- a/lib/gollum/views/page.rb +++ b/lib/gollum/views/page.rb @@ -57,10 +57,6 @@ module Precious @allow_uploads end - def upload_dest - @upload_dest - end - def has_header if @header @header.formatted_data.strip.empty? ? false : true diff --git a/test/test_allow_editing.rb b/test/test_allow_editing.rb index 7c3ab887..0d2a8d35 100644 --- a/test/test_allow_editing.rb +++ b/test/test_allow_editing.rb @@ -32,7 +32,7 @@ context "Precious::Views::Editing" do assert_match /Delete this Page/, last_response.body, "'Delete this Page' link is blocked in page template" assert_match /New/, last_response.body, "'New' button is blocked in page template" - assert_match /Upload/, last_response.body, "'Upload' link is blocked in page template" + assert_match /Upload\b/, last_response.body, "'Upload' link is blocked in page template" assert_match /Rename/, last_response.body, "'Rename' link is blocked in page template" assert_match /Edit/, last_response.body, "'Edit' link is blocked in page template" @@ -56,7 +56,7 @@ context "Precious::Views::Editing" do assert_no_match /Delete this Page/, last_response.body, "'Delete this Page' link not blocked in page template" assert_no_match /New/, last_response.body, "'New' button not blocked in page template" - assert_no_match /Upload/, last_response.body, "'Upload' link not blocked in page template" + assert_no_match /Upload\b/, last_response.body, "'Upload' link not blocked in page template" assert_no_match /Rename/, last_response.body, "'Rename' link not blocked in page template" assert_no_match /Edit/, last_response.body, "'Edit' link not blocked in page template"