Add preview functionality to frontend.
This commit is contained in:
@@ -71,6 +71,13 @@ module Precious
|
|||||||
redirect "/#{name}"
|
redirect "/#{name}"
|
||||||
end
|
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
|
get %r{/(.+?)/([0-9a-f]{40})} do
|
||||||
name = params[:captures][0]
|
name = params[:captures][0]
|
||||||
wiki = Gollum::Wiki.new($path)
|
wiki = Gollum::Wiki.new($path)
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#editbar .inner {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
#editbar .current {
|
#editbar .current {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
@@ -26,6 +33,10 @@
|
|||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#editbar .group-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
#editbar .group-separator {
|
#editbar .group-separator {
|
||||||
border-right: 1px solid #ddd;
|
border-right: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
@@ -103,7 +114,7 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
#editbar .tab a.open:hover {
|
#editbar .tab a.open:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,19 +182,16 @@ html {overflow-y: scroll;}
|
|||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#guides .write input.text,
|
#guides .write input.text {
|
||||||
#guides .write textarea {
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border: 1px solid #888;
|
border: 1px solid #888;
|
||||||
}
|
|
||||||
|
|
||||||
#guides .write input.text {
|
|
||||||
width: 40em;
|
width: 40em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#guides .write textarea {
|
#guides .write textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 25em;
|
height: 25em;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#guides .write label span.title {
|
#guides .write label span.title {
|
||||||
@@ -206,6 +203,12 @@ html {overflow-y: scroll;}
|
|||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#guides .write #preview_bucket {
|
||||||
|
border: 1px solid #888;
|
||||||
|
background-color: white;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* Wiki
|
/* Wiki
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@@ -337,6 +340,23 @@ html {overflow-y: scroll;}
|
|||||||
color: yellow !important;
|
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 */
|
/* Special markup considerations */
|
||||||
|
|
||||||
.wikistyle.gollum.footer {
|
.wikistyle.gollum.footer {
|
||||||
@@ -401,3 +421,68 @@ html {overflow-y: scroll;}
|
|||||||
.wikistyle.gollum.rest > div.document > div.section > h1:first-child {
|
.wikistyle.gollum.rest > div.document > div.section > h1:first-child {
|
||||||
display: none;
|
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)
|
var target = $('#editbar .sections .toc div.current').get(0)
|
||||||
sectionItemClick.call(target)
|
sectionItemClick.call(target)
|
||||||
})
|
})
|
||||||
@@ -174,7 +174,7 @@ $(function(){
|
|||||||
$('#editbar .sections .page').removeClass('current')
|
$('#editbar .sections .page').removeClass('current')
|
||||||
var classes = $(this).attr('class').split(' ')
|
var classes = $(this).attr('class').split(' ')
|
||||||
var name = classes[0]
|
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) {
|
if (classes.indexOf('gollum') == -1) {
|
||||||
$('#editbar .sections .page.' + name + '.' + format).addClass('current')
|
$('#editbar .sections .page.' + name + '.' + format).addClass('current')
|
||||||
} else {
|
} else {
|
||||||
@@ -184,4 +184,22 @@ $(function(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
$('#editbar .sections .toc div').click(sectionItemClick)
|
$('#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>
|
<a href="/{{name}}">« Back</a>
|
||||||
<h1>Editing “{{name}}”</h1>
|
<h1>Editing “{{name}}”</h1>
|
||||||
|
|
||||||
<form class="edit_wiki" method="post" action="/edit/{{name}}">
|
<form iclass="edit_wiki" method="post" action="/edit/{{name}}">
|
||||||
<label>
|
<div id="wiki-form" class="comment-form wiki-form">
|
||||||
Format<br />
|
<ul class="tabs inline-tabs">
|
||||||
<select name="format">
|
<li><a href="#write_bucket" action="write">Write</a></li>
|
||||||
{{#formats}}
|
<li><a href="#preview_bucket" action="preview">Preview</a></li>
|
||||||
<option {{#selected}}selected="true" {{/selected}}value="{{id}}">{{name}}</option>
|
</ul>
|
||||||
{{/formats}}
|
<div id="write_bucket" class="tab-content">
|
||||||
</select>
|
{{>editbar}}
|
||||||
</label>
|
<div class="inner">
|
||||||
<label>
|
<textarea name="content">{{content}}</textarea>
|
||||||
{{>editbar}}
|
</div>
|
||||||
<textarea name="content">{{content}}</textarea>
|
</div>
|
||||||
</label>
|
<div id="preview_bucket" class="tab-content content-body content wikistyle gollum">
|
||||||
|
<p>Loading content...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<label>
|
<label>
|
||||||
Edit Summary <small>(Briefly describe the changes you have made)</small><br />
|
Edit Summary <small>(Briefly describe the changes you have made)</small><br />
|
||||||
<input type="text" class="text" name="message" />
|
<input type="text" class="text" name="message" />
|
||||||
|
|||||||
@@ -17,10 +17,20 @@
|
|||||||
<a href="#">Help</a>
|
<a href="#">Help</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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>
|
||||||
<div class="sections">
|
<div class="sections">
|
||||||
<div class="toc">
|
<div class="toc">
|
||||||
<div class="headers">Headers</div>
|
<div class="headers current">Headers</div>
|
||||||
<div class="links gollum">Links</div>
|
<div class="links gollum">Links</div>
|
||||||
<div class="images gollum">Images</div>
|
<div class="images gollum">Images</div>
|
||||||
<div class="code gollum">Code</div>
|
<div class="code gollum">Code</div>
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
<link rel="stylesheet" href="/css/editbar.css" type="text/css" charset="utf-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-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.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/gollum.js" type="text/javascript"></script>
|
||||||
<script src="/javascript/MathJax/MathJax.js" type="text/javascript">
|
<script src="/javascript/MathJax/MathJax.js" type="text/javascript">
|
||||||
MathJax.OutputJax.fontDir = "http://github-assets.s3.amazonaws.com/javascripts/MathJax/fonts"
|
MathJax.OutputJax.fontDir = "http://github-assets.s3.amazonaws.com/javascripts/MathJax/fonts"
|
||||||
|
|||||||
Reference in New Issue
Block a user