Add comment window using Ace that allows user entered commit messages.

Use darkness div to dim the background when the comment window is active.
Set CSS in batch to avoid unnecessary reflows.
Use debouncing to efficiently resize the window.
Eliminate previewSetter in favor of redefining the previewSet function.
This commit is contained in:
bootstraponline
2012-05-18 10:28:59 -06:00
parent 32e5cc4a5a
commit 3479dca0d0
3 changed files with 183 additions and 53 deletions
@@ -2,7 +2,22 @@ body {
overflow: hidden; overflow: hidden;
} }
#editor { #darkness {
visibility: hidden;
position: absolute;
left: 0px;
top: 0px;
background-color: black;
opacity: 0.8;
z-index: 1001; /* must be > 1000 to overlay ace gutter */
}
#commenttoolpanel {
visibility: hidden;
z-index: 1002; /* > 1001 to not be hidden by darkness */
}
#comment, #editor {
margin: 0; margin: 0;
padding: 0; padding: 0;
position: absolute; position: absolute;
@@ -10,6 +25,16 @@ body {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
/* Set font size of both ace editors. */
font-size: 16px;
}
/* Set comment to have a higher z-index
so editor doesn't display in the background. */
#comment {
visibility: hidden;
z-index: 1003; /* > 1002 to not be hidden by toolpanel */
} }
#contentframe { #contentframe {
@@ -30,7 +55,7 @@ body {
} }
/* -- Start from notepag.es -- */ /* -- Start from notepag.es -- */
#toolpanel { .toolpanel {
position: fixed; position: fixed;
background: #666; background: #666;
top: 0; top: 0;
@@ -43,7 +68,7 @@ body {
text-align: center; text-align: center;
} }
#toolpanel.edit a.edit { .toolpanel.edit a.edit {
opacity: 0.4; opacity: 0.4;
/* Make it appear as a link even though save /* Make it appear as a link even though save
doesn't have a href attribute. */ doesn't have a href attribute. */
@@ -51,7 +76,7 @@ body {
display: inline-block; display: inline-block;
} }
#toolpanel a { .toolpanel a {
color: white; color: white;
text-decoration: none; text-decoration: none;
margin: 0 5px; margin: 0 5px;
@@ -60,7 +85,7 @@ body {
font-family: sans-serif; font-family: sans-serif;
} }
#toolpanel a img { .toolpanel a img {
vertical-align: middle; vertical-align: middle;
margin-left: 5px; margin-left: 5px;
margin: 0; margin: 0;
Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

