Created selectionMgr object in editor

This commit is contained in:
benweet 2014-04-05 01:54:06 +01:00
parent e9fe7014b8
commit da2351d837
7 changed files with 277 additions and 268 deletions

View File

@ -321,8 +321,8 @@ define([
// Adjust editor's cursor position and local discussions at the same time // Adjust editor's cursor position and local discussions at the same time
if(fileMgr.currentFile === fileDesc) { if(fileMgr.currentFile === fileDesc) {
editorSelection = { editorSelection = {
selectionStart: editor.inputElt.selectionStart, selectionStart: editor.selectionMgr.selectionStart,
selectionEnd: editor.inputElt.selectionEnd selectionEnd: editor.selectionMgr.selectionEnd
}; };
localDiscussionArray.push(editorSelection); localDiscussionArray.push(editorSelection);
fileDesc.newDiscussion && localDiscussionArray.push(fileDesc.newDiscussion); fileDesc.newDiscussion && localDiscussionArray.push(fileDesc.newDiscussion);
@ -380,7 +380,7 @@ define([
} }
if(fileMgr.currentFile === fileDesc) { if(fileMgr.currentFile === fileDesc) {
editor.setValueNoWatch(newContent); editor.setValueNoWatch(newContent);
editorSelection && editor.inputElt.setSelectionStartEnd( editorSelection && editor.selectionMgr.setSelectionStartEnd(
editorSelection.selectionStart, editorSelection.selectionStart,
editorSelection.selectionEnd editorSelection.selectionEnd
); );
@ -405,8 +405,8 @@ define([
}); });
commentsChanged && eventMgr.onCommentsChanged(fileDesc); commentsChanged && eventMgr.onCommentsChanged(fileDesc);
} }
editor.undoManager.currentMode = 'sync'; editor.undoMgr.currentMode = 'sync';
editor.undoManager.saveState(); editor.undoMgr.saveState();
eventMgr.onMessage('"' + remoteTitle + '" has been updated from ' + self.providerName + '.'); eventMgr.onMessage('"' + remoteTitle + '" has been updated from ' + self.providerName + '.');
if(conflictList.length) { if(conflictList.length) {
eventMgr.onMessage('"' + remoteTitle + '" has conflicts that you have to review.'); eventMgr.onMessage('"' + remoteTitle + '" has conflicts that you have to review.');

View File

@ -394,7 +394,7 @@ define([
if(pagedownEditor !== undefined) { if(pagedownEditor !== undefined) {
// If the editor is already created // If the editor is already created
return editor.undoManager.init(); return editor.undoMgr.init();
} }
// Create the converter and the editor // Create the converter and the editor
@ -411,7 +411,7 @@ define([
}; };
converter.setOptions(options); converter.setOptions(options);
pagedownEditor = new Markdown.Editor(converter, undefined, { pagedownEditor = new Markdown.Editor(converter, undefined, {
undoManager: editor.undoManager undoManager: editor.undoMgr
}); });
// Custom insert link dialog // Custom insert link dialog
@ -435,7 +435,7 @@ define([
eventMgr.onPagedownConfigure(pagedownEditor); eventMgr.onPagedownConfigure(pagedownEditor);
pagedownEditor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview); pagedownEditor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview);
pagedownEditor.run(); pagedownEditor.run();
editor.undoManager.init(); editor.undoMgr.init();
// Hide default buttons // Hide default buttons
$(".wmd-button-row li").addClass("btn btn-success").css("left", 0).find("span").hide(); $(".wmd-button-row li").addClass("btn btn-success").css("left", 0).find("span").hide();

View File

@ -19,8 +19,6 @@ define([
} }
var editor = {}; var editor = {};
var selectionStart = 0;
var selectionEnd = 0;
var scrollTop = 0; var scrollTop = 0;
var inputElt; var inputElt;
var $inputElt; var $inputElt;
@ -98,50 +96,6 @@ define([
var watcher = new Watcher(); var watcher = new Watcher();
editor.watcher = watcher; editor.watcher = watcher;
function setValue(value) {
var startOffset = diffMatchPatch.diff_commonPrefix(previousTextContent, value);
var endOffset = Math.min(
diffMatchPatch.diff_commonSuffix(previousTextContent, value),
previousTextContent.length - startOffset,
value.length - startOffset
);
var replacement = value.substring(startOffset, value.length - endOffset);
var range = createRange(startOffset, previousTextContent.length - endOffset);
range.deleteContents();
range.insertNode(document.createTextNode(replacement));
}
function setValueNoWatch(value) {
setValue(value);
previousTextContent = value;
}
editor.setValueNoWatch = setValueNoWatch;
function setSelectionStartEnd(start, end, applySelection) {
selectionStart = start;
selectionEnd = end;
fileDesc.editorStart = selectionStart;
fileDesc.editorEnd = selectionEnd;
if(applySelection === false) {
return;
}
var range = createRange(start, end);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
function createRange(start, end) {
var range = document.createRange();
var offset = _.isObject(start) ? start : findOffset(start);
range.setStart(offset.element, offset.offset);
if (end && end != start) {
offset = _.isObject(end) ? end : findOffset(end);
}
range.setEnd(offset.element, offset.offset);
return range;
}
var diffMatchPatch = new diff_match_patch(); var diffMatchPatch = new diff_match_patch();
var jsonDiffPatch = jsondiffpatch.create({ var jsonDiffPatch = jsondiffpatch.create({
objectHash: function(obj) { objectHash: function(obj) {
@ -155,8 +109,210 @@ define([
} }
}); });
var previousTextContent; function SelectionMgr() {
function UndoManager() { this.selectionStart = 0;
this.selectionEnd = 0;
this.cursorY = 0;
this.findOffset = function(offset) {
var walker = document.createTreeWalker(contentElt, 4);
while(walker.nextNode()) {
var text = walker.currentNode.nodeValue || '';
if (text.length > offset) {
return {
container: walker.currentNode,
offset: offset
};
}
offset -= text.length;
}
return {
container: contentElt,
offset: 0
};
};
this.createRange = function(start, end) {
var range = document.createRange();
var offset = _.isObject(start) ? start : this.findOffset(start);
range.setStart(offset.container, offset.offset);
if (end && end != start) {
offset = _.isObject(end) ? end : this.findOffset(end);
}
range.setEnd(offset.container, offset.offset);
return range;
};
this.setSelectionStartEnd = function(start, end, range, skipSelectionUpdate) {
if(start === undefined) {
start = this.selectionStart;
}
if(end === undefined) {
end = this.selectionEnd;
}
var min = Math.min(start, end);
var max = Math.max(start, end);
range = range || this.createRange(min, max);
if(start < end || !skipSelectionUpdate) {
this.selectionStart = min;
this.selectionEnd = max;
}
else {
this.selectionStart = max;
this.selectionEnd = min;
}
if(!skipSelectionUpdate) {
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
fileDesc.editorStart = this.selectionStart;
fileDesc.editorEnd = this.selectionEnd;
// Update cursor coordinates
$inputElt.toggleClass('has-selection', this.selectionStart !== this.selectionEnd);
var coordinates = this.getCoordinates(this.selectionEnd, this.selectionEndContainer, this.selectionEndOffset);
if(this.cursorY !== coordinates.y) {
this.cursorY = coordinates.y;
eventMgr.onCursorCoordinates(coordinates.x, coordinates.y);
}
return range;
};
this.saveSelectionState = function(skipSelectionUpdate) {
if(fileChanged === false) {
var selection = window.getSelection();
if(!skipSelectionUpdate && selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
var element = range.startContainer;
if ((inputElt.compareDocumentPosition(element) & 0x10)) {
var container = element;
var offset = range.startOffset;
do {
while (element = element.previousSibling) {
if (element.textContent) {
offset += element.textContent.length;
}
}
element = container = container.parentNode;
} while (element && element != inputElt);
// Determine if it's a backward selection
var isBackwardSelection = false;
if (!selection.isCollapsed) {
var tmpRange = document.createRange();
tmpRange.setStart(selection.anchorNode, selection.anchorOffset);
tmpRange.setEnd(selection.focusNode, selection.focusOffset);
isBackwardSelection = tmpRange.collapsed;
tmpRange.detach();
}
if(isBackwardSelection) {
this.setSelectionStartEnd(offset + (range + '').length, offset, range, true);
}
else {
this.setSelectionStartEnd(offset, offset + (range + '').length, range, true);
}
}
}
}
undoMgr.saveSelectionState();
};
this.getCoordinates = function(inputOffset, container, offset) {
if(!container) {
offset = this.findOffset(inputOffset);
container = offset.container;
offset = offset.offset;
}
var x = 0;
var y = 0;
if(container.textContent == '\n') {
y = container.parentNode.offsetTop + container.parentNode.offsetHeight / 2;
}
else {
var selectedChar = textContent[inputOffset];
var startOffset = {
container: container,
offset: offset
};
var endOffset = {
container: container,
offset: offset
};
if(selectedChar === undefined || selectedChar == '\n') {
if(startOffset.offset === 0) {
startOffset = inputOffset - 1;
}
else {
startOffset.offset -= 1;
}
}
else {
if(endOffset.offset === container.textContent.length) {
endOffset = inputOffset + 1;
}
else {
endOffset.offset += 1;
}
}
var selectionRange = this.createRange(startOffset, endOffset);
var selectionRect = selectionRange.getBoundingClientRect();
y = selectionRect.top + selectionRect.height / 2 - inputElt.offsetTop + inputElt.scrollTop;
selectionRange.detach();
}
return {
x: x,
y: y
};
};
}
var selectionMgr = new SelectionMgr();
editor.selectionMgr = selectionMgr;
var adjustCursorPosition = _.debounce(function() {
if(inputElt === undefined) {
return;
}
selectionMgr.saveSelectionState();
var adjust = inputElt.offsetHeight / 2;
if(adjust > 130) {
adjust = 130;
}
var cursorMinY = inputElt.scrollTop + adjust;
var cursorMaxY = inputElt.scrollTop + inputElt.offsetHeight - adjust;
if(selectionMgr.cursorY < cursorMinY) {
inputElt.scrollTop += selectionMgr.cursorY - cursorMinY;
}
else if(selectionMgr.cursorY > cursorMaxY) {
inputElt.scrollTop += selectionMgr.cursorY - cursorMaxY;
}
}, 0);
eventMgr.addListener('onLayoutResize', adjustCursorPosition);
var textContent;
function setValue(value) {
var startOffset = diffMatchPatch.diff_commonPrefix(textContent, value);
var endOffset = Math.min(
diffMatchPatch.diff_commonSuffix(textContent, value),
textContent.length - startOffset,
value.length - startOffset
);
var replacement = value.substring(startOffset, value.length - endOffset);
var range = selectionMgr.createRange(startOffset, textContent.length - endOffset);
range.deleteContents();
range.insertNode(document.createTextNode(replacement));
}
function setValueNoWatch(value) {
setValue(value);
textContent = value;
}
editor.setValueNoWatch = setValueNoWatch;
function getValue() {
return textContent;
}
editor.setValueNoWatch = getValue;
function UndoMgr() {
var undoStack = []; var undoStack = [];
var redoStack = []; var redoStack = [];
var lastTime; var lastTime;
@ -169,7 +325,7 @@ define([
}; };
this.setMode = function() {}; // For compatibility with PageDown this.setMode = function() {}; // For compatibility with PageDown
this.onButtonStateChange = function() {}; // To be overridden by PageDown this.onButtonStateChange = function() {}; // To be overridden by PageDown
this.saveState = function() { this.saveState = _.debounce(function() {
redoStack = []; redoStack = [];
var currentTime = Date.now(); var currentTime = Date.now();
if(this.currentMode == 'comment' || (this.currentMode != lastMode && lastMode != 'newlines') || currentTime - lastTime > 1000) { if(this.currentMode == 'comment' || (this.currentMode != lastMode && lastMode != 'newlines') || currentTime - lastTime > 1000) {
@ -186,20 +342,20 @@ define([
currentState = { currentState = {
selectionStartBefore: selectionStartBefore, selectionStartBefore: selectionStartBefore,
selectionEndBefore: selectionEndBefore, selectionEndBefore: selectionEndBefore,
selectionStartAfter: selectionStart, selectionStartAfter: selectionMgr.selectionStart,
selectionEndAfter: selectionEnd, selectionEndAfter: selectionMgr.selectionEnd,
content: previousTextContent, content: textContent,
discussionListJSON: fileDesc.discussionListJSON discussionListJSON: fileDesc.discussionListJSON
}; };
lastTime = currentTime; lastTime = currentTime;
lastMode = this.currentMode; lastMode = this.currentMode;
this.currentMode = undefined; this.currentMode = undefined;
this.onButtonStateChange(); this.onButtonStateChange();
}; }, 0);
this.saveSelectionState = _.debounce(function() { this.saveSelectionState = _.debounce(function() {
if(this.currentMode === undefined) { if(this.currentMode === undefined) {
selectionStartBefore = selectionStart; selectionStartBefore = selectionMgr.selectionStart;
selectionEndBefore = selectionEnd; selectionEndBefore = selectionMgr.selectionEnd;
} }
}, 10); }, 10);
this.canUndo = function() { this.canUndo = function() {
@ -212,12 +368,12 @@ define([
function restoreState(state, selectionStart, selectionEnd) { function restoreState(state, selectionStart, selectionEnd) {
// Update editor // Update editor
watcher.noWatch(function() { watcher.noWatch(function() {
if(previousTextContent != state.content) { if(textContent != state.content) {
setValueNoWatch(state.content); setValueNoWatch(state.content);
fileDesc.content = state.content; fileDesc.content = state.content;
eventMgr.onContentChanged(fileDesc, state.content); eventMgr.onContentChanged(fileDesc, state.content);
} }
setSelectionStartEnd(selectionStart, selectionEnd); selectionMgr.setSelectionStartEnd(selectionStart, selectionEnd);
var discussionListJSON = fileDesc.discussionListJSON; var discussionListJSON = fileDesc.discussionListJSON;
if(discussionListJSON != state.discussionListJSON) { if(discussionListJSON != state.discussionListJSON) {
var oldDiscussionList = fileDesc.discussionList; var oldDiscussionList = fileDesc.discussionList;
@ -280,60 +436,31 @@ define([
contentElt.textContent = content; contentElt.textContent = content;
}; };
} }
var undoManager = new UndoManager(); var undoMgr = new UndoMgr();
editor.undoManager = undoManager; editor.undoMgr = undoMgr;
function onComment() { function onComment() {
if(watcher.isWatching === true) { if(watcher.isWatching === true) {
undoManager.currentMode = 'comment'; undoMgr.currentMode = 'comment';
undoManager.saveState(); undoMgr.saveState();
} }
} }
eventMgr.addListener('onDiscussionCreated', onComment); eventMgr.addListener('onDiscussionCreated', onComment);
eventMgr.addListener('onDiscussionRemoved', onComment); eventMgr.addListener('onDiscussionRemoved', onComment);
eventMgr.addListener('onCommentsChanged', onComment); eventMgr.addListener('onCommentsChanged', onComment);
function saveSelectionState() {
if(fileChanged === false) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
var element = range.startContainer;
if ((inputElt.compareDocumentPosition(element) & 0x10)) {
var container = element;
var offset = range.startOffset;
do {
while (element = element.previousSibling) {
if (element.textContent) {
offset += element.textContent.length;
}
}
element = container = container.parentNode;
} while (element && element != inputElt);
selectionStart = offset;
selectionEnd = offset + (range + '').length;
}
}
fileDesc.editorStart = selectionStart;
fileDesc.editorEnd = selectionEnd;
}
undoManager.saveSelectionState();
}
function checkContentChange() { function checkContentChange() {
saveSelectionState();
var currentTextContent = inputElt.textContent; var currentTextContent = inputElt.textContent;
if(fileChanged === false) { if(fileChanged === false) {
if(currentTextContent == previousTextContent) { if(currentTextContent == textContent) {
return; return;
} }
if(!/\n$/.test(currentTextContent)) { if(!/\n$/.test(currentTextContent)) {
currentTextContent += '\n'; currentTextContent += '\n';
} }
undoManager.currentMode = undoManager.currentMode || 'typing'; undoMgr.currentMode = undoMgr.currentMode || 'typing';
var changes = diffMatchPatch.diff_main(previousTextContent, currentTextContent); var changes = diffMatchPatch.diff_main(textContent, currentTextContent);
textContent = currentTextContent;
// Move comments according to changes // Move comments according to changes
var updateDiscussionList = false; var updateDiscussionList = false;
var startOffset = 0; var startOffset = 0;
@ -377,138 +504,27 @@ define([
if(updateDiscussionList === true) { if(updateDiscussionList === true) {
fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage
} }
fileDesc.content = currentTextContent; fileDesc.content = textContent;
eventMgr.onContentChanged(fileDesc, currentTextContent); selectionMgr.saveSelectionState();
eventMgr.onContentChanged(fileDesc, textContent);
updateDiscussionList && eventMgr.onCommentsChanged(fileDesc); updateDiscussionList && eventMgr.onCommentsChanged(fileDesc);
previousTextContent = currentTextContent; undoMgr.saveState();
undoManager.saveState();
} }
else { else {
if(!/\n$/.test(currentTextContent)) { if(!/\n$/.test(currentTextContent)) {
currentTextContent += '\n'; currentTextContent += '\n';
fileDesc.content = currentTextContent; fileDesc.content = currentTextContent;
} }
selectionStart = fileDesc.editorStart; textContent = currentTextContent;
selectionEnd = fileDesc.editorEnd; selectionMgr.setSelectionStartEnd(fileDesc.editorStart, fileDesc.editorEnd);
eventMgr.onFileOpen(fileDesc, currentTextContent); eventMgr.onFileOpen(fileDesc, textContent);
previewElt.scrollTop = fileDesc.previewScrollTop; previewElt.scrollTop = fileDesc.previewScrollTop;
scrollTop = fileDesc.editorScrollTop; scrollTop = fileDesc.editorScrollTop;
inputElt.scrollTop = scrollTop; inputElt.scrollTop = scrollTop;
previousTextContent = currentTextContent;
fileChanged = false; fileChanged = false;
} }
} }
function findOffset(offset) {
var walker = document.createTreeWalker(contentElt, 4);
while(walker.nextNode()) {
var text = walker.currentNode.nodeValue || '';
if (text.length > offset) {
return {
element: walker.currentNode,
offset: offset
};
}
offset -= text.length;
}
return {
element: contentElt,
offset: 0,
error: true
};
}
function getCoordinates(inputOffset, element, offset) {
var x = 0;
var y = 0;
if(element.textContent == '\n') {
y = element.parentNode.offsetTop + element.parentNode.offsetHeight / 2;
}
else {
var selectedChar = inputElt.textContent[inputOffset];
var selectionRange;
if(selectedChar === undefined || selectedChar == '\n') {
selectionRange = createRange(inputOffset - 1, {
element: element,
offset: offset
});
}
else {
selectionRange = createRange({
element: element,
offset: offset
}, inputOffset + 1);
}
var selectionRect = selectionRange.getBoundingClientRect();
y = selectionRect.top + selectionRect.height / 2 - inputElt.offsetTop + inputElt.scrollTop;
selectionRange.detach();
}
return {
x: x,
y: y
};
}
var cursorY = 0;
var isBackwardSelection = false;
function updateCursorCoordinates() {
saveSelectionState();
$inputElt.toggleClass('has-selection', selectionStart !== selectionEnd);
var element;
var offset;
var inputOffset;
if(inputElt.focused) {
isBackwardSelection = false;
var selection = window.getSelection();
if(!selection.rangeCount) {
return;
}
if (!selection.isCollapsed) {
var range = document.createRange();
range.setStart(selection.anchorNode, selection.anchorOffset);
range.setEnd(selection.focusNode, selection.focusOffset);
isBackwardSelection = range.collapsed;
range.detach();
}
var selectionRange = selection.getRangeAt(0);
element = isBackwardSelection ? selectionRange.startContainer : selectionRange.endContainer;
offset = isBackwardSelection ? selectionRange.startOffset : selectionRange.endOffset;
inputOffset = isBackwardSelection ? selectionStart : selectionEnd;
}
else {
inputOffset = isBackwardSelection ? selectionStart : selectionEnd;
var elementOffset = findOffset(inputOffset);
element = elementOffset.element;
offset = elementOffset.offset;
}
var coordinates = getCoordinates(inputOffset, element, offset);
cursorY = coordinates.y;
eventMgr.onCursorCoordinates(coordinates.x, coordinates.y);
}
var adjustCursorPosition = _.debounce(function() {
if(inputElt === undefined) {
return;
}
updateCursorCoordinates();
var adjust = inputElt.offsetHeight / 2;
if(adjust > 130) {
adjust = 130;
}
var cursorMinY = inputElt.scrollTop + adjust;
var cursorMaxY = inputElt.scrollTop + 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;
$inputElt = $(inputElt); $inputElt = $(inputElt);
@ -549,7 +565,7 @@ define([
inputElt.focus = function() { inputElt.focus = function() {
$contentElt.focus(); $contentElt.focus();
setSelectionStartEnd(selectionStart, selectionEnd); selectionMgr.setSelectionStartEnd();
inputElt.scrollTop = scrollTop; inputElt.scrollTop = scrollTop;
}; };
$contentElt.focus(function() { $contentElt.focus(function() {
@ -561,17 +577,17 @@ define([
Object.defineProperty(inputElt, 'value', { Object.defineProperty(inputElt, 'value', {
get: function () { get: function () {
return this.textContent; return textContent;
}, },
set: setValue set: setValue
}); });
Object.defineProperty(inputElt, 'selectionStart', { Object.defineProperty(inputElt, 'selectionStart', {
get: function () { get: function () {
return selectionStart; return selectionMgr.selectionStart;
}, },
set: function (value) { set: function (value) {
setSelectionStartEnd(value, selectionEnd); selectionMgr.setSelectionStartEnd(value);
}, },
enumerable: true, enumerable: true,
@ -580,23 +596,16 @@ define([
Object.defineProperty(inputElt, 'selectionEnd', { Object.defineProperty(inputElt, 'selectionEnd', {
get: function () { get: function () {
return selectionEnd; return selectionMgr.selectionEnd;
}, },
set: function (value) { set: function (value) {
setSelectionStartEnd(selectionStart, value); selectionMgr.setSelectionStartEnd(undefined, value);
}, },
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
inputElt.setSelectionStartEnd = setSelectionStartEnd;
inputElt.createRange = createRange;
inputElt.getOffsetCoordinates = function(ss) {
var offset = findOffset(ss);
return getCoordinates(ss, offset.element, offset.offset);
};
var clearNewline = false; var clearNewline = false;
$contentElt.on('keydown', function (evt) { $contentElt.on('keydown', function (evt) {
if( if(
@ -607,7 +616,7 @@ define([
) { ) {
return; return;
} }
saveSelectionState(); selectionMgr.saveSelectionState();
var cmdOrCtrl = evt.metaKey || evt.ctrlKey; var cmdOrCtrl = evt.metaKey || evt.ctrlKey;
if(!cmdOrCtrl) { if(!cmdOrCtrl) {
@ -634,15 +643,15 @@ define([
}) })
.on('mouseup', function() { .on('mouseup', function() {
setTimeout(function() { setTimeout(function() {
updateCursorCoordinates(); selectionMgr.saveSelectionState();
}, 0); }, 0);
}) })
.on('paste', function () { .on('paste', function () {
undoManager.currentMode = 'paste'; undoMgr.currentMode = 'paste';
adjustCursorPosition(); adjustCursorPosition();
}) })
.on('cut', function () { .on('cut', function () {
undoManager.currentMode = 'cut'; undoMgr.currentMode = 'cut';
adjustCursorPosition(); adjustCursorPosition();
}); });
@ -650,8 +659,8 @@ define([
options = options || {}; options = options || {};
var text = inputElt.value, var text = inputElt.value,
ss = options.start || selectionStart, ss = options.start || selectionMgr.selectionStart,
se = options.end || selectionEnd, se = options.end || selectionMgr.selectionEnd,
state = { state = {
ss: ss, ss: ss,
se: se, se: se,
@ -662,7 +671,7 @@ define([
actions[action](state, options); actions[action](state, options);
inputElt.value = state.before + state.selection + state.after; inputElt.value = state.before + state.selection + state.after;
setSelectionStartEnd(state.ss, state.se); selectionMgr.setSelectionStartEnd(state.ss, state.se);
$inputElt.trigger('input'); $inputElt.trigger('input');
}; };
@ -719,7 +728,7 @@ define([
clearNewline = true; clearNewline = true;
} }
undoManager.currentMode = 'newlines'; undoMgr.currentMode = 'newlines';
state.before += '\n' + indent; state.before += '\n' + indent;
state.selection = ''; state.selection = '';
@ -804,7 +813,7 @@ define([
if(fileChanged === true) { if(fileChanged === true) {
contentElt.innerHTML = ''; contentElt.innerHTML = '';
contentElt.appendChild(newSectionEltList); contentElt.appendChild(newSectionEltList);
setSelectionStartEnd(selectionStart, selectionEnd); selectionMgr.setSelectionStartEnd();
} }
else { else {
// Remove outdated sections // Remove outdated sections
@ -829,8 +838,7 @@ define([
} }
childNode = nextNode; childNode = nextNode;
} }
selectionMgr.setSelectionStartEnd();
setSelectionStartEnd(selectionStart, selectionEnd);
} }
}); });
} }
@ -866,5 +874,6 @@ define([
section.elt = sectionElt; section.elt = sectionElt;
} }
eventMgr.onEditorCreated(editor);
return editor; return editor;
}); });

View File

@ -170,6 +170,7 @@ define([
addEventHook("onPeriodicRun"); addEventHook("onPeriodicRun");
// To access modules that are loaded after extensions // To access modules that are loaded after extensions
addEventHook("onEditorCreated");
addEventHook("onFileMgrCreated"); addEventHook("onFileMgrCreated");
addEventHook("onSynchronizerCreated"); addEventHook("onSynchronizerCreated");
addEventHook("onPublisherCreated"); addEventHook("onPublisherCreated");

View File

@ -32,6 +32,11 @@ define([
eventMgr = eventMgrParam; eventMgr = eventMgrParam;
}; };
var editor;
comments.onEditorCreated = function(editorParam) {
editor = editorParam;
};
var offsetMap = {}; var offsetMap = {};
function setCommentEltCoordinates(commentElt, y) { function setCommentEltCoordinates(commentElt, y) {
var lineIndex = Math.round(y / 10); var lineIndex = Math.round(y / 10);
@ -123,7 +128,7 @@ define([
commentElt.className += ' icon-split'; commentElt.className += ' icon-split';
} }
commentElt.discussionIndex = discussion.discussionIndex; commentElt.discussionIndex = discussion.discussionIndex;
var coordinates = inputElt.getOffsetCoordinates(discussion.selectionEnd); var coordinates = editor.selectionMgr.getCoordinates(discussion.selectionEnd);
var lineIndex = setCommentEltCoordinates(commentElt, coordinates.y); var lineIndex = setCommentEltCoordinates(commentElt, coordinates.y);
offsetMap[lineIndex] = (offsetMap[lineIndex] || 0) + 1; offsetMap[lineIndex] = (offsetMap[lineIndex] || 0) + 1;
@ -166,7 +171,7 @@ define([
} }
catch(e) {} catch(e) {}
var discussion = context.getDiscussion(); var discussion = context.getDiscussion();
context.selectionRange = inputElt.createRange(discussion.selectionStart, discussion.selectionEnd); context.selectionRange = editor.selectionMgr.createRange(discussion.selectionStart, discussion.selectionEnd);
// Highlight selected text // Highlight selected text
context.rangyRange = rangy.createRange(); context.rangyRange = rangy.createRange();
@ -253,7 +258,7 @@ define([
} }
var discussion = currentContext.getDiscussion(); var discussion = currentContext.getDiscussion();
var titleLength = discussion.selectionEnd - discussion.selectionStart; var titleLength = discussion.selectionEnd - discussion.selectionStart;
var title = inputElt.textContent.substr(discussion.selectionStart, titleLength > 20 ? 20 : titleLength); var title = editor.getValue().substr(discussion.selectionStart, titleLength > 20 ? 20 : titleLength);
if(titleLength > 20) { if(titleLength > 20) {
title += '...'; title += '...';
} }
@ -277,28 +282,28 @@ define([
// If it's an existing discussion // If it's an existing discussion
var discussion = context.getDiscussion(); var discussion = context.getDiscussion();
if(discussion) { if(discussion) {
context.selectionRange = inputElt.createRange(discussion.selectionStart, discussion.selectionEnd); context.selectionRange = editor.selectionMgr.setSelectionStartEnd(discussion.selectionStart, discussion.selectionEnd, undefined, true);
inputElt.setSelectionStartEnd(discussion.selectionStart, discussion.selectionEnd, false);
return; return;
} }
// Get selected text // Get selected text
var selectionStart = inputElt.selectionStart; var selectionStart = editor.selectionMgr.selectionStart;
var selectionEnd = inputElt.selectionEnd; var selectionEnd = editor.selectionMgr.selectionEnd;
if(selectionStart === selectionEnd) { if(selectionStart === selectionEnd) {
var after = inputElt.textContent.substring(selectionStart); var textContent = editor.getValue();
var after = textContent.substring(selectionStart);
var match = /\S+/.exec(after); var match = /\S+/.exec(after);
if(match) { if(match) {
selectionStart += match.index; selectionStart += match.index;
if(match.index === 0) { if(match.index === 0) {
while(selectionStart && /\S/.test(inputElt.textContent[selectionStart - 1])) { while(selectionStart && /\S/.test(textContent[selectionStart - 1])) {
selectionStart--; selectionStart--;
} }
} }
selectionEnd += match.index + match[0].length; selectionEnd += match.index + match[0].length;
} }
} }
context.selectionRange = inputElt.createRange(selectionStart, selectionEnd); context.selectionRange = editor.selectionMgr.createRange(selectionStart, selectionEnd);
currentFileDesc.newDiscussion = { currentFileDesc.newDiscussion = {
selectionStart: selectionStart, selectionStart: selectionStart,
selectionEnd: selectionEnd, selectionEnd: selectionEnd,

View File

@ -3,6 +3,8 @@ Prism.languages.md = (function() {
var urlPattern = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>\[\]'"]+|\([^\s()<>\[\]'"]*\))+(?:\([^\s()<>\[\]'"]*\)|[^\s`!()\[\]{}:'".,<>?«»“”‘’]))/gi; var urlPattern = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>\[\]'"]+|\([^\s()<>\[\]'"]*\))+(?:\([^\s()<>\[\]'"]*\)|[^\s`!()\[\]{}:'".,<>?«»“”‘’]))/gi;
var emailPattern = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/gi; var emailPattern = /[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/gi;
var latex = Prism.languages.latex;
var md = {}; var md = {};
md.pre = { md.pre = {
pattern: /(^|(?:^|(?:^|\n)(?![ \t]*([*+\-]|\d+\.)[ \t]).*\n)\s*?\n)(\s*(?: {4}|\t).*(?:\n|$))+/g, pattern: /(^|(?:^|(?:^|\n)(?![ \t]*([*+\-]|\d+\.)[ \t]).*\n)\s*?\n)(\s*(?: {4}|\t).*(?:\n|$))+/g,
@ -65,14 +67,16 @@ Prism.languages.md = (function() {
inside: { inside: {
"md md-bracket-start": /^(\$\$|\\\\\[|\\\\\\\\\()/, "md md-bracket-start": /^(\$\$|\\\\\[|\\\\\\\\\()/,
"md md-bracket-end": /(\$\$|\\\\\]|\\\\\\\\\))/, "md md-bracket-end": /(\$\$|\\\\\]|\\\\\\\\\))/,
rest: Prism.languages.latex lf: /\n/gm,
rest: latex
} }
}; };
md['latex block'] = { md['latex block'] = {
pattern: /\\?\\begin\{[a-z]*\*?\}[\s\S]*?\\?\\end\{[a-z]*\*?\}/g, pattern: /\\?\\begin\{[a-z]*\*?\}[\s\S]*?\\?\\end\{[a-z]*\*?\}/g,
inside: { inside: {
"keyword": /\\?\\(begin|end)/, "keyword": /\\?\\(begin|end)/,
rest: Prism.languages.latex lf: /\n/gm,
rest: latex
} }
}; };
md.fndef = { md.fndef = {
@ -212,7 +216,7 @@ Prism.languages.md = (function() {
inside: { inside: {
"md md-bracket-start": /^\$/, "md md-bracket-start": /^\$/,
"md md-bracket-end": /\$$/, "md md-bracket-end": /\$$/,
rest: Prism.languages.latex rest: latex
} }
}; };
md.strong = { md.strong = {
@ -290,14 +294,4 @@ Prism.languages.md = (function() {
md.linkref.inside["ref-start"].inside["md md-underlined-text"].inside = inside; md.linkref.inside["ref-start"].inside["md md-underlined-text"].inside = inside;
return md; return md;
/*
Prism.hooks.add("wrap", function (t) {
var i = -1 !== document.getElementsByTagName("body")[0].className.indexOf("tmpl-diffs") ? true : false;
if (0 === t.type.indexOf("img") && !i) {
var s = t.content.match(/md\-src"\s>([^<]+)/),
a = t.content.match(/md\-alt"\s>([^<]+)/);
s && s[1] && s[1].match(n) && (a = ' alt="' + (a ? e(a[1]) : "") + '"', t.content += "<span class='img-preview' contenteditable='false'><img src='" + s[1] + "' " + a + " /></span>");
}
});
*/
})(); })();

View File

@ -40,7 +40,7 @@
} }
*/ */
@primary: #9d9d9d; @primary: #9a9a9a;
@secondary-color: #a8a8a8; @secondary-color: #a8a8a8;
@navbar-default-bg: #474747; @navbar-default-bg: #474747;
@btn-default-hover-bg: fade(@primary, 16%); @btn-default-hover-bg: fade(@primary, 16%);