Switch to ACE editor

This commit is contained in:
benweet 2013-09-10 00:32:24 +01:00
parent 24ba484010
commit 582337d595
18 changed files with 198 additions and 215 deletions

View File

@ -18,7 +18,7 @@ define([
return new Range(rangeComponents[0], rangeComponents[1], rangeComponents[2], rangeComponents[3]); return new Range(rangeComponents[0], rangeComponents[1], rangeComponents[2], rangeComponents[3]);
} }
catch(e) { catch(e) {
return new Range(); return new Range(0, 0, 0, 0);
} }
})(); })();
this._editorEnd = parseInt(localStorage[fileIndex + ".editorEnd"]) || 0; this._editorEnd = parseInt(localStorage[fileIndex + ".editorEnd"]) || 0;

View File

@ -187,56 +187,64 @@ define([
} }
} }
// Create the layout // Create ACE editor
var aceEditor = undefined; var aceEditor = undefined;
function createLayout() { function createAceEditor() {
aceEditor = ace.edit("wmd-input"); aceEditor = ace.edit("wmd-input");
aceEditor.renderer.setShowGutter(false); aceEditor.renderer.setShowGutter(false);
aceEditor.renderer.setShowPrintMargin(false); aceEditor.renderer.setShowPrintMargin(false);
aceEditor.renderer.setPrintMarginColumn(false); aceEditor.renderer.setPrintMarginColumn(false);
aceEditor.renderer.setPadding(12); aceEditor.renderer.setPadding(10);
aceEditor.session.setUseWrapMode(true); aceEditor.session.setUseWrapMode(true);
aceEditor.session.setMode("libs/acemode"); aceEditor.session.setMode("libs/acemode");
// Make bold titles... // Make bold titles...
(function(bgTokenizer) { (function(self) {
var worker = bgTokenizer.$worker; function customWorker() {
bgTokenizer.$worker = function() { if (!self.running) { return; }
bgTokenizer.currentLine = bgTokenizer.currentLine ? bgTokenizer.currentLine - 1 : 0;
worker(); var workerStart = new Date();
_.each(bgTokenizer.lines, function(line, i) { var startLine = self.currentLine;
if(i !== 0 && line && line.length !== 0 && line[0].type.indexOf("markup.heading.multi") === 0) { var doc = self.doc;
_.each(bgTokenizer.lines[i-1], function(previousLineObject) {
previousLineObject.type = "markup.heading.prev.multi"; var processedLines = 0;
});
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++;
} }
});
// 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);
return;
}
}
self.running = false;
self.fireUpdateEvent(startLine, len - 1);
}
self.$worker = function() {
self.currentLine = self.currentLine ? self.currentLine - 1 : 0;
customWorker();
}; };
})(aceEditor.session.bgTokenizer); })(aceEditor.session.bgTokenizer);
eventMgr.onAceCreated(aceEditor);
window.aceEditor = aceEditor;
window.wmdInput = { }
editor: aceEditor,
focus: function() { // Create the layout
aceEditor.focus(); function createLayout() {
}
};
Object.defineProperty(window.wmdInput, 'value', {
get: function() {
return aceEditor.getValue();
},
set: function(value) {
aceEditor.setValue(value);
}
});
Object.defineProperty(window.wmdInput, 'scrollTop', {
get: function() {
return aceEditor.renderer.getScrollTop();
},
set: function(value) {
aceEditor.renderer.scrollToY(value);
}
});
var layoutGlobalConfig = { var layoutGlobalConfig = {
closable: true, closable: true,
resizable: false, resizable: false,
@ -319,7 +327,7 @@ define([
var editor = undefined; var editor = undefined;
var fileDesc = undefined; var fileDesc = undefined;
var documentContent = undefined; var documentContent = undefined;
var $editorElt = undefined; var UndoManager = require("ace/undomanager").UndoManager;
core.initEditor = function(fileDescParam) { core.initEditor = function(fileDescParam) {
if(fileDesc !== undefined) { if(fileDesc !== undefined) {
eventMgr.onFileClosed(fileDesc); eventMgr.onFileClosed(fileDesc);
@ -329,15 +337,12 @@ define([
var initDocumentContent = fileDesc.content; var initDocumentContent = fileDesc.content;
aceEditor.setValue(initDocumentContent, -1); aceEditor.setValue(initDocumentContent, -1);
_.defer(function() { aceEditor.getSession().setUndoManager(new UndoManager());
aceEditor.session.getUndoManager().reset();
});
if(editor !== undefined) { if(editor !== undefined) {
// If the editor is already created // If the editor is already created
aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange); aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange);
aceEditor.renderer.scrollToY(fileDesc.editorScrollTop);
aceEditor.focus(); aceEditor.focus();
eventMgr.onFileOpen(fileDesc);
editor.refreshPreview(); editor.refreshPreview();
return; return;
} }
@ -345,9 +350,12 @@ define([
var $previewContainerElt = $(".preview-container"); var $previewContainerElt = $(".preview-container");
// Store editor scrollTop on scroll event // Store editor scrollTop on scroll event
var debouncedUpdateScroll = _.debounce(function() {
fileDesc.editorScrollTop = aceEditor.renderer.getScrollTop();
}, 100);
aceEditor.session.on('changeScrollTop', function() { aceEditor.session.on('changeScrollTop', function() {
if(documentContent !== undefined) { if(documentContent !== undefined) {
fileDesc.editorScrollTop = aceEditor.renderer.getScrollTop(); debouncedUpdateScroll();
} }
}); });
// Store editor selection on change // Store editor selection on change
@ -419,9 +427,12 @@ define([
var debouncedMakePreview = _.debounce(makePreview, 500); var debouncedMakePreview = _.debounce(makePreview, 500);
return function() { return function() {
if(documentContent === undefined) { if(documentContent === undefined) {
aceEditor.renderer.scrollToY(fileDesc.editorScrollTop);
makePreview(); makePreview();
//$editorElt.scrollTop(fileDesc.editorScrollTop);
$previewContainerElt.scrollTop(fileDesc.previewScrollTop); $previewContainerElt.scrollTop(fileDesc.previewScrollTop);
_.defer(function() {
eventMgr.onFileOpen(fileDesc);
});
} }
else { else {
debouncedMakePreview(); debouncedMakePreview();
@ -441,13 +452,12 @@ define([
}; };
}; };
} }
eventMgr.onEditorConfigure(editor); eventMgr.onPagedownConfigure(editor);
editor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview); editor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview);
editor.run(previewWrapper); editor.run(aceEditor, previewWrapper);
// editor.undoManager.reinit(initDocumentContent, fileDesc.editorStart, // editor.undoManager.reinit(initDocumentContent, fileDesc.editorStart,
// fileDesc.editorEnd, fileDesc.editorScrollTop); // fileDesc.editorEnd, fileDesc.editorScrollTop);
aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange); aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange);
aceEditor.renderer.scrollToY(fileDesc.editorScrollTop);
aceEditor.focus(); aceEditor.focus();
// Hide default buttons // Hide default buttons
@ -470,23 +480,6 @@ define([
var $btnGroupElt = $('.wmd-button-group4'); var $btnGroupElt = $('.wmd-button-group4');
$("#wmd-undo-button").append($('<i class="icon-reply">')).appendTo($btnGroupElt); $("#wmd-undo-button").append($('<i class="icon-reply">')).appendTo($btnGroupElt);
$("#wmd-redo-button").append($('<i class="icon-forward">')).appendTo($btnGroupElt); $("#wmd-redo-button").append($('<i class="icon-forward">')).appendTo($btnGroupElt);
eventMgr.onFileOpen(fileDesc);
};
// Used to lock the editor from the user interaction during asynchronous
// tasks
var uiLocked = false;
core.lockUI = function(param) {
uiLocked = param;
$editorElt.prop("disabled", uiLocked);
$(".navbar-inner .btn").toggleClass("blocked", uiLocked);
if(uiLocked) {
$(".lock-ui").removeClass("hide");
}
else {
$(".lock-ui").addClass("hide");
}
}; };
// Initialize multiple things and then fire eventMgr.onReady // Initialize multiple things and then fire eventMgr.onReady
@ -569,29 +562,18 @@ define([
} }
}); });
// UI layout
createLayout();
$editorElt = $("#wmd-input");
// Editor's textarea // Editor's textarea
$("#wmd-input, #md-section-helper").css({ $("#wmd-input").css({
// Apply editor font // Apply editor font
"font-family": settings.editorFontFamily, "font-family": settings.editorFontFamily,
"font-size": settings.editorFontSize + "px", "font-size": settings.editorFontSize + "px",
"line-height": Math.round(settings.editorFontSize * (20 / 14)) + "px" "line-height": Math.round(settings.editorFontSize * (20 / 12)) + "px"
}); });
// Handle tab key // ACE editor
$editorElt.keydown(function(e) { createAceEditor();
if(e.keyCode === 9) { // UI layout
var value = $editorElt.val(); createLayout();
var start = this.selectionStart;
var end = this.selectionEnd;
$(this).val(value.substring(0, start) + "\t" + value.substring(end));
this.selectionStart = this.selectionEnd = start + 1;
e.preventDefault();
}
});
// Do periodic tasks // Do periodic tasks
intervalId = window.setInterval(function() { intervalId = window.setInterval(function() {
@ -617,13 +599,14 @@ define([
isModalShown = true; isModalShown = true;
}).on('shown.bs.modal', function() { }).on('shown.bs.modal', function() {
// Focus on the first input when modal opens // Focus on the first input when modal opens
_.defer(function(elt) { var elt = $(this);
setTimeout(function() {
elt.find("input:enabled:visible:first").focus(); elt.find("input:enabled:visible:first").focus();
}, $(this)); }, 50);
}).on('hidden.bs.modal', function() { }).on('hidden.bs.modal', function() {
// Focus on the editor when modal is gone // Focus on the editor when modal is gone
isModalShown = false; isModalShown = false;
$editorElt.focus(); aceEditor.focus();
// Revert to current theme when settings modal is closed // Revert to current theme when settings modal is closed
applyTheme(localStorage.theme); applyTheme(localStorage.theme);
}).keyup(function(e) { }).keyup(function(e) {

View File

@ -171,8 +171,11 @@ define([
addEventHook("onLayoutResize"); addEventHook("onLayoutResize");
// Operations on PageDown // Operations on PageDown
addEventHook("onEditorConfigure"); addEventHook("onPagedownConfigure");
addEventHook("onSectionsCreated"); addEventHook("onSectionsCreated");
// Operation on ACE
addEventHook("onAceCreated");
var onPreviewFinished = createEventHook("onPreviewFinished"); var onPreviewFinished = createEventHook("onPreviewFinished");
var onAsyncPreviewListenerList = getExtensionListenerList("onAsyncPreview"); var onAsyncPreviewListenerList = getExtensionListenerList("onAsyncPreview");

View File

@ -30,7 +30,7 @@ define([
var files = (evt.dataTransfer || evt.target).files; var files = (evt.dataTransfer || evt.target).files;
$(".modal-import-harddrive-markdown, .modal-import-harddrive-html").modal("hide"); $(".modal-import-harddrive-markdown, .modal-import-harddrive-html").modal("hide");
_.each(files, function(file) { _.each(files, function(file) {
if($(evt.target).is("#wmd-input") && file.name.match(/.(jpe?g|png|gif)$/)) { if($(evt.target).is("#wmd-input *") && file.name.match(/.(jpe?g|png|gif)$/)) {
return; return;
} }
var reader = new FileReader(); var reader = new FileReader();

View File

@ -29,6 +29,11 @@ define([
newConfig.shortcutNext = utils.getInputTextValue("#input-document-selector-shortcut-next", event); newConfig.shortcutNext = utils.getInputTextValue("#input-document-selector-shortcut-next", event);
}; };
var aceEditor = undefined;
documentSelector.onAceCreated = function(aceEditorParam) {
aceEditor = aceEditorParam;
};
var fileMgr = undefined; var fileMgr = undefined;
documentSelector.onFileMgrCreated = function(fileMgrParameter) { documentSelector.onFileMgrCreated = function(fileMgrParameter) {
fileMgr = fileMgrParameter; fileMgr = fileMgrParameter;
@ -41,7 +46,6 @@ define([
' </a>', ' </a>',
'</li>' '</li>'
].join(''); ].join('');
var $editorElt = undefined;
var dropdownElt = undefined; var dropdownElt = undefined;
var liEltMap = undefined; var liEltMap = undefined;
var liEltList = undefined; var liEltList = undefined;
@ -70,7 +74,7 @@ define([
fileMgr.selectFile(fileDesc); fileMgr.selectFile(fileDesc);
} }
else { else {
$editorElt.focus(); aceEditor.focus();
} }
}); });
}); });
@ -91,8 +95,6 @@ define([
documentSelector.onPublishRemoved = buildSelector; documentSelector.onPublishRemoved = buildSelector;
documentSelector.onReady = function() { documentSelector.onReady = function() {
$editorElt = $("#wmd-input");
if(documentSelector.config.orderBy == "title") { if(documentSelector.config.orderBy == "title") {
sortFunction = function(fileDesc) { sortFunction = function(fileDesc) {
return fileDesc.title.toLowerCase(); return fileDesc.title.toLowerCase();

View File

@ -5,7 +5,7 @@ define([
var emailConverter = new Extension("emailConverter", "Markdown Email", true); var emailConverter = new Extension("emailConverter", "Markdown Email", true);
emailConverter.settingsBlock = '<p>Converts email adresses in the form &lt;email@example.com&gt; into clickable links.</p>'; emailConverter.settingsBlock = '<p>Converts email adresses in the form &lt;email@example.com&gt; into clickable links.</p>';
emailConverter.onEditorConfigure = function(editor) { emailConverter.onPagedownConfigure = function(editor) {
editor.getConverter().hooks.chain("postConversion", function(text) { editor.getConverter().hooks.chain("postConversion", function(text) {
return text.replace(/<(mailto\:)?([^\s>]+@[^\s>]+\.\S+?)>/g, function(match, mailto, email) { return text.replace(/<(mailto\:)?([^\s>]+@[^\s>]+\.\S+?)>/g, function(match, mailto, email) {
return '<a href="mailto:' + email + '">' + email + '</a>'; return '<a href="mailto:' + email + '">' + email + '</a>';

View File

@ -44,7 +44,7 @@ define([
newConfig.highlighter = utils.getInputValue("#input-markdownextra-highlighter"); newConfig.highlighter = utils.getInputValue("#input-markdownextra-highlighter");
}; };
markdownExtra.onEditorConfigure = function(editor) { markdownExtra.onPagedownConfigure = function(editor) {
var converter = editor.getConverter(); var converter = editor.getConverter();
var options = { var options = {
extensions: markdownExtra.config.extensions extensions: markdownExtra.config.extensions

View File

@ -61,7 +61,7 @@ define([
}); });
}; };
mathJax.onEditorConfigure = function(editorObject) { mathJax.onPagedownConfigure = function(editorObject) {
t = document.getElementById("preview-contents"); t = document.getElementById("preview-contents");
var converter = editorObject.getConverter(); var converter = editorObject.getConverter();

View File

@ -172,7 +172,7 @@ define([
} }
} }
partialRendering.onEditorConfigure = function(editor) { partialRendering.onPagedownConfigure = function(editor) {
converter = editor.getConverter(); converter = editor.getConverter();
converter.hooks.chain("preConversion", function(text) { converter.hooks.chain("preConversion", function(text) {
var result = _.map(modifiedSections, function(section) { var result = _.map(modifiedSections, function(section) {

View File

@ -10,14 +10,17 @@ define([
var scrollLink = new Extension("scrollLink", "Scroll Link", true, true); var scrollLink = new Extension("scrollLink", "Scroll Link", true, true);
scrollLink.settingsBlock = scrollLinkSettingsBlockHTML; scrollLink.settingsBlock = scrollLinkSettingsBlockHTML;
var aceEditor = undefined;
scrollLink.onAceCreated = function(aceEditorParam) {
aceEditor = aceEditorParam;
};
var sectionList = undefined; var sectionList = undefined;
scrollLink.onSectionsCreated = function(sectionListParam) { scrollLink.onSectionsCreated = function(sectionListParam) {
sectionList = sectionListParam; sectionList = sectionListParam;
}; };
var $editorElt = undefined;
var $previewElt = undefined; var $previewElt = undefined;
var $textareaElt = undefined;
var mdSectionList = []; var mdSectionList = [];
var htmlSectionList = []; var htmlSectionList = [];
function pxToFloat(px) { function pxToFloat(px) {
@ -27,57 +30,21 @@ define([
var lastPreviewScrollTop = undefined; var lastPreviewScrollTop = undefined;
var buildSections = _.debounce(function() { var buildSections = _.debounce(function() {
// Try to find Markdown sections by looking for titles
mdSectionList = []; mdSectionList = [];
// It has to be the same width as wmd-input var mdTextOffset = 0;
$textareaElt.width($editorElt.width());
// Consider wmd-input top padding (will be used for 1st and last
// section)
var padding = pxToFloat($editorElt.css('padding-top'));
var mdSectionOffset = 0; var mdSectionOffset = 0;
function addMdSection(sectionText) { _.each(sectionList, function(sectionText) {
var sectionHeight = padding; mdTextOffset += sectionText.length;
if(sectionText !== undefined) { var documentPosition = aceEditor.session.doc.indexToPosition(mdTextOffset);
$textareaElt.val(sectionText); var screenPosition = aceEditor.session.documentToScreenPosition(documentPosition.row, documentPosition.column);
sectionHeight += $textareaElt.prop('scrollHeight'); var newSectionOffset = screenPosition.row * aceEditor.renderer.lineHeight;
} var sectionHeight = newSectionOffset - mdSectionOffset;
var newSectionOffset = mdSectionOffset + sectionHeight;
mdSectionList.push({ mdSectionList.push({
startOffset: mdSectionOffset, startOffset: mdSectionOffset,
endOffset: newSectionOffset, endOffset: newSectionOffset,
height: sectionHeight height: sectionHeight
}); });
mdSectionOffset = newSectionOffset; mdSectionOffset = newSectionOffset;
padding = 0;
}
_.each(sectionList, function(sectionText, index) {
if(index !== sectionList.length - 1) {
if(sectionText.length === 0) {
sectionText = undefined;
}
else {
// Remove the last \n preceding the next title
sectionText = sectionText.substring(0, sectionText.length - 1);
}
}
else {
// Last section
// Consider wmd-input bottom padding and keep last empty line
padding += pxToFloat($editorElt.css('padding-bottom'));
}
addMdSection(sectionText);
});
// Apply a coef to manage divergence in some browsers
var theoricalHeight = _.last(mdSectionList).endOffset;
var realHeight = $editorElt[0].scrollHeight;
var coef = realHeight/theoricalHeight;
mdSectionList = _.map(mdSectionList, function(mdSection) {
return {
startOffset: mdSection.startOffset * coef,
endOffset: mdSection.endOffset * coef,
height: mdSection.height * coef,
};
}); });
// Try to find corresponding sections in the preview // Try to find corresponding sections in the preview
@ -114,11 +81,13 @@ define([
var isScrollPreview = false; var isScrollPreview = false;
var doScrollLink = _.debounce(function() { var doScrollLink = _.debounce(function() {
if(mdSectionList.length === 0 || mdSectionList.length !== htmlSectionList.length) { if(mdSectionList.length === 0 || mdSectionList.length !== htmlSectionList.length) {
// Delay
doScrollLink();
return; return;
} }
var editorScrollTop = $editorElt.scrollTop(); var editorScrollTop = aceEditor.renderer.getScrollTop();
var previewScrollTop = $previewElt.scrollTop(); var previewScrollTop = $previewElt.scrollTop();
function animate(srcScrollTop, srcSectionList, destElt, destSectionList, currentDestScrollTop, callback) { function getDestScrollTop(srcScrollTop, srcSectionList, destSectionList) {
// Find the section corresponding to the offset // Find the section corresponding to the offset
var sectionIndex = undefined; var sectionIndex = undefined;
var srcSection = _.find(srcSectionList, function(section, index) { var srcSection = _.find(srcSectionList, function(section, index) {
@ -131,38 +100,56 @@ define([
} }
var posInSection = (srcScrollTop - srcSection.startOffset) / srcSection.height; var posInSection = (srcScrollTop - srcSection.startOffset) / srcSection.height;
var destSection = destSectionList[sectionIndex]; var destSection = destSectionList[sectionIndex];
var destScrollTop = destSection.startOffset + destSection.height * posInSection; return destSection.startOffset + destSection.height * posInSection;
destScrollTop = _.min([
destScrollTop,
destElt.prop('scrollHeight') - destElt.outerHeight()
]);
if(Math.abs(destScrollTop - currentDestScrollTop) <= 9) {
// Skip the animation if diff is <= 9
callback(currentDestScrollTop);
return;
}
destElt.animate({
scrollTop: destScrollTop
}, 500, function() {
callback(destScrollTop);
});
} }
// Perform the animation if diff > 9px // Perform the animation if diff > 9px
if(isScrollEditor === true && Math.abs(editorScrollTop - lastEditorScrollTop) > 9) { if(isScrollEditor === true && Math.abs(editorScrollTop - lastEditorScrollTop) > 9) {
isScrollEditor = false; isScrollEditor = false;
// Animate the preview // Animate the preview
lastEditorScrollTop = editorScrollTop; lastEditorScrollTop = editorScrollTop;
animate(editorScrollTop, mdSectionList, $previewElt, htmlSectionList, previewScrollTop, function(destScrollTop) { var destScrollTop = getDestScrollTop(editorScrollTop, mdSectionList, htmlSectionList);
lastPreviewScrollTop = destScrollTop; destScrollTop = _.min([
}); destScrollTop,
$previewElt.prop('scrollHeight') - $previewElt.outerHeight()
]);
if(Math.abs(destScrollTop - previewScrollTop) <= 9) {
// Skip the animation if diff is <= 9
lastPreviewScrollTop = previewScrollTop;
}
else {
$previewElt.animate({
scrollTop: destScrollTop
}, 'easeOutQuad', function() {
lastPreviewScrollTop = destScrollTop;
});
}
} }
else if(isScrollPreview === true && Math.abs(previewScrollTop - lastPreviewScrollTop) > 9) { else if(isScrollPreview === true && Math.abs(previewScrollTop - lastPreviewScrollTop) > 9) {
isScrollPreview = false; isScrollPreview = false;
// Animate the editor // Animate the editor
lastPreviewScrollTop = previewScrollTop; lastPreviewScrollTop = previewScrollTop;
animate(previewScrollTop, htmlSectionList, $editorElt, mdSectionList, editorScrollTop, function(destScrollTop) { var destScrollTop = getDestScrollTop(previewScrollTop, htmlSectionList, mdSectionList);
lastEditorScrollTop = destScrollTop; destScrollTop = _.min([
}); destScrollTop,
aceEditor.session.getScreenLength() * aceEditor.renderer.lineHeight - aceEditor.renderer.$size.scrollerHeight
]);
if(Math.abs(destScrollTop - editorScrollTop) <= 9) {
// Skip the animation if diff is <= 9
lastEditorScrollTop = editorScrollTop;
}
else {
$("<div>").animate({
value: destScrollTop - editorScrollTop
}, {
easing: 'easeOutQuad',
step: function(now) {
aceEditor.session.setScrollTop(editorScrollTop + now);
},
complete: function() {
lastEditorScrollTop = destScrollTop;
}
});
}
} }
}, 500); }, 500);
@ -171,13 +158,13 @@ define([
buildSections(); buildSections();
}; };
scrollLink.onFileClosed = function() {
mdSectionList = [];
};
scrollLink.onReady = function() { scrollLink.onReady = function() {
$editorElt = $("#wmd-input");
$previewElt = $(".preview-container"); $previewElt = $(".preview-container");
// This textarea is used to measure sections height
$textareaElt = $("#md-section-helper");
$previewElt.bind("keyup mouseup mousewheel", function() { $previewElt.bind("keyup mouseup mousewheel", function() {
isScrollPreview = true; isScrollPreview = true;
isScrollEditor = false; isScrollEditor = false;
@ -188,15 +175,15 @@ define([
isScrollEditor = false; isScrollEditor = false;
doScrollLink(); doScrollLink();
}); });
$editorElt.bind("keyup mouseup mousewheel", function() { aceEditor.session.on("changeScrollTop", function(e) {
isScrollEditor = true; isScrollEditor = true;
isScrollPreview = false; isScrollPreview = false;
doScrollLink(); doScrollLink();
}); });
}; };
var $previewContentsElt = undefined; var $previewContentsElt = undefined;
scrollLink.onEditorConfigure = function(editor) { scrollLink.onPagedownConfigure = function(editor) {
$previewContentsElt = $("#preview-contents"); $previewContentsElt = $("#preview-contents");
editor.getConverter().hooks.chain("postConversion", function(text) { editor.getConverter().hooks.chain("postConversion", function(text) {
// To avoid losing scrolling position before elements are fully // To avoid losing scrolling position before elements are fully

View File

@ -114,7 +114,7 @@ define([
return '<div class="toc">\n<ul>\n' + elementList.join("") + '</ul>\n</div>\n'; return '<div class="toc">\n<ul>\n' + elementList.join("") + '</ul>\n</div>\n';
} }
toc.onEditorConfigure = function(editor) { toc.onPagedownConfigure = function(editor) {
previewContentsElt = document.getElementById('preview-contents'); previewContentsElt = document.getElementById('preview-contents');
var tocEltList = document.querySelectorAll('.table-of-contents'); var tocEltList = document.querySelectorAll('.table-of-contents');
var tocExp = new RegExp("^" + toc.config.marker + "$", "g"); var tocExp = new RegExp("^" + toc.config.marker + "$", "g");

View File

@ -150,9 +150,12 @@ define([
}); });
}; };
eventMgr.addListener("onReady", function() { var aceEditor = undefined;
var $editorElt = $("#wmd-input"); eventMgr.addListener('onAceCreated', function(aceEditorParam) {
aceEditor = aceEditorParam;
});
eventMgr.addListener("onReady", function() {
fileMgr.selectFile(); fileMgr.selectFile();
var $fileTitleElt = $('.file-title-navbar'); var $fileTitleElt = $('.file-title-navbar');
@ -160,10 +163,6 @@ define([
$(".action-create-file").click(function() { $(".action-create-file").click(function() {
var fileDesc = fileMgr.createFile(); var fileDesc = fileMgr.createFile();
fileMgr.selectFile(fileDesc); fileMgr.selectFile(fileDesc);
var wmdInput = $editorElt.focus().get(0);
if(wmdInput.setSelectionRange) {
wmdInput.setSelectionRange(0, 0);
}
$fileTitleElt.click(); $fileTitleElt.click();
}); });
$(".action-remove-file").click(function() { $(".action-remove-file").click(function() {
@ -189,7 +188,7 @@ define([
eventMgr.onTitleChanged(fileDesc); eventMgr.onTitleChanged(fileDesc);
} }
$fileTitleInputElt.val(fileDesc.title); $fileTitleInputElt.val(fileDesc.title);
$editorElt.focus(); aceEditor.focus();
} }
$fileTitleInputElt.blur(function() { $fileTitleInputElt.blur(function() {
applyTitle(); applyTitle();
@ -206,7 +205,7 @@ define([
window.location.href = "."; window.location.href = ".";
}); });
$(".action-edit-document").click(function() { $(".action-edit-document").click(function() {
var content = $editorElt.val(); var content = aceEditor.getValue();
var title = fileMgr.currentFile.title; var title = fileMgr.currentFile.title;
var fileDesc = fileMgr.createFile(title, content); var fileDesc = fileMgr.createFile(title, content);
fileMgr.selectFile(fileDesc); fileMgr.selectFile(fileDesc);

View File

@ -39,7 +39,7 @@
</ul> </ul>
</div> </div>
</div> </div>
<div id="wmd-input" class="ui-layout-center form-control"></div> <div id="wmd-input" class="ui-layout-center"></div>
<div class="ui-layout-east preview-container"></div> <div class="ui-layout-east preview-container"></div>
<div class="ui-layout-south preview-container"></div> <div class="ui-layout-south preview-container"></div>
<div id="wmd-button-bar" class="hide"></div> <div id="wmd-button-bar" class="hide"></div>
@ -1076,6 +1076,5 @@
</div> </div>
<textarea id="md-section-helper" class="form-control"></textarea>
<div class="lock-ui hide"></div> <div class="lock-ui hide"></div>
<div id="dropboxjs" data-app-key="x0k2l8puemfvg0o"></div> <div id="dropboxjs" data-app-key="x0k2l8puemfvg0o"></div>

View File

@ -34,7 +34,7 @@
</div> </div>
</div> </div>
<div id="wmd-button-bar" class="hide"></div> <div id="wmd-button-bar" class="hide"></div>
<textarea id="wmd-input" class="hide"></textarea> <div id="wmd-input" class="hide"></div>
<div class="ui-layout-center preview-container"></div> <div class="ui-layout-center preview-container"></div>
<div class="menu-panel collapse width"> <div class="menu-panel collapse width">

View File

@ -135,11 +135,11 @@
panels; panels;
var undoManager; var undoManager;
this.run = function (previewWrapper) { this.run = function (aceEditor, previewWrapper) {
if (panels) if (panels)
return; // already initialized return; // already initialized
panels = new PanelCollection(idPostfix); panels = new PanelCollection(idPostfix, aceEditor);
var commandManager = new CommandManager(hooks, getString); var commandManager = new CommandManager(hooks, getString);
var previewManager = new PreviewManager(markdownConverter, panels, function () { hooks.onPreviewRefresh(); }, previewWrapper); var previewManager = new PreviewManager(markdownConverter, panels, function () { hooks.onPreviewRefresh(); }, previewWrapper);
var uiManager; var uiManager;
@ -318,10 +318,10 @@
// This ONLY affects Internet Explorer (tested on versions 6, 7 // This ONLY affects Internet Explorer (tested on versions 6, 7
// and 8) and ONLY on button clicks. Keyboard shortcuts work // and 8) and ONLY on button clicks. Keyboard shortcuts work
// normally since the focus never leaves the textarea. // normally since the focus never leaves the textarea.
function PanelCollection(postfix) { function PanelCollection(postfix, aceEditor) {
this.buttonBar = doc.getElementById("wmd-button-bar" + postfix); this.buttonBar = doc.getElementById("wmd-button-bar" + postfix);
this.preview = doc.getElementById("wmd-preview" + postfix); this.preview = doc.getElementById("wmd-preview" + postfix);
this.input = window.wmdInput; this.input = aceEditor;
}; };
// Returns true if the DOM element is visible, false if it's hidden. // Returns true if the DOM element is visible, false if it's hidden.
@ -467,6 +467,7 @@
return [maxWidth, maxHeight, innerWidth, innerHeight]; return [maxWidth, maxHeight, innerWidth, innerHeight];
}; };
/*benweet
// Handles pushing and popping TextareaStates for undo/redo commands. // Handles pushing and popping TextareaStates for undo/redo commands.
// I should rename the stack variables to list. // I should rename the stack variables to list.
function UndoManager(callback, panels) { function UndoManager(callback, panels) {
@ -717,6 +718,7 @@
} }
// end of UndoManager // end of UndoManager
*/
// The input textarea state/contents. // The input textarea state/contents.
// This is used to implement undo/redo by the undo manager. // This is used to implement undo/redo by the undo manager.
@ -737,14 +739,14 @@
var Range = require('ace/range').Range; var Range = require('ace/range').Range;
(function(range) { (function(range) {
stateObj.before = inputArea.editor.session.getTextRange(new Range(0,0,range.start.row, range.start.column)); stateObj.before = inputArea.session.getTextRange(new Range(0,0,range.start.row, range.start.column));
stateObj.selection = inputArea.editor.session.getTextRange(); stateObj.selection = inputArea.session.getTextRange();
stateObj.after = inputArea.editor.session.getTextRange(new Range(range.end.row, range.end.column, Number.MAX_VALUE, Number.MAX_VALUE)); stateObj.after = inputArea.session.getTextRange(new Range(range.end.row, range.end.column, Number.MAX_VALUE, Number.MAX_VALUE));
})(inputArea.editor.selection.getRange()); })(inputArea.selection.getRange());
this.text = [this.before, this.selection, this.after].join(''); this.text = [this.before, this.selection, this.after].join('');
this.length = this.text.length; this.length = this.text.length;
this.setInputAreaSelectionStartEnd(); this.setInputAreaSelectionStartEnd();
this.scrollTop = inputArea.scrollTop; this.scrollTop = inputArea.renderer.getScrollTop();
/*benweet /*benweet
if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) { if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) {
this.text = inputArea.value; this.text = inputArea.value;
@ -757,11 +759,11 @@
this.setInputAreaSelection = function () { this.setInputAreaSelection = function () {
var Range = require('ace/range').Range; var Range = require('ace/range').Range;
inputArea.editor.selection.setSelectionRange((function(posStart, posEnd) { inputArea.selection.setSelectionRange((function(posStart, posEnd) {
return new Range(posStart.row, posStart.column, posEnd.row, posEnd.column); return new Range(posStart.row, posStart.column, posEnd.row, posEnd.column);
})(inputArea.editor.session.doc.indexToPosition(stateObj.start), inputArea.editor.session.doc.indexToPosition(stateObj.end))); })(inputArea.session.doc.indexToPosition(stateObj.start), inputArea.session.doc.indexToPosition(stateObj.end)));
inputArea.editor.renderer.scrollToY(stateObj.scrollTop); inputArea.renderer.scrollToY(stateObj.scrollTop);
inputArea.editor.focus(); inputArea.focus();
/*benweet /*benweet
if (!util.isVisible(inputArea)) { if (!util.isVisible(inputArea)) {
@ -871,8 +873,8 @@
var Range = require('ace/range').Range; var Range = require('ace/range').Range;
var range = (function(posStart, posEnd) { var range = (function(posStart, posEnd) {
return new Range(posStart.row, posStart.column, posEnd.row, posEnd.column); return new Range(posStart.row, posStart.column, posEnd.row, posEnd.column);
})(inputArea.editor.session.doc.indexToPosition(startIndex), inputArea.editor.session.doc.indexToPosition(stateObj.length - endIndex)); })(inputArea.session.doc.indexToPosition(startIndex), inputArea.session.doc.indexToPosition(stateObj.length - endIndex));
inputArea.editor.session.replace(range, stateObj.text.substring(startIndex, afterMaxOffset - endIndex + 1)); inputArea.session.replace(range, stateObj.text.substring(startIndex, afterMaxOffset - endIndex + 1));
this.setInputAreaSelection(); this.setInputAreaSelection();
/*benweet /*benweet
@ -960,7 +962,7 @@
return; return;
var text = panels.input.value; var text = panels.input.getValue();
if (text && text == oldInputText) { if (text && text == oldInputText) {
return; // Input text hasn't changed. return; // Input text hasn't changed.
} }
@ -1103,7 +1105,7 @@
/*benweet /*benweet
setupEvents(panels.input, applyTimeout); setupEvents(panels.input, applyTimeout);
*/ */
panels.input.editor.session.on('change', applyTimeout); panels.input.session.on('change', applyTimeout);
//Not necessary //Not necessary
//makePreviewHtml(); //makePreviewHtml();
@ -1330,7 +1332,7 @@
return; return;
} }
var identifier = identifierList.pop(); var identifier = identifierList.pop();
inputBox.editor.commands.addCommand({ inputBox.commands.addCommand({
name: getString(identifier), name: getString(identifier),
bindKey: {win: 'Ctrl-' + keyStrokes[identifier], mac: 'Command-' + keyStrokes[identifier]}, bindKey: {win: 'Ctrl-' + keyStrokes[identifier], mac: 'Command-' + keyStrokes[identifier]},
exec: function(editor) { exec: function(editor) {
@ -1530,7 +1532,7 @@
return; return;
} }
panels.ieCachedRange = document.selection.createRange(); panels.ieCachedRange = document.selection.createRange();
panels.ieCachedScrollTop = panels.input.scrollTop; panels.ieCachedScrollTop = panels.input.renderer.getScrollTop();
}; };
} }
@ -1617,10 +1619,10 @@
buttons.hr = makeButton("wmd-hr-button", getStringAndKey("hr"), "-180px", bindCommand("doHorizontalRule")); buttons.hr = makeButton("wmd-hr-button", getStringAndKey("hr"), "-180px", bindCommand("doHorizontalRule"));
makeSpacer(3); makeSpacer(3);
buttons.undo = makeButton("wmd-undo-button", getStringAndKey("undo"), "-200px", null); buttons.undo = makeButton("wmd-undo-button", getStringAndKey("undo"), "-200px", null);
buttons.undo.execute = function (manager) { inputBox.editor.session.getUndoManager().undo(); }; buttons.undo.execute = function (manager) { inputBox.session.getUndoManager().undo(); };
buttons.redo = makeButton("wmd-redo-button", getStringAndKey("redo"), "-220px", null); buttons.redo = makeButton("wmd-redo-button", getStringAndKey("redo"), "-220px", null);
buttons.redo.execute = function (manager) { inputBox.editor.session.getUndoManager().redo(); }; buttons.redo.execute = function (manager) { inputBox.session.getUndoManager().redo(); };
if (helpOptions) { if (helpOptions) {
var helpButton = document.createElement("li"); var helpButton = document.createElement("li");
@ -1640,7 +1642,7 @@
} }
setUndoRedoButtonStates(); setUndoRedoButtonStates();
inputBox.editor.session.on('change', setUndoRedoButtonStates); inputBox.session.on('change', setUndoRedoButtonStates);
} }
function setUndoRedoButtonStates() { function setUndoRedoButtonStates() {
@ -1651,8 +1653,8 @@
} }
*/ */
setTimeout(function() { setTimeout(function() {
setupButton(buttons.undo, inputBox.editor.session.getUndoManager().hasUndo()); setupButton(buttons.undo, inputBox.session.getUndoManager().hasUndo());
setupButton(buttons.redo, inputBox.editor.session.getUndoManager().hasRedo()); setupButton(buttons.redo, inputBox.session.getUndoManager().hasRedo());
}, 0); }, 0);
}; };

View File

@ -55,13 +55,13 @@ var MarkdownHighlightRules = function() {
token : "support.function", token : "support.function",
regex : "(`+)(.*?[^`])(\\1)" regex : "(`+)(.*?[^`])(\\1)"
}, { // reference }, { // reference
token : ["text", "constant", "text", "url", "string", "text"], token : ["text", "reference", "text", "markup.underline", "description", "text"],
regex : "^([ ]{0,3}\\[)([^\\]]+)(\\]:\\s*)([^ ]+)(\\s*(?:[\"][^\"]+[\"])?(\\s*))$" regex : "^([ ]{0,3}\\[)([^\\]]+)(\\]:\\s*)([^ ]+)(\\s*(?:[\"][^\"]+[\"])?(\\s*))$"
}, { // link by reference }, { // link by reference
token : ["text", "string", "text", "constant", "text"], token : ["text", "description", "text", "markup.underline", "text"],
regex : "(\\[)((?:[[^\\]]*\\]|[^\\[\\]])*)(\\][ ]?(?:\\n[ ]*)?\\[)(.*?)(\\])" regex : "(\\[)((?:[[^\\]]*\\]|[^\\[\\]])*)(\\][ ]?(?:\\n[ ]*)?\\[)(.*?)(\\])"
}, { // link by url }, { // link by url
token : ["text", "string", "text", "markup.underline", "string", "text"], token : ["text", "description", "text", "markup.underline", "string", "text"],
regex : "(\\[)"+ regex : "(\\[)"+
"(\\[[^\\]]*\\]|[^\\[\\]]*)"+ "(\\[[^\\]]*\\]|[^\\[\\]]*)"+
"(\\]\\([ \\t]*)"+ "(\\]\\([ \\t]*)"+

View File

@ -274,7 +274,7 @@ define([
// Keep a link to the pagedown editor // Keep a link to the pagedown editor
var editor = undefined; var editor = undefined;
eventMgr.addListener("onEditorConfigure", function(editorParam) { eventMgr.addListener("onPagedownConfigure", function(editorParam) {
editor = editorParam; editor = editorParam;
}); });

View File

@ -16,7 +16,7 @@
@primary-color: #333; @primary-color: #333;
@primary-color-light: lighten(@primary-color, 13%); @primary-color-light: lighten(@primary-color, 13%);
@primary-color-lighter: lighten(@primary-color, 20%); @primary-color-lighter: lighten(@primary-color, 20%);
@primary-color-lightest: lighten(@primary-color, 40%); @primary-color-lightest: lighten(@primary-color, 33%);
@primary-color-inv: #fff; @primary-color-inv: #fff;
@bg-navbar-hover: @primary-bg-lighter; @bg-navbar-hover: @primary-bg-lighter;
@error-border: #ff8661; @error-border: #ff8661;
@ -908,6 +908,10 @@ ul,ol {
* Editor * Editor
*****************************/ *****************************/
.ace_editor {
color: @primary-color-light;
}
.ace-tm .ace_marker-layer .ace_active-line { .ace-tm .ace_marker-layer .ace_active-line {
background-color: @primary-bg-lighter; background-color: @primary-bg-lighter;
} }
@ -934,6 +938,10 @@ ul,ol {
font-style: italic; font-style: italic;
} }
.ace-tm .ace_description {
color: @primary-color-lightest;
}
#wmd-input { #wmd-input {
.box-shadow(none); .box-shadow(none);
padding: 0; padding: 0;