@@ -2,7 +2,8 @@
<head> <head>
<title>Live Preview</title> <title>Live Preview</title>
<link rel="stylesheet" type="text/css" href="../css/template.css" /> <!-- change to href="../css/template.css" for production. -->
<link rel="stylesheet" type="text/css" href="css/gollum/template.css" />
<link rel="stylesheet" type="text/css" href="css/highlightjs/github.css" /> <link rel="stylesheet" type="text/css" href="css/highlightjs/github.css" />
<link rel="stylesheet" type="text/css" href="css/custom.css" /> <link rel="stylesheet" type="text/css" href="css/custom.css" />
@@ -13,27 +14,40 @@
<script src="js/pagedown/Markdown.Sanitizer.js" type="text/javascript" charset="utf-8"></script> <script src="js/pagedown/Markdown.Sanitizer.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jquery/jquery-1.7.2.min.js" type="text/javascript" charset="utf-8"></script> <script src="js/jquery/jquery-1.7.2.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/highlightjs/highlight.pack.js" type="text/javascript" charset="utf-8"></script> <script src="js/highlightjs/highlight.pack.js" type="text/javascript" charset="utf-8"></script>
<script src="js/debounce/jquery.ba-throttle-debounce.js" type="text/javascript" charset="utf-8"></script>
</head> </head>
<body> <body>
<div id="editor"></div> <div id="editor"></div>
<div id="previewframe"><div id="contentframe" class="markdown-body"></div></div> <div id="previewframe"><div id="contentframe" class="markdown-body"></div></div>
<!-- tool panel from notepage.es. save & savecomment icons from Retina Display Icon Set --> <!-- tool panel from notepage.es. save & savecomment icons from Retina Display Icon Set. -->
<div id="toolpanel" class="edit" style="width: 500px; right: 0px; "> <div id="toolpanel" class="toolpanel edit" style="width: 500px; right: 0px; ">
<a id="save" class="edit"><img src="images/save_24.png" alt="Save" title="Save"></a> <a id="save" class="edit"><img src="images/save_24.png" alt="save" title="save"></a>
<a id="savecomment" class="edit"><img src="images/savecomment_24.png" alt="Save with comment" title="Save with comment"></a> <a id="savecomment" class="edit"><img src="images/savecomment_24.png" alt="Save with comment" title="Save with comment"></a>
<a id="toggle" class="edit" href="javascript:void(0)" onclick="jsm.toggleLeftRight();"><img src="images/lr_24.png" alt="Toggle left to right" title="Toggle left to right"></a> <a id="toggle" class="edit" href="javascript:void(0)" onclick="jsm.toggleLeftRight();"><img src="images/lr_24.png" alt="Toggle left to right" title="Toggle left to right"></a>
</div> </div>
<div id="commenttoolpanel" class="toolpanel edit" style="width: 500px; right: 0px; ">
<a id="savecommentconfirm" class="edit"><img src="images/savecomment_24.png" alt="Confirm save with comment" title="Confirm save with comment"></a>
<a id="commentcancel" class="edit"><img src="images/cancel_24.png" alt="Cancel save with comment" title="Cancel save with comment"></a>
</div>
<div id="comment"></div>
<div id="darkness"></div>
<script type="text/javascript"> <script type="text/javascript">
(function () { (function () {
var converter = Markdown.getSanitizingConverter(); var converter = Markdown.getSanitizingConverter();
var editor = ace.edit("editor"); var editor = ace.edit("editor");
var editorSession = editor.getSession(); var editorSession = editor.getSession();
var editorContainer = editor.container;
var preview = document.getElementById("previewframe"); var preview = document.getElementById("previewframe");
var content = document.getElementById("contentframe"); var content = document.getElementById("contentframe");
var toolPanel = document.getElementById("toolpanel"); var toolPanel = document.getElementById("toolpanel");
var comment = document.getElementById("comment");
var commentToolPanel = document.getElementById("commenttoolpanel");
// dim the page
var darkness = document.getElementById("darkness");
var leftRight = true; var leftRight = true;
var jsm = {}; // JavaScript Markdown var jsm = {}; // JavaScript Markdown
@@ -43,18 +57,29 @@ window.jsm.toggleLeftRight = function() {
jsm.resize(); jsm.resize();
} }
editor.setTheme("ace/theme/twilight");
var MarkdownMode = require("ace/mode/markdown").Mode; var MarkdownMode = require("ace/mode/markdown").Mode;
editorSession.setMode(new MarkdownMode()); function initAce(editor, editorSession) {
// Gutter shows line numbers editor.setTheme("ace/theme/twilight");
editor.renderer.setShowGutter(true); editorSession.setMode(new MarkdownMode());
editor.renderer.setHScrollBarAlwaysVisible(false); // Gutter shows line numbers
editorSession.setUseSoftTabs(true); editor.renderer.setShowGutter(true);
editorSession.setTabSize(2); editor.renderer.setHScrollBarAlwaysVisible(false);
editorSession.setUseWrapMode(true); editorSession.setUseSoftTabs(true);
editor.setShowPrintMargin(false); editorSession.setTabSize(2);
editor.setBehavioursEnabled(true); editorSession.setUseWrapMode(true);
editor.setShowPrintMargin(false);
editor.setBehavioursEnabled(true);
}
initAce(editor, editorSession);
// Setup comment ace.
var commentEditor = ace.edit("comment"); // Comment Editor
var commentEditorSession = commentEditor.getSession(); // Comment Editor Session
var commentEditorContainer = commentEditor.container; // COmment Editor Container
initAce(commentEditor, commentEditorSession);
window.onload = function() { window.onload = function() {
// RegExp from http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript // RegExp from http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
@@ -72,21 +97,21 @@ window.onload = function() {
} }
}); });
$.save = function() { $.save = function( commitMessage ) {
// if &create=true then handle create instead of edit. // if &create=true then handle create instead of edit.
var create = $.key("create"); var create = $.key("create");
var POST = "POST"; var POST = "POST";
var pageName = $.key("page"); var pageName = $.key("page");
var markdown = "markdown"; var markdown = "markdown";
var txt = editorSession.getValue(); var txt = editorSession.getValue();
var msg = pageName + " ("+markdown+")" var msg = pageName + " (" + markdown + ")"
var newLocation = window.location.origin + "/" + pageName; var newLocation = window.location.origin + "/" + pageName;
if (create) { if (create) {
jQuery.ajax({ jQuery.ajax({
type: POST, type: POST,
url: "/create", url: "/create",
data: { page: pageName, format: markdown, content: txt, message: "Created " + msg }, data: { page: pageName, format: markdown, content: txt, message: commitMessage || "Created " + msg },
success: function() { success: function() {
window.location = newLocation; window.location = newLocation;
} }
@@ -95,7 +120,7 @@ window.onload = function() {
jQuery.ajax({ jQuery.ajax({
type: POST, type: POST,
url: "/edit/" + pageName, url: "/edit/" + pageName,
data: { format: markdown, content: txt, message: "Updated " + msg }, data: { format: markdown, content: txt, message: commitMessage || "Updated " + msg },
success: function() { success: function() {
window.location = newLocation; window.location = newLocation;
} }
@@ -103,12 +128,35 @@ window.onload = function() {
} // end else } // end else
} }
$('#save').click(function() { $("#save").click(function() {
$.save(); $.save();
}); });
$('#savecomment').click(function() { // Hide dimmer, comment tool panel, and comment.
$.save(); $("#commentcancel").click(function() {
hideCommentWindow();
});
var isCommentHidden = true;
function hideCommentWindow() {
isCommentHidden = true;
darkness.style.visibility = "hidden";
commentToolPanel.style.visibility = "hidden";
comment.style.visibility = "hidden";
}
// Show dimmer, comment tool panel, and comment.
$("#savecomment").click(function() {
isCommentHidden = false;
darkness.style.visibility = "visible";
commentToolPanel.style.visibility = "visible";
comment.style.visibility = "visible";
});
$("#savecommentconfirm").click(function() {
$.save(ces.getValue());
hideCommentWindow();
}); });
// onChange calls applyTimeout which rate limits the calling of makePreviewHtml based on render time. // onChange calls applyTimeout which rate limits the calling of makePreviewHtml based on render time.
@@ -116,33 +164,68 @@ window.onload = function() {
makePreviewHtml(); // preview default text on load makePreviewHtml(); // preview default text on load
function resize() { function resize() {
var ace = editor.container;//document.getElementById("editor"); var width = $(window).width();
var widthHalf = $(window).width() / 2; var widthHalf = width / 2;
var widthFourth = widthHalf / 2;
var height = $(window).height(); var height = $(window).height();
ace.style.width = widthHalf + "px"; var heightHalf = height / 2;
// Minus 50 so the end of document text doesn't flow off the page.
ace.style.height = height - 50 + "px"; // height minus 50 so the end of document text doesn't flow off the page.
ace.style.left = leftRight === false ? widthHalf + "px" : "0px"; var editorContainerStyle = "width:" + widthHalf + "px;" +
ace.style.top = "40px"; // use 40px for tool menu "height:" + (height - 50) + "px;" +
ace.style.fontSize = 16 + "px"; "left:" + (leftRight === false ? widthHalf + "px;" : "0px;") +
"top:" + "40px;"; // use 40px for tool menu
cssSet( editorContainer, editorContainerStyle );
editor.resize(); editor.resize();
var previewFrame = document.getElementById("previewframe"); // width -2 for scroll bar & -10 for left offset
previewFrame.style.width = widthHalf - 2 - 10 + "px"; // -2 for scroll bar & -10 for left offset var previewStyle = "width:" + (widthHalf - 2 - 10) + "px;" +
previewFrame.style.height = height + "px"; "height:" + height + "px;" +
previewFrame.style.left = leftRight === false ? "10px" : widthHalf + "px"; "left:" + (leftRight === false ? "10px;" : widthHalf + "px;") +
previewFrame.style.top = "0px"; "top:" + "0px;";
cssSet( preview, previewStyle );
// Resize tool panel // Resize tool panel
toolPanel.style.width = widthHalf + "px"; var toolPanelStyle = "width:" + widthHalf + "px;" +
toolPanel.style.left = leftRight === false ? widthHalf + "px" : "0px"; "left:" + (leftRight === false ? widthHalf + "px;" : "0px;");
cssSet( toolPanel, toolPanelStyle );
// Resize comment related elements.
var commentHidden = "visibility:" + ( isCommentHidden === true ? "hidden;" : "visible;" );
// Adjust comment editor
var commentEditorContainerStyle = "height:" + heightHalf + "px;" +
"width:" + widthHalf + "px;" +
"left:" + widthFourth + "px;" +
"top:" + (heightHalf / 2) + "px;" +
commentHidden;
cssSet( commentEditorContainer, commentEditorContainerStyle );
commentEditor.resize();
// In top subtract height (40px) of comment tool panel.
var commentToolPanelStyle = "width:" + widthHalf + "px;" +
"left:" + widthFourth + "px;" +
"top:" + (height / 4 - 40) + "px;" +
commentHidden;
cssSet( commentToolPanel, commentToolPanelStyle );
// Resize dimmer.
var darknessStyle = "width:" + width + "px;" +
"height:" + height + "px;" +
commentHidden;
cssSet(darkness, darknessStyle);
} }
window.jsm.resize = resize; window.jsm.resize = resize;
$(window).resize(function() { /*
resize(); Resize can be called an absurd amount of times
}); and will crash the page without debouncing.
http://benalman.com/projects/jquery-throttle-debounce-plugin/
https://github.com/cowboy/jquery-throttle-debounce
http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
*/
$(window).resize( $.debounce( 100, resize ) );
// resize for the intial page load // resize for the intial page load
resize(); resize();
@@ -152,7 +235,6 @@ var elapsedTime;
var oldInputText = ""; var oldInputText = "";
// ---- from Markdown.Editor // ---- from Markdown.Editor
var previewSetter;
var timeout; var timeout;
var nonSuckyBrowserPreviewSet = function (text) { var nonSuckyBrowserPreviewSet = function (text) {
@@ -173,16 +255,39 @@ var ieSafePreviewSet = function (text) {
parent.insertBefore(content, sibling); parent.insertBefore(content, sibling);
} }
var previewSet = function (text) { var cssTextSet = function( element, css ){
if (previewSetter) element.style.cssText = css;
return previewSetter(text); }
var cssAttrSet = function( element, css ){
element.setAttribute( 'style', css );
}
/*
Redefine the function based on browser support.
element - the element to set the css on
css - a fully formed css string. ex: "top: 0; left: 0;"
Avoid reflow by batching CSS changes.
http://dev.opera.com/articles/view/efficient-javascript/?page=3#stylechanges
*/
var cssSet = function( element, css ) {
if( typeof( element.style.cssText ) != 'undefined' ) {
cssTextSet( element, css );
cssSet = cssTextSet;
} else {
cssAttrSet( element, css );
cssSet = cssAttrSet;
}
}
var previewSet = function( text ) {
try { try {
nonSuckyBrowserPreviewSet(text); nonSuckyBrowserPreviewSet( text );
previewSetter = nonSuckyBrowserPreviewSet; previewSet = nonSuckyBrowserPreviewSet;
} catch (e) { } catch (e) {
previewSetter = ieSafePreviewSet; ieSafePreviewSet( text );
previewSetter(text); previewSet = ieSafePreviewSet;
} }
}; };