From 6438d69775d73f2f520d9e0590cb857fbe6df7b5 Mon Sep 17 00:00:00 2001 From: Tom Preston-Werner Date: Sat, 31 Jul 2010 14:30:38 -0400 Subject: [PATCH] Add preview functionality to frontend. --- lib/gollum/frontend/app.rb | 7 ++ lib/gollum/frontend/public/css/editbar.css | 13 ++- lib/gollum/frontend/public/css/screen.css | 95 ++++++++++++++++++- .../frontend/public/javascript/gollum.js | 22 ++++- .../jquery.previewable_comment_form.js | 57 +++++++++++ .../frontend/public/javascript/jquery.tabs.js | 59 ++++++++++++ lib/gollum/frontend/templates/edit.mustache | 29 +++--- .../frontend/templates/editbar.mustache | 12 ++- lib/gollum/frontend/templates/layout.mustache | 2 + 9 files changed, 274 insertions(+), 22 deletions(-) create mode 100644 lib/gollum/frontend/public/javascript/jquery.previewable_comment_form.js create mode 100644 lib/gollum/frontend/public/javascript/jquery.tabs.js diff --git a/lib/gollum/frontend/app.rb b/lib/gollum/frontend/app.rb index ad903bfd..65c3bbce 100644 --- a/lib/gollum/frontend/app.rb +++ b/lib/gollum/frontend/app.rb @@ -71,6 +71,13 @@ module Precious redirect "/#{name}" end + post '/preview' do + format = params['wiki_format'] + data = params['text'] + wiki = Gollum::Wiki.new($path) + wiki.preview_page("Preview", data, format).formatted_data + end + get %r{/(.+?)/([0-9a-f]{40})} do name = params[:captures][0] wiki = Gollum::Wiki.new($path) diff --git a/lib/gollum/frontend/public/css/editbar.css b/lib/gollum/frontend/public/css/editbar.css index a49dae55..c316e225 100644 --- a/lib/gollum/frontend/public/css/editbar.css +++ b/lib/gollum/frontend/public/css/editbar.css @@ -8,6 +8,13 @@ font-size: 13px; } + #editbar .inner { + width: 100%; + padding: 0; + margin: 0; + border: none; + } + #editbar .current { display: block !important; } @@ -26,6 +33,10 @@ padding-right: 6px; } + #editbar .group-right { + float: right; + } + #editbar .group-separator { border-right: 1px solid #ddd; } @@ -103,7 +114,7 @@ color: #333; } - #editbar .tab a.open:hover { + #editbar .tab a.open:hover { text-decoration: none; } diff --git a/lib/gollum/frontend/public/css/screen.css b/lib/gollum/frontend/public/css/screen.css index 304d1c38..ee525c7a 100644 --- a/lib/gollum/frontend/public/css/screen.css +++ b/lib/gollum/frontend/public/css/screen.css @@ -182,19 +182,16 @@ html {overflow-y: scroll;} margin: 1em 0; } - #guides .write input.text, - #guides .write textarea { + #guides .write input.text { padding: 5px; border: 1px solid #888; - } - - #guides .write input.text { width: 40em; } #guides .write textarea { width: 100%; height: 25em; + border: none; } #guides .write label span.title { @@ -206,6 +203,12 @@ html {overflow-y: scroll;} margin-right: 1em; } + #guides .write #preview_bucket { + border: 1px solid #888; + background-color: white; + padding: 5px; + } + /****************************************************************************/ /* Wiki /****************************************************************************/ @@ -337,6 +340,23 @@ html {overflow-y: scroll;} color: yellow !important; } +/* Wiki form */ + +.wiki-form .inner { + margin: 0; + padding: 5px 0 5px 5px; + background: #fff; + border: solid 1px #888 +} + +.wiki-form input[type=text] { + width: 100%; +} + +label.wiki-label { + padding: 1em 5px; +} + /* Special markup considerations */ .wikistyle.gollum.footer { @@ -401,3 +421,68 @@ html {overflow-y: scroll;} .wikistyle.gollum.rest > div.document > div.section > h1:first-child { display: none; } + +/****************************************************************************/ +/* Comment Form +/****************************************************************************/ + +.comment-form-error{ + margin:-15px 0 15px 0; + font-weight:bold; + color:#aa0000; +} + +.comment-form{ + margin:-10px 0 10px 0; + padding:5px; + background:#eee; + -webkit-border-radius:5px; + -moz-border-radius:5px; +} + +.comment-form textarea{ + margin:0; + width:100%; + height:100px; +} + +.comment-form p.help{ + margin:3px 0 0 0; + float:right; + font-size:11px; + color:#666; +} + +.comment-form ul.tabs{ + margin:0 0 5px 0; +} + +.comment-form ul.tabs li{ + list-style-type:none; + margin:0; + display:inline-block; +} + +.comment-form ul.tabs a{ + display:inline-block; + padding:2px 8px; + font-size:11px; + font-weight:bold; + text-decoration:none; + color:#666; + border:1px solid transparent; + -webkit-border-radius:10px; + -moz-border-radius:10px; +} + +.comment-form ul.tabs a.selected{ + color:#333; + background:#fff; + border-color:#bbb; + border-right-color: #ddd; + border-bottom-color: #ddd; +} + +.comment-form .comment{ + margin:5px 0 0 0; +} \ No newline at end of file diff --git a/lib/gollum/frontend/public/javascript/gollum.js b/lib/gollum/frontend/public/javascript/gollum.js index 9acb1daf..6bcc7426 100644 --- a/lib/gollum/frontend/public/javascript/gollum.js +++ b/lib/gollum/frontend/public/javascript/gollum.js @@ -163,7 +163,7 @@ $(function(){ } }) - $('#guides .write select[name=format]').change(function() { + $('#wiki_format').change(function() { var target = $('#editbar .sections .toc div.current').get(0) sectionItemClick.call(target) }) @@ -174,7 +174,7 @@ $(function(){ $('#editbar .sections .page').removeClass('current') var classes = $(this).attr('class').split(' ') var name = classes[0] - var format = $('#guides .write select[name=format] option:selected').attr('value') + var format = $('#wiki_format option:selected').attr('value') if (classes.indexOf('gollum') == -1) { $('#editbar .sections .page.' + name + '.' + format).addClass('current') } else { @@ -184,4 +184,22 @@ $(function(){ } $('#editbar .sections .toc div').click(sectionItemClick) + + var whichType = function(){ + return $('#wiki_format').val() + } + + $('#wiki-form').previewableCommentForm({ + previewUrl: "/preview", + previewOptions: {'wiki_format': whichType}, + onSuccess: function() { + MathJax.Hub.Typeset(this[0]) + $('#wiki_format option').each(function() { + $('#preview_bucket').removeClass($(this).val()) + }) + $('#preview_bucket').addClass(whichType) + } + }) + + $('ul.inline-tabs').tabs() }) diff --git a/lib/gollum/frontend/public/javascript/jquery.previewable_comment_form.js b/lib/gollum/frontend/public/javascript/jquery.previewable_comment_form.js new file mode 100644 index 00000000..75df676f --- /dev/null +++ b/lib/gollum/frontend/public/javascript/jquery.previewable_comment_form.js @@ -0,0 +1,57 @@ +(function($){ + $.fn.previewableCommentForm = function(options){ + var opts = $.extend({}, $.fn.previewableCommentForm.defaults, options); + + return this.each(function(){ + var wrapper = $(this) + var input = wrapper.find('textarea') + var output = wrapper.find('.content-body') + var error = wrapper.prev('.comment-form-error') + var button = wrapper.find('.form-actions button') + var text = input.val() + var dirty = false + var request = null + + dirtyInputs = $.merge(wrapper.find('.preview-dirty'), input) + dirtyInputs.blur(function(){ + if (text != input.val()){ + dirty = true + text = input.val() + } + updatePreview() + }) + + var updatePreview = function(force){ + if (!dirty && !force) return + if ($.trim(text) == ""){ // empty input + output.html("

