Fixes for new editor

This commit is contained in:
benweet 2014-03-19 00:33:57 +00:00
parent 400d416e3c
commit 8cb7c307ee
9 changed files with 328 additions and 387 deletions

View File

@ -519,6 +519,7 @@ define([
// If the editor is already created // If the editor is already created
$editorElt.val(initDocumentContent); $editorElt.val(initDocumentContent);
aceEditor && aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange); aceEditor && aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange);
aceEditor || pagedownEditor.undoManager.reinit(initDocumentContent, fileDesc.editorStart, fileDesc.editorEnd, fileDesc.editorScrollTop);
aceEditor ? aceEditor.focus() : $editorElt.focus(); aceEditor ? aceEditor.focus() : $editorElt.focus();
//pagedownEditor.refreshPreview(); //pagedownEditor.refreshPreview();
return; return;

View File

@ -60,23 +60,27 @@ define([
}); });
var previousTextContent; var previousTextContent;
function onInputChange() { function onInputContentChange() {
selectionStart = inputElt.selectionStart; selectionStart = inputElt.selectionStart;
selectionEnd = inputElt.selectionEnd; selectionEnd = inputElt.selectionEnd;
var currentTextContent = inputElt.textContent; var currentTextContent = inputElt.textContent;
if(!/\n$/.test(currentTextContent)) {
currentTextContent += '\n';
}
if(fileChanged === false) { if(fileChanged === false) {
fileDesc.editorStart = selectionStart; fileDesc.editorStart = selectionStart;
fileDesc.editorEnd = selectionEnd; fileDesc.editorEnd = selectionEnd;
if(currentTextContent == previousTextContent) { if(currentTextContent == previousTextContent) {
return; return;
} }
if(!/\n$/.test(currentTextContent)) {
currentTextContent += '\n';
}
fileDesc.content = currentTextContent; fileDesc.content = currentTextContent;
eventMgr.onContentChanged(fileDesc); eventMgr.onContentChanged(fileDesc);
} }
else { else {
if(!/\n$/.test(currentTextContent)) {
currentTextContent += '\n';
fileDesc.content = currentTextContent;
}
eventMgr.onFileOpen(fileDesc); eventMgr.onFileOpen(fileDesc);
previewElt.scrollTop = fileDesc.previewScrollTop; previewElt.scrollTop = fileDesc.previewScrollTop;
selectionStart = fileDesc.editorStart; selectionStart = fileDesc.editorStart;
@ -88,6 +92,58 @@ define([
previousTextContent = currentTextContent; previousTextContent = currentTextContent;
} }
function adjustCursorPosition() {
setTimeout(function() {
selectionStart = inputElt.selectionStart;
selectionEnd = inputElt.selectionEnd;
var backwards = false;
var selection = window.getSelection();
if (!selection.isCollapsed) {
var range = document.createRange();
range.setStart(selection.anchorNode, selection.anchorOffset);
range.setEnd(selection.focusNode, selection.focusOffset);
backwards = range.collapsed;
range.detach();
}
var selectionRange = selection.getRangeAt(0);
var container = backwards ? selectionRange.startContainer : selectionRange.endContainer;
var cursorY;
if(container.textContent == '\n') {
cursorY = container.parentNode.offsetTop + container.parentNode.offsetHeight / 2 - inputElt.scrollTop;
}
else {
if(selectionStart === selectionEnd) {
var selectedChar = inputElt.textContent[selectionStart];
if(selectedChar === undefined || selectedChar == '\n') {
selectionRange = createRange(selectionStart - 1, selectionEnd);
}
else {
selectionRange = createRange(selectionStart, selectionEnd + 1);
}
}
var selectionRect = selectionRange.getBoundingClientRect();
cursorY = selectionRect.top + selectionRect.height / 2 - inputElt.offsetTop;
selectionRange.detach();
}
var adjust = inputElt.offsetHeight / 2;
if(adjust > 130) {
adjust = 130;
}
var cursorMinY = adjust;
var cursorMaxY = inputElt.offsetHeight - adjust;
if(cursorY < cursorMinY) {
inputElt.scrollTop += cursorY - cursorMinY;
}
else if(cursorY > cursorMaxY) {
inputElt.scrollTop += cursorY - cursorMaxY;
}
}, 0);
}
eventMgr.addListener('onLayoutResize', adjustCursorPosition);
editor.init = function(elt1, elt2) { editor.init = function(elt1, elt2) {
inputElt = elt1; inputElt = elt1;
previewElt = elt2; previewElt = elt2;
@ -103,7 +159,7 @@ define([
if(fileChanged === false) { if(fileChanged === false) {
fileDesc.editorScrollTop = scrollTop; fileDesc.editorScrollTop = scrollTop;
} }
}).bind("keyup mouseup", onInputChange); }).bind("keyup mouseup", onInputContentChange);
$(previewElt).scroll(function() { $(previewElt).scroll(function() {
if(fileChanged === false) { if(fileChanged === false) {
fileDesc.previewScrollTop = previewElt.scrollTop; fileDesc.previewScrollTop = previewElt.scrollTop;
@ -151,10 +207,10 @@ define([
var replacementText = value.substring(startIndex, value.length - endIndex + 1); var replacementText = value.substring(startIndex, value.length - endIndex + 1);
endIndex = currentValue.length - endIndex + 1; endIndex = currentValue.length - endIndex + 1;
var range = createRange(inputElt, startIndex, endIndex); var range = createRange(startIndex, endIndex);
range.deleteContents(); range.deleteContents();
range.insertNode(document.createTextNode(replacementText)); range.insertNode(document.createTextNode(replacementText));
onInputChange(); onInputContentChange();
} }
}); });
@ -213,87 +269,10 @@ define([
configurable: true configurable: true
}); });
function findOffset(root, ss) {
if (!root) {
return null;
}
var offset = 0,
element = root,
container;
do {
container = element;
element = element.firstChild;
if (element) {
do {
var len = element.textContent.length;
if (offset <= ss && offset + len > ss) {
break;
}
offset += len;
} while (element = element.nextSibling);
}
if (!element) {
// It's the container's lastChild
break;
}
} while (element && element.hasChildNodes() && element.nodeType != 3);
if (element) {
return {
element: element,
offset: ss - offset
};
} else if (container) {
element = container;
while (element && element.lastChild) {
element = element.lastChild;
}
if (element.nodeType === 3) {
return {
element: element,
offset: element.textContent.length
};
} else {
return {
element: element,
offset: 0
};
}
}
return {
element: root,
offset: 0,
error: true
};
}
function createRange(root, ss, se) {
var range = document.createRange(),
offset = findOffset(root, ss);
range.setStart(offset.element, offset.offset);
if (se && se != ss) {
offset = findOffset(root, se);
}
range.setEnd(offset.element, offset.offset);
return range;
}
inputElt.setSelectionRange = function (ss, se) { inputElt.setSelectionRange = function (ss, se) {
selectionStart = ss; selectionStart = ss;
selectionEnd = se; selectionEnd = se;
var range = createRange(editor.contentElt, ss, se); var range = createRange(ss, se);
var selection = window.getSelection(); var selection = window.getSelection();
selection.removeAllRanges(); selection.removeAllRanges();
@ -303,6 +282,10 @@ define([
editor.$contentElt.on('keydown', function (evt) { editor.$contentElt.on('keydown', function (evt) {
var cmdOrCtrl = evt.metaKey || evt.ctrlKey; var cmdOrCtrl = evt.metaKey || evt.ctrlKey;
if(!cmdOrCtrl && !event.altKey && !event.shiftKey) {
adjustCursorPosition();
}
switch (evt.keyCode) { switch (evt.keyCode) {
case 9: // Tab case 9: // Tab
if (!cmdOrCtrl) { if (!cmdOrCtrl) {
@ -330,14 +313,14 @@ define([
editor.$contentElt.on('paste', function () { editor.$contentElt.on('paste', function () {
pagedownEditor.undoManager.setMode("paste"); pagedownEditor.undoManager.setMode("paste");
setTimeout(function() { setTimeout(function() {
onInputChange(); onInputContentChange();
}, 0); }, 0);
}); });
editor.$contentElt.on('cut', function () { editor.$contentElt.on('cut', function () {
pagedownEditor.undoManager.setMode("cut"); pagedownEditor.undoManager.setMode("cut");
setTimeout(function() { setTimeout(function() {
onInputChange(); onInputContentChange();
}, 0); }, 0);
}); });
@ -403,94 +386,13 @@ define([
pagedownEditor.undoManager.setMode("newlines"); pagedownEditor.undoManager.setMode("newlines");
state.before += '\n'// + indent; state.before += '\n' + indent;
state.selection = ''; state.selection = '';
state.ss += indent.length + 1; state.ss += indent.length + 1;
state.se = state.ss; state.se = state.ss;
}, },
comment: function (state) {
var textAction;
var open = '<!--',
close = '-->';
var start = state.before.lastIndexOf(open),
end = state.after.indexOf(close),
closeBefore = state.before.lastIndexOf(close),
openAfter = state.after.indexOf(start);
pagedownEditor.undoManager.setMode("typing");
if (start > -1 && end > -1 && (start > closeBefore || closeBefore === -1) && (end < openAfter || openAfter === -1)) {
// Uncomment
state.before = state.before.splice(start, open.length);
state.after = state.after.splice(end, close.length);
textAction = [{
add: '',
del: open,
start: start
}, {
add: '',
del: close,
start: state.before.length + state.selection.length + end
}];
state.ss -= open.length;
state.se -= open.length;
return textAction;
} else {
// Comment
if (state.selection) {
// Comment selection
state.selection = open + state.selection + close;
textAction = [{
add: open,
del: '',
start: state.ss
}, {
add: close,
del: '',
start: open.length + state.se
}];
} else {
// Comment whole line
start = state.before.lastIndexOf('\n') + 1;
end = state.after.indexOf('\n');
if (end === -1) {
end = state.after.length;
}
while (/\s/.test(state.before.charAt(start))) {
start++;
}
state.before = state.before.splice(start, 0, open);
state.after = state.after.splice(end, 0, close);
textAction = [{
add: open,
del: '',
start: start
}, {
add: close,
del: '',
start: state.before.length + end
}];
}
state.ss += open.length;
state.se += open.length;
return textAction;
}
}
}; };
}; };
@ -516,7 +418,12 @@ define([
// Find modified section starting from top // Find modified section starting from top
var leftIndex = sectionList.length; var leftIndex = sectionList.length;
_.some(sectionList, function(section, index) { _.some(sectionList, function(section, index) {
if(index >= newSectionList.length || section.text != newSectionList[index].text) { var newSection = newSectionList[index];
if(index >= newSectionList.length ||
// Check modified
section.textWithFrontMatter != newSection.textWithFrontMatter ||
// Check that section has not been detached from the DOM with backspace
!section.highlightedContent.parentNode) {
leftIndex = index; leftIndex = index;
return true; return true;
} }
@ -525,9 +432,14 @@ define([
// Find modified section starting from bottom // Find modified section starting from bottom
var rightIndex = -sectionList.length; var rightIndex = -sectionList.length;
_.some(sectionList.slice().reverse(), function(section, index) { _.some(sectionList.slice().reverse(), function(section, index) {
var newSectionText = newSectionList[newSectionList.length - index - 1].text; var newSection = newSectionList[newSectionList.length - index - 1];
if(index >= newSectionList.length ||
// Check modified
section.textWithFrontMatter != newSection.textWithFrontMatter ||
// Check that section has not been detached from the DOM with backspace
!section.highlightedContent.parentNode ||
// Check also the content of the node since new lines can be added just at the beggining // Check also the content of the node since new lines can be added just at the beggining
if(index >= newSectionList.length || section.text != newSectionText || section.highlightedContent.textContent != newSectionText) { section.highlightedContent.textContent != newSection.textWithFrontMatter) {
rightIndex = -index; rightIndex = -index;
return true; return true;
} }
@ -577,8 +489,6 @@ define([
editor.contentElt.appendChild(newSectionEltList); editor.contentElt.appendChild(newSectionEltList);
} }
//var dummyTextNode = document.createTextNode('\n');
//editor.contentElt.appendChild(dummyTextNode);
inputElt.setSelectionRange(selectionStart, selectionEnd); inputElt.setSelectionRange(selectionStart, selectionEnd);
// Remove textNodes created outside sections // Remove textNodes created outside sections
@ -592,49 +502,9 @@ define([
} }
} }
} }
/*
function asyncHighlightSections() {
var startTime = Date.now();
var deferredList = [];
modifiedSections.forEach(function(section) {
var deferred = $.Deferred();
setTimeout(function() {
highlight(section);
deferred.resolve();
}, 0);
deferredList.push(deferred);
});
$.when.apply($, deferredList).then(function() {
var text = _.reduce(sectionList, function(text, section) {
return text + section.text;
}, '');
// Check that the editor has the actual value
if(inputElt.textContent == text) {
selectionStart = inputElt.selectionStart;
selectionEnd = inputElt.selectionEnd;
var newSectionEltList = document.createDocumentFragment();
modifiedSections.forEach(function(section) {
newSectionEltList.appendChild(section.highlightedContent);
});
if(insertBeforeSection !== undefined) {
var insertBeforeElt = document.getElementById("wmd-input-section-" + insertBeforeSection.id);
editor.$contentElt[0].insertBefore(newSectionEltList, insertBeforeElt);
}
else {
editor.$contentElt[0].appendChild(newSectionEltList);
}
inputElt.setSelectionRange(selectionStart, selectionEnd);
elapsedTime = Date.now() - startTime;
}
});
}
*/
function highlight(section) { function highlight(section) {
var text = section.text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' '); var text = section.textWithFrontMatter.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
var sectionElt = crel('span', { var sectionElt = crel('span', {
id: 'wmd-input-section-' + section.id, id: 'wmd-input-section-' + section.id,
class: 'wmd-input-section' class: 'wmd-input-section'
@ -643,5 +513,79 @@ define([
section.highlightedContent = sectionElt; section.highlightedContent = sectionElt;
} }
function createRange(ss, se) {
function findOffset(ss) {
var offset = 0,
element = editor.contentElt,
container;
do {
container = element;
element = element.firstChild;
if (element) {
do {
var len = element.textContent.length;
if (offset <= ss && offset + len > ss) {
break;
}
offset += len;
} while (element = element.nextSibling);
}
if (!element) {
// It's the container's lastChild
break;
}
} while (element && element.hasChildNodes() && element.nodeType != 3);
if (element) {
return {
element: element,
offset: ss - offset
};
} else if (container) {
element = container;
while (element && element.lastChild) {
element = element.lastChild;
}
if (element.nodeType === 3) {
return {
element: element,
offset: element.textContent.length
};
} else {
return {
element: element,
offset: 0
};
}
}
return {
element: editor.contentElt,
offset: 0,
error: true
};
}
var range = document.createRange(),
offset = findOffset(ss);
range.setStart(offset.element, offset.offset);
if (se && se != ss) {
offset = findOffset(se);
}
range.setEnd(offset.element, offset.offset);
return range;
}
return editor; return editor;
}); });

View File

@ -43,7 +43,8 @@ define([
var cursorMinY = coef*editorHeight; var cursorMinY = coef*editorHeight;
var cursorMaxY = (1-coef)*editorHeight; var cursorMaxY = (1-coef)*editorHeight;
var cursorY = $editorElt.caret('offset').top - $editorElt.offset().top; var cursorY = $editorElt.caret('offset').top - $editorElt.offset().top;
console.log($editorElt.caret('offset')); //console.log($editorElt.find('.pre-content').caret('offset'));
//console.log(window.getSelection().getRangeAt(0).getBoundingClientRect());
//$positionHelper.detach(); //$positionHelper.detach();
//parentNode.normalize(); //parentNode.normalize();
/* /*

View File

@ -40,7 +40,7 @@ define([
}); });
}; };
var trimLen; var trimLen = 0;
markdownSectionParser.onMarkdownTrim = function(len) { markdownSectionParser.onMarkdownTrim = function(len) {
trimLen = len; trimLen = len;
}; };
@ -48,13 +48,16 @@ define([
var sectionCounter = 0; var sectionCounter = 0;
function parseFileContent(fileDesc) { function parseFileContent(fileDesc) {
var text = fileDesc.content.substring(trimLen); var text = fileDesc.content.substring(trimLen);
var frontMatter = fileDesc.content.substring(0, trimLen);
var tmpText = text + "\n\n"; var tmpText = text + "\n\n";
function addSection(startOffset, endOffset) { function addSection(startOffset, endOffset) {
var sectionText = tmpText.substring(offset, endOffset); var sectionText = tmpText.substring(offset, endOffset);
sectionList.push({ sectionList.push({
id: ++sectionCounter, id: ++sectionCounter,
text: sectionText text: sectionText,
textWithFrontMatter: frontMatter + sectionText
}); });
frontMatter = '';
} }
sectionList = []; sectionList = [];
var offset = 0; var offset = 0;

View File

@ -161,8 +161,8 @@ define([
lastPreviewScrollTop = previewScrollTop; lastPreviewScrollTop = previewScrollTop;
return; return;
} }
$previewElt.stop('scrollLinkFx', true).animate({ scrollingHelper.stop('scrollLinkFx', true).css('value', 0).animate({
scrollTop: destScrollTop value: destScrollTop - previewScrollTop
}, { }, {
easing: 'easeOutSine', easing: 'easeOutSine',
duration: 200, duration: 200,
@ -170,13 +170,15 @@ define([
step: function(now) { step: function(now) {
isPreviewMoving = true; isPreviewMoving = true;
lastPreviewScrollTop = previewScrollTop + now; lastPreviewScrollTop = previewScrollTop + now;
$previewElt.scrollTop(lastPreviewScrollTop);
}, },
done: function() { done: function() {
setTimeout(function() { _.defer(function() {
isPreviewMoving = false; isPreviewMoving = false;
}, 100); });
}, },
}).dequeue('scrollLinkFx'); }).dequeue('scrollLinkFx');
} }
else if(isScrollPreview === true) { else if(isScrollPreview === true) {
if(Math.abs(previewScrollTop - lastPreviewScrollTop) <= 9) { if(Math.abs(previewScrollTop - lastPreviewScrollTop) <= 9) {
@ -205,25 +207,6 @@ define([
lastEditorScrollTop = editorScrollTop; lastEditorScrollTop = editorScrollTop;
return; return;
} }
if(window.lightMode) {
$editorElt.stop('scrollLinkFx', true).animate({
scrollTop: destScrollTop
}, {
easing: 'easeOutSine',
duration: 200,
queue: 'scrollLinkFx',
step: function(now) {
isEditorMoving = true;
lastEditorScrollTop = editorScrollTop + now;
},
done: function() {
setTimeout(function() {
isEditorMoving = false;
}, 100);
},
}).dequeue('scrollLinkFx');
}
else {
scrollingHelper.stop('scrollLinkFx', true).css('value', 0).animate({ scrollingHelper.stop('scrollLinkFx', true).css('value', 0).animate({
value: destScrollTop - editorScrollTop value: destScrollTop - editorScrollTop
}, { }, {
@ -233,7 +216,12 @@ define([
step: function(now) { step: function(now) {
isEditorMoving = true; isEditorMoving = true;
lastEditorScrollTop = editorScrollTop + now; lastEditorScrollTop = editorScrollTop + now;
if(window.lightMode) {
$editorElt.scrollTop(lastEditorScrollTop);
}
else {
aceEditor.session.setScrollTop(lastEditorScrollTop); aceEditor.session.setScrollTop(lastEditorScrollTop);
}
}, },
done: function() { done: function() {
_.defer(function() { _.defer(function() {
@ -242,7 +230,6 @@ define([
}, },
}).dequeue('scrollLinkFx'); }).dequeue('scrollLinkFx');
} }
}
}, 100); }, 100);
scrollLink.onLayoutResize = function() { scrollLink.onLayoutResize = function() {

View File

@ -17,7 +17,8 @@ define([
}; };
var regex = /^(\s*-{3}\s*\n([\w\W]+?)\n\s*-{3}\s*\n)?([\w\W]*)$/; var regex = /^(\s*-{3}\s*\n([\w\W]+?)\n\s*-{3}\s*\n)?([\w\W]*)$/;
yamlFrontMatterParser.onContentChanged = function(fileDesc) {
function parseFrontMatter(fileDesc) {
var text = fileDesc.content; var text = fileDesc.content;
var results = regex.exec(text); var results = regex.exec(text);
var yaml = results[2]; var yaml = results[2];
@ -34,11 +35,14 @@ define([
} }
catch (e) { catch (e) {
eventMgr.onMarkdownTrim(0); eventMgr.onMarkdownTrim(0);
return text; return;
} }
} }
eventMgr.onMarkdownTrim((results[1] || '').length); eventMgr.onMarkdownTrim((results[1] || '').length);
}; }
yamlFrontMatterParser.onFileOpen = parseFrontMatter;
yamlFrontMatterParser.onContentChanged = parseFrontMatter;
return yamlFrontMatterParser; return yamlFrontMatterParser;
}); });

View File

@ -123,6 +123,22 @@
</div> </div>
<div class=dropdown-header>IMPORT</div> <div class=dropdown-header>IMPORT</div>
<div class="list-group"> <div class="list-group">
<a class="list-group-item action-sync-import-dropbox" href="#"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-dropbox"></i> Open from
Dropbox</a>
<a href="#" class="list-group-item submenu-sync-gdrive action-sync-import-gdrive"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-gdrive"></i> Open from
Google Drive</a>
<a href="#" class="list-group-item submenu-sync-gdrivesec action-sync-import-gdrivesec"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-gdrive"></i> Open from
Google Drive <small>(2nd account)</small></a>
<a href="#" class="list-group-item submenu-sync-gdriveter action-sync-import-gdriveter"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-gdrive"></i> Open from
Google Drive <small>(3rd account)</small></a>
<a data-toggle="modal" <a data-toggle="modal"
data-target=".modal-import-harddrive-markdown" data-target=".modal-import-harddrive-markdown"
class="list-group-item action-reset-input" href="#"><i class="list-group-item action-reset-input" href="#"><i
@ -134,22 +150,6 @@
data-target=".modal-import-harddrive-html" data-target=".modal-import-harddrive-html"
class="list-group-item action-reset-input" href="#"><i class="list-group-item action-reset-input" href="#"><i
class="icon-code"></i> Convert HTML to Markdown</a> class="icon-code"></i> Convert HTML to Markdown</a>
<a class="list-group-item action-sync-import-dropbox" href="#"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-dropbox"></i> Import from
Dropbox</a>
<a href="#" class="list-group-item submenu-sync-gdrive action-sync-import-gdrive"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-gdrive"></i> Import from
Google Drive</a>
<a href="#" class="list-group-item submenu-sync-gdrivesec action-sync-import-gdrivesec"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-gdrive"></i> Import from
Google Drive <small>(2nd account)</small></a>
<a href="#" class="list-group-item submenu-sync-gdriveter action-sync-import-gdriveter"
data-toggle="collapse" data-target=".menu-panel"><i
class="icon-provider-gdrive"></i> Import from
Google Drive <small>(3rd account)</small></a>
</div> </div>
<ul class="nav"> <ul class="nav">
<li><a href="#" data-toggle="modal" <li><a href="#" data-toggle="modal"

View File

@ -106,6 +106,7 @@ Prism.languages.md = (function() {
'md md-toc': /^\s*\[(toc|TOC)\]\s*$/g 'md md-toc': /^\s*\[(toc|TOC)\]\s*$/g
} }
}; };
md.br = /^\n$/gm;
md.img = { md.img = {
pattern: /!\[[^\]]*\]\([^\)]+\)/g, pattern: /!\[[^\]]*\]\([^\)]+\)/g,
inside: { inside: {

View File

@ -1252,7 +1252,7 @@ a {
word-break: break-word; word-break: break-word;
> div { > div {
margin: 0 auto; margin: 0 auto;
padding: 10px 0 230px; padding-bottom: 230px;
} }
} }