Switch to ACE editor

This commit is contained in:
benweet 2013-09-15 02:35:58 +01:00
parent ca34415d22
commit 99e5b27fa4
13 changed files with 132 additions and 118 deletions

View File

@ -18,6 +18,6 @@
"stacktrace": "~0.5.3",
"requirejs-text": "~2.0.10",
"bootstrap-tour": "~0.6.0",
"ace": "~1.1.1"
"ace": "#51b7cb67a63998c9c0b7d089a85c60e032a7cc17"
}
}

View File

@ -118,8 +118,8 @@ define([
utils.setInputValue("#input-settings-editor-font-family", settings.editorFontFamily);
// Editor font size
utils.setInputValue("#input-settings-editor-font-size", settings.editorFontSize);
// Editor max width
utils.setInputValue("#input-settings-editor-max-width", settings.editorMaxWidth);
// Max width
utils.setInputValue("#input-settings-max-width", settings.maxWidth);
// Default content
utils.setInputValue("#textarea-settings-default-content", settings.defaultContent);
// Commit message
@ -147,8 +147,8 @@ define([
newSettings.editorFontFamily = utils.getInputTextValue("#input-settings-editor-font-family", event);
// Editor font size
newSettings.editorFontSize = utils.getInputIntValue("#input-settings-editor-font-size", event, 1, 99);
// Editor max width
newSettings.editorMaxWidth = utils.getInputIntValue("#input-settings-editor-max-width", event, 1);
// Max width
newSettings.maxWidth = utils.getInputIntValue("#input-settings-max-width", event, 1);
// Default content
newSettings.defaultContent = utils.getInputValue("#textarea-settings-default-content");
// Commit message
@ -212,52 +212,73 @@ define([
aceEditor.renderer.setPadding(EDITOR_DEFAULT_PADDING);
aceEditor.session.setUseWrapMode(true);
aceEditor.session.setMode("libs/ace_mode");
// Make titles bold...
// Make bold titles...
(function(self) {
function checkLine(currentLine) {
var line = self.lines[currentLine];
if(line.length !== 0) {
if(line[0].type.indexOf("markup.heading.multi") === 0) {
_.each(self.lines[currentLine - 1], function(previousLineObject) {
previousLineObject.type = "markup.heading.prev.multi";
});
}
}
}
function customWorker() {
if (!self.running) { return; }
// Duplicate from background_tokenizer.js
if(!self.running) {
return;
}
var workerStart = new Date();
var startLine = self.currentLine;
var currentLine = self.currentLine;
var endLine = -1;
var doc = self.doc;
var processedLines = 0;
while (self.lines[currentLine]) {
currentLine++;
}
var startLine = currentLine;
var len = doc.getLength();
while (self.currentLine < len) {
self.$tokenizeRow(self.currentLine);
while (self.lines[self.currentLine]) {
var line = self.lines[self.currentLine];
if(line.length !== 0 && line[0].type.indexOf("markup.heading.multi") === 0) {
_.each(self.lines[self.currentLine-1], function(previousLineObject) {
previousLineObject.type = "markup.heading.prev.multi";
});
}
self.currentLine++;
}
var processedLines = 0;
self.running = false;
while (currentLine < len) {
self.$tokenizeRow(currentLine);
endLine = currentLine;
do {
checkLine(currentLine); // benweet
currentLine++;
} while (self.lines[currentLine]);
// only check every 5 lines
processedLines ++;
if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
self.fireUpdateEvent(startLine, self.currentLine-1);
self.running = setTimeout(customWorker, 20);
processedLines++;
if((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
self.running = setTimeout(customWorker, 20); // benweet
self.currentLine = currentLine;
return;
}
}
self.currentLine = currentLine;
self.running = false;
self.fireUpdateEvent(startLine, len - 1);
if(startLine <= endLine)
self.fireUpdateEvent(startLine, endLine);
}
;
self.$worker = function() {
self.currentLine = self.currentLine ? self.currentLine - 1 : 0;
self.lines.splice(0, self.lines.length);
self.states.splice(0, self.states.length);
self.currentLine = 0;
customWorker();
};
})(aceEditor.session.bgTokenizer);
eventMgr.onAceCreated(aceEditor);
window.aceEditor = aceEditor;
}
// Create the layout
function createLayout() {
var layoutGlobalConfig = {
@ -291,8 +312,11 @@ define([
onresize_end: function(paneName) {
if(aceEditor !== undefined && paneName == 'center') {
aceEditor.resize();
var bottomMargin = (aceEditor.renderer.$size.scrollerHeight - aceEditor.renderer.lineHeight) / 2;
bottomMargin < 0 && (bottomMargin = 0);
aceEditor.renderer.setScrollMargin(0, bottomMargin, 0, 0);
setTimeout(function() {
var padding = (aceEditor.renderer.$size.scrollerWidth - settings.editorMaxWidth)/2;
var padding = (aceEditor.renderer.$size.scrollerWidth - settings.maxWidth) / 2;
if(padding < EDITOR_DEFAULT_PADDING) {
padding = EDITOR_DEFAULT_PADDING;
}
@ -301,7 +325,7 @@ define([
aceEditor.resize(true);
}
}, 5);
}
}
eventMgr.onLayoutResize(paneName);
},
};
@ -324,6 +348,7 @@ define([
south__minSize: 200
}));
}
settings.maxWidth && $('#preview-contents').css('max-width', (settings.maxWidth + 30) + 'px');
$(".navbar").click(function() {
layout.allowOverflow('north');
});
@ -335,16 +360,16 @@ define([
// have fixed position
// We also move the north toggler to the east or south resizer as the
// north resizer is very small
var $previewButtonsContainerElt = $('<div class="preview-button-container">');
$previewButtonsElt = $('<div class="extension-preview-buttons">').appendTo($previewButtonsContainerElt);
// var $previewButtonsContainerElt = $('<div
// class="preview-button-container">');
$previewButtonsElt = $('<div class="extension-preview-buttons">');
$editorButtonsElt = $('<div class="extension-editor-buttons">');
if(settings.layoutOrientation == "horizontal") {
$('.ui-layout-resizer-north').append($previewButtonsContainerElt);
if(viewerMode || settings.layoutOrientation == "horizontal") {
$('.ui-layout-resizer-north').append($previewButtonsElt);
$('.ui-layout-resizer-east').append($northTogglerElt).append($editorButtonsElt);
}
else {
$previewButtonsContainerElt.append($editorButtonsElt);
$('.ui-layout-resizer-south').append($previewButtonsContainerElt).append($northTogglerElt);
$('.ui-layout-resizer-south').append($previewButtonsElt).append($editorButtonsElt).append($northTogglerElt);
}
setPanelVisibility();
@ -374,7 +399,7 @@ define([
else {
$editorElt.val(initDocumentContent);
}
if(editor !== undefined) {
// If the editor is already created
aceEditor && aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange);
@ -432,7 +457,7 @@ define([
eventMgr.onSectionsCreated(sectionList);
return text;
});
function checkDocumentChanges() {
var newDocumentContent = $editorElt.val();
if(aceEditor !== undefined) {
@ -444,7 +469,7 @@ define([
}
documentContent = newDocumentContent;
}
if(!lightMode) {
editor = new Markdown.Editor(converter);
// Custom insert link dialog
@ -490,7 +515,9 @@ define([
$editorElt.on("input propertychange", previewWrapper);
editor = {
hooks: hooks,
getConverter: function () { return converter; },
getConverter: function() {
return converter;
},
run: previewWrapper,
refreshPreview: previewWrapper
};
@ -502,10 +529,10 @@ define([
var debouncedMakePreview = _.debounce(makePreview, 500);
return function() {
if(documentContent === undefined) {
aceEditor.renderer.scrollToY(fileDesc.editorScrollTop);
makePreview();
$previewContainerElt.scrollTop(fileDesc.previewScrollTop);
_.defer(function() {
aceEditor.renderer.scrollToY(fileDesc.editorScrollTop);
eventMgr.onFileOpen(fileDesc);
});
}
@ -639,7 +666,7 @@ define([
// ACE editor
createAceEditor();
// Editor's element
$editorElt = $("#wmd-input").css({
// Apply editor font
@ -666,6 +693,11 @@ define([
// Other initialization that are not prioritary
eventMgr.addListener("onReady", function() {
// In vertical mode, we have to offset the editor buttons otherwise they hide the editor buttons
if(!viewerMode && settings.layoutOrientation == "vertical") {
$previewButtonsElt.css('right', parseInt($previewButtonsElt.css('right')) + $editorButtonsElt.width());
}
var isModalShown = false;
$('.modal').on('show.bs.modal', function() {

View File

@ -7,7 +7,6 @@ define([
"settings",
"text!html/settingsExtensionsAccordion.html",
"extensions/partialRendering",
"extensions/userCustom",
"extensions/buttonMarkdownSyntax",
"extensions/googleAnalytics",
"extensions/dialogAbout",
@ -33,6 +32,7 @@ define([
"extensions/buttonHtmlCode",
"extensions/buttonViewer",
"extensions/welcomeTour",
"extensions/userCustom",
"bootstrap",
"jquery-waitforimages"
], function($, _, crel, utils, Extension, settings, settingsExtensionsAccordionHTML) {
@ -136,8 +136,8 @@ define([
addEventHook("onError");
addEventHook("onOfflineChanged");
addEventHook("onUserActive");
addEventHook("onAsyncRunning", true);
addEventHook("onPeriodicRun", true);
addEventHook("onAsyncRunning");
addEventHook("onPeriodicRun");
// To access modules that are loaded after extensions
addEventHook("onFileMgrCreated");
@ -184,17 +184,13 @@ define([
var onPreviewFinished = createEventHook("onPreviewFinished");
var onAsyncPreviewListenerList = getExtensionListenerList("onAsyncPreview");
// The number of times we expect tryFinished to be called
var nbAsyncPreviewListener = onAsyncPreviewListenerList.length + 1;
var previewContentsElt = undefined;
var $previewContentsElt = undefined;
eventMgr["onAsyncPreview"] = function() {
logger.log("onAsyncPreview");
logger.log("Conversion time: " + (new Date() - eventMgr.previewStartTime));
// Call onPreviewFinished listeners when all async preview are finished
var counter = 0;
function tryFinished() {
if(++counter === nbAsyncPreviewListener) {
function recursiveCall(callbackList) {
var callback = callbackList.length ? callbackList.shift() : function() {
logger.log("Preview time: " + (new Date() - eventMgr.previewStartTime));
_.defer(function() {
var html = "";
@ -203,13 +199,15 @@ define([
});
onPreviewFinished(utils.trim(html));
});
}
};
callback(function() {
recursiveCall(callbackList);
});
}
// We assume images are loading in the preview
$previewContentsElt.waitForImages(tryFinished);
_.each(onAsyncPreviewListenerList, function(asyncPreviewListener) {
asyncPreviewListener(tryFinished);
});
recursiveCall(onAsyncPreviewListenerList.concat([function(callback) {
// We assume some images are loading asynchronously after the preview
$previewContentsElt.waitForImages(callback);
}]));
};
var onReady = createEventHook("onReady");
@ -255,27 +253,6 @@ define([
});
document.getElementById('extension-buttons').appendChild(extensionButtonsFragment);
// Create extension preview buttons
logger.log("onCreatePreviewButton");
var onCreatePreviewButtonListenerList = getExtensionListenerList("onCreatePreviewButton");
var extensionPreviewButtonsFragment = document.createDocumentFragment();
_.each(onCreatePreviewButtonListenerList, function(listener) {
extensionPreviewButtonsFragment.appendChild(createBtn(listener));
});
var previewButtonsElt = document.querySelector('.extension-preview-buttons');
previewButtonsElt.appendChild(extensionPreviewButtonsFragment);
// A bit of jQuery...
var $previewButtonsElt = $(previewButtonsElt);
var previewButtonsWidth = $previewButtonsElt.width();
$previewButtonsElt.find('.btn-group').each(function() {
var $btnGroupElt = $(this);
// Align dropdown to the left of the screen
$btnGroupElt.find('.dropdown-menu').css({
right: -previewButtonsWidth + $btnGroupElt.width() + $btnGroupElt.position().left
});
});
// Create extension editor buttons
logger.log("onCreateEditorButton");
var onCreateEditorButtonListenerList = getExtensionListenerList("onCreateEditorButton");
@ -287,6 +264,27 @@ define([
editorButtonsElt.appendChild(extensionEditorButtonsFragment);
}
// Create extension preview buttons
logger.log("onCreatePreviewButton");
var onCreatePreviewButtonListenerList = getExtensionListenerList("onCreatePreviewButton");
var extensionPreviewButtonsFragment = document.createDocumentFragment();
_.each(onCreatePreviewButtonListenerList, function(listener) {
extensionPreviewButtonsFragment.appendChild(createBtn(listener));
});
var previewButtonsElt = document.querySelector('.extension-preview-buttons');
previewButtonsElt.appendChild(extensionPreviewButtonsFragment);
// A bit of jQuery...
var $previewButtonsElt = $(previewButtonsElt);
var previewButtonsWidth = $previewButtonsElt.width();
$previewButtonsElt.find('.btn-group').each(function() {
var $btnGroupElt = $(this);
// Align dropdown to the left of the screen
$btnGroupElt.find('.dropdown-menu').css({
right: -previewButtonsWidth + $btnGroupElt.width() + $btnGroupElt.position().left
});
});
// Call onReady listeners
onReady();
};

View File

@ -4,7 +4,7 @@ define([
"text!html/buttonMarkdownSyntax.html",
], function($, Extension, buttonMarkdownSyntaxHTML) {
var buttonMarkdownSyntax = new Extension("buttonMarkdownSyntax", 'Button "Markdown syntax', true);
var buttonMarkdownSyntax = new Extension("buttonMarkdownSyntax", 'Button "Markdown syntax', true, true);
buttonMarkdownSyntax.settingsBlock = '<p>Adds a "Markdown syntax" button over the preview.</p>';
buttonMarkdownSyntax.onCreatePreviewButton = function() {

View File

@ -4,7 +4,7 @@ define([
"text!html/buttonViewer.html",
], function($, Extension, buttonViewerHTML) {
var buttonViewer = new Extension("buttonViewer", 'Button "Viewer"', true);
var buttonViewer = new Extension("buttonViewer", 'Button "Viewer"', true, true);
buttonViewer.settingsBlock = '<p>Adds a "Viewer" button over the preview.</p>';
buttonViewer.onCreatePreviewButton = function() {

View File

@ -9,6 +9,7 @@ define([
var dialogAbout = new Extension("dialogAbout", 'Dialog "About"');
var libraries = {
"ACE": "http://ace.c9.io/",
"Bootstrap": "http://getbootstrap.com/",
"Bootstrap Tour": "http://bootstraptour.com/",
"crel": "https://github.com/KoryNunn/crel",

View File

@ -65,7 +65,7 @@ define([
Markdown.Extra.init(converter, options);
// Store extensions list in converter for partialRendering
converter.extraExtensions = markdownExtra.config.extensions;
converter.setExtraExtension && converter.setExtraExtension(markdownExtra.config.extensions);
};
return markdownExtra;

View File

@ -122,7 +122,7 @@ define([
class: 'wmd-preview-section preview-content'
});
var isFirst = true;
while(childNode) {
while (childNode) {
var nextNode = childNode.nextSibling;
if(isFirst === false && /(^| )wmd-title($| )/.test(childNode.className)) {
// Stop when encountered the next wmd-title
@ -140,7 +140,8 @@ define([
sectionElt.appendChild(childNode);
}
childNode = nextNode;
};
}
;
newSectionEltList.appendChild(sectionElt);
});
wmdPreviewElt.innerHTML = '';
@ -184,6 +185,11 @@ define([
editor.hooks.chain("onPreviewRefresh", function() {
refreshSections();
});
converter.setExtraExtension = function(extraExtensions) {
doFootnotes = _.some(extraExtensions, function(extension) {
return extension == "footnotes";
});
};
};
partialRendering.onReady = function() {
@ -199,13 +205,5 @@ define([
fileChanged = true;
};
partialRendering.onFileOpen = function() {
if(converter.extraExtensions) {
doFootnotes = _.some(converter.extraExtensions, function(extension) {
return extension == "footnotes";
});
}
};
return partialRendering;
});

View File

@ -946,10 +946,10 @@
</div>
<div class="form-group">
<label class="col-lg-4 control-label"
for="input-settings-editor-max-width">Editor max width</label>
for="input-settings-max-width">Max width</label>
<div class="col-lg-8 form-inline">
<input type="text"
id="input-settings-editor-max-width"
id="input-settings-max-width"
class="form-control col-lg-3"> px
</div>
</div>

View File

@ -48,7 +48,7 @@ var Mode = function() {
oop.inherits(Mode, TextMode);
(function() {
this.type = "text";
this.lineCommentStart = ">";
this.getNextLineIndent = function(state, line, tab) {

View File

@ -113,7 +113,7 @@ var MarkdownHighlightRules = function() {
}, { // list
token : "markup.list",
regex : "^\\s{0,3}(?:[*+-]|\\d+\\.)\\s+",
next : "listblock"
next : "listblock-start"
}, {
include : "basic"
}],
@ -127,13 +127,11 @@ var MarkdownHighlightRules = function() {
defaultToken : "markup.heading"
} ],
/* don't need checkbox highlighting...
"listblock-start" : [{
token : "checkbox",
regex : /(?:\[[ x]\])?/,
next : "listblock"
}],
*/
"listblock" : [ { // Lists only escape on completely blank lines.
token : "empty_line",
@ -142,7 +140,7 @@ var MarkdownHighlightRules = function() {
}, { // list
token : "markup.list",
regex : "^\\s{0,3}(?:[*+-]|\\d+\\.)\\s+",
next : "listblock"
next : "listblock-start"
}, {
include : "basic", noEscape: true
}, {

View File

@ -8,7 +8,7 @@ define([
lazyRendering: true,
editorFontFamily: 'Menlo, Consolas, "Courier New", Courier, monospace',
editorFontSize: 12,
editorMaxWidth: 960,
maxWidth: 960,
defaultContent: "\n\n\n> Written with [StackEdit](" + MAIN_URL + ").",
commitMsg: "Published with " + MAIN_URL,
template: [

View File

@ -112,7 +112,7 @@ body {
#preview-contents {
padding: 15px;
margin-bottom: 50px;
margin: 0 auto 50px;
.ui-layout-east & {
padding-left: 5px;
}
@ -567,19 +567,11 @@ body {
* Preview/Editor extensions buttons
********************/
.preview-button-container {
position: absolute;
right: 0;
.extension-editor-buttons {
position: relative;
}
}
.extension-preview-buttons {
display: inline-block;
z-index: 1;
position: absolute;
z-index: 1;
margin-top: 6px;
margin-right: 30px;
right: 30px;
.ui-layout-resizer-south-closed & {
display: none !important;
}
@ -1231,11 +1223,6 @@ div.jGrowl {
line-height: @input-height-base;
}
#preview-contents {
max-width: 1024px;
margin: 0 auto;
}
.document-panel .search-bar {
padding: 20px 20px 10px;
.input-group-btn {