Add preview functionality to frontend.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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("<p>Nothing to preview</p>")
|
||||
return
|
||||
}
|
||||
output.html("<p>Loading preview…</p>")
|
||||
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);
|
||||
@@ -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();
|
||||
});
|
||||
};
|
||||
@@ -2,19 +2,22 @@
|
||||
<a href="/{{name}}">« Back</a>
|
||||
<h1>Editing “{{name}}”</h1>
|
||||
|
||||
<form class="edit_wiki" method="post" action="/edit/{{name}}">
|
||||
<label>
|
||||
Format<br />
|
||||
<select name="format">
|
||||
{{#formats}}
|
||||
<option {{#selected}}selected="true" {{/selected}}value="{{id}}">{{name}}</option>
|
||||
{{/formats}}
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
{{>editbar}}
|
||||
<textarea name="content">{{content}}</textarea>
|
||||
</label>
|
||||
<form iclass="edit_wiki" method="post" action="/edit/{{name}}">
|
||||
<div id="wiki-form" class="comment-form wiki-form">
|
||||
<ul class="tabs inline-tabs">
|
||||
<li><a href="#write_bucket" action="write">Write</a></li>
|
||||
<li><a href="#preview_bucket" action="preview">Preview</a></li>
|
||||
</ul>
|
||||
<div id="write_bucket" class="tab-content">
|
||||
{{>editbar}}
|
||||
<div class="inner">
|
||||
<textarea name="content">{{content}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="preview_bucket" class="tab-content content-body content wikistyle gollum">
|
||||
<p>Loading content...</p>
|
||||
</div>
|
||||
</div>
|
||||
<label>
|
||||
Edit Summary <small>(Briefly describe the changes you have made)</small><br />
|
||||
<input type="text" class="text" name="message" />
|
||||
|
||||
@@ -17,10 +17,20 @@
|
||||
<a href="#">Help</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="group group-right">
|
||||
<span class="tab">
|
||||
Format:
|
||||
<select id="wiki_format" name="format">
|
||||
{{#formats}}
|
||||
<option {{#selected}}selected="true" {{/selected}}value="{{id}}">{{name}}</option>
|
||||
{{/formats}}
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sections">
|
||||
<div class="toc">
|
||||
<div class="headers">Headers</div>
|
||||
<div class="headers current">Headers</div>
|
||||
<div class="links gollum">Links</div>
|
||||
<div class="images gollum">Images</div>
|
||||
<div class="code gollum">Code</div>
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
<link rel="stylesheet" href="/css/editbar.css" type="text/css" charset="utf-8" />
|
||||
<script src="/javascript/jquery-1.4.2.min.js" type="text/javascript"></script>
|
||||
<script src="/javascript/jquery.text_selection-1.0.0.min.js" type="text/javascript"></script>
|
||||
<script src="/javascript/jquery.previewable_comment_form.js" type="text/javascript"></script>
|
||||
<script src="/javascript/jquery.tabs.js" type="text/javascript"></script>
|
||||
<script src="/javascript/gollum.js" type="text/javascript"></script>
|
||||
<script src="/javascript/MathJax/MathJax.js" type="text/javascript">
|
||||
MathJax.OutputJax.fontDir = "http://github-assets.s3.amazonaws.com/javascripts/MathJax/fonts"
|
||||
|
||||
Reference in New Issue
Block a user