Nothing to preview

") + return + } + output.html("

Loading preview…

") + if (request) request.abort() + var params = $.extend({"text": text}, opts.previewOptions) + request = $.post(opts.previewUrl, params, function(data) { + output.html(data) + opts.onSuccess.call(output) + }) + } + updatePreview(true) + + // Custom validation + wrapper.closest('form').submit(function(){ + error.hide() + if ( $.trim(input.val()) == "" ){ + error.show() + return false + } + button.attr('disabled', 'disabled') + }) + }) + } + + $.fn.previewableCommentForm.defaults = { + previewUrl: "/preview", + previewOptions: {}, + onSuccess: function() { } + } +})(jQuery); diff --git a/lib/gollum/frontend/public/javascript/jquery.tabs.js b/lib/gollum/frontend/public/javascript/jquery.tabs.js new file mode 100644 index 00000000..b39f1218 --- /dev/null +++ b/lib/gollum/frontend/public/javascript/jquery.tabs.js @@ -0,0 +1,59 @@ +jQuery.fn.tabs = function(){ + + var getAnchor = function(str) { + return /#([a-z][\w.:-]*)$/i.exec(str)[1]; + } + + var windowHash = window.location.hash.substr(1); + + return this.each(function(){ + var selectedLink = null; + var selectedContainer = null; + + $(this).find('li a').each(function(){ + // Find & hide the container + var container = $('#' + getAnchor(this.href)); + if (container == []) return; + container.hide(); + // Setup the click handlers for the tab links + $(this).click(function(){ + var self = $(this) + + var switchTab = function(){ + if (selectedContainer) selectedContainer.hide(); + if (selectedLink) selectedLink.removeClass('selected'); + + selectedContainer = container.show(); + selectedLink = self.addClass('selected'); + } + + if (self.attr('ajax')){ + self.addClass('loading') + $.ajax({ + url: self.attr('ajax'), + success: function(data){ + container.html(data) + self.removeClass('loading') + self[0].removeAttribute('ajax') + switchTab() + }, + failure: function(data){ + alert("An error occured, please reload the page") + } + }) + }else{ + switchTab() + } + + return false; + }); + + if ($(this).hasClass('selected')) $(this).click(); + }); + + // Try to match window.location.hash + $(this).find("li a[href='#" + windowHash + "']").click() + // Show one tab by default + if (selectedContainer == null) $($(this).find('li a')[0]).click(); + }); +}; \ No newline at end of file diff --git a/lib/gollum/frontend/templates/edit.mustache b/lib/gollum/frontend/templates/edit.mustache index 126816d0..b5a4a161 100644 --- a/lib/gollum/frontend/templates/edit.mustache +++ b/lib/gollum/frontend/templates/edit.mustache @@ -2,19 +2,22 @@ « Back

Editing “{{name}}”

-
- - + +
+ +
+ {{>editbar}} +
+ +
+
+
+

Loading content...

+
+