diff --git a/public/res/classes/Provider.js b/public/res/classes/Provider.js index a84d471f..4cab7c34 100644 --- a/public/res/classes/Provider.js +++ b/public/res/classes/Provider.js @@ -321,8 +321,8 @@ define([ // Adjust editor's cursor position and local discussions at the same time if(fileMgr.currentFile === fileDesc) { editorSelection = { - selectionStart: editor.inputElt.selectionStart, - selectionEnd: editor.inputElt.selectionEnd + selectionStart: editor.selectionMgr.selectionStart, + selectionEnd: editor.selectionMgr.selectionEnd }; localDiscussionArray.push(editorSelection); fileDesc.newDiscussion && localDiscussionArray.push(fileDesc.newDiscussion); @@ -380,7 +380,7 @@ define([ } if(fileMgr.currentFile === fileDesc) { editor.setValueNoWatch(newContent); - editorSelection && editor.inputElt.setSelectionStartEnd( + editorSelection && editor.selectionMgr.setSelectionStartEnd( editorSelection.selectionStart, editorSelection.selectionEnd ); @@ -405,8 +405,8 @@ define([ }); commentsChanged && eventMgr.onCommentsChanged(fileDesc); } - editor.undoManager.currentMode = 'sync'; - editor.undoManager.saveState(); + editor.undoMgr.currentMode = 'sync'; + editor.undoMgr.saveState(); eventMgr.onMessage('"' + remoteTitle + '" has been updated from ' + self.providerName + '.'); if(conflictList.length) { eventMgr.onMessage('"' + remoteTitle + '" has conflicts that you have to review.'); diff --git a/public/res/core.js b/public/res/core.js index 976fe204..fbc3e84e 100644 --- a/public/res/core.js +++ b/public/res/core.js @@ -394,7 +394,7 @@ define([ if(pagedownEditor !== undefined) { // If the editor is already created - return editor.undoManager.init(); + return editor.undoMgr.init(); } // Create the converter and the editor @@ -411,7 +411,7 @@ define([ }; converter.setOptions(options); pagedownEditor = new Markdown.Editor(converter, undefined, { - undoManager: editor.undoManager + undoManager: editor.undoMgr }); // Custom insert link dialog @@ -435,7 +435,7 @@ define([ eventMgr.onPagedownConfigure(pagedownEditor); pagedownEditor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview); pagedownEditor.run(); - editor.undoManager.init(); + editor.undoMgr.init(); // Hide default buttons $(".wmd-button-row li").addClass("btn btn-success").css("left", 0).find("span").hide(); diff --git a/public/res/editor.js b/public/res/editor.js index 622081a5..51e1e93e 100644 --- a/public/res/editor.js +++ b/public/res/editor.js @@ -19,8 +19,6 @@ define([ } var editor = {}; - var selectionStart = 0; - var selectionEnd = 0; var scrollTop = 0; var inputElt; var $inputElt; @@ -98,50 +96,6 @@ define([ var watcher = new 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 jsonDiffPatch = jsondiffpatch.create({ objectHash: function(obj) { @@ -155,8 +109,210 @@ define([ } }); - var previousTextContent; - function UndoManager() { + function SelectionMgr() { + 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 redoStack = []; var lastTime; @@ -169,7 +325,7 @@ define([ }; this.setMode = function() {}; // For compatibility with PageDown this.onButtonStateChange = function() {}; // To be overridden by PageDown - this.saveState = function() { + this.saveState = _.debounce(function() { redoStack = []; var currentTime = Date.now(); if(this.currentMode == 'comment' || (this.currentMode != lastMode && lastMode != 'newlines') || currentTime - lastTime > 1000) { @@ -186,20 +342,20 @@ define([ currentState = { selectionStartBefore: selectionStartBefore, selectionEndBefore: selectionEndBefore, - selectionStartAfter: selectionStart, - selectionEndAfter: selectionEnd, - content: previousTextContent, + selectionStartAfter: selectionMgr.selectionStart, + selectionEndAfter: selectionMgr.selectionEnd, + content: textContent, discussionListJSON: fileDesc.discussionListJSON }; lastTime = currentTime; lastMode = this.currentMode; this.currentMode = undefined; this.onButtonStateChange(); - }; + }, 0); this.saveSelectionState = _.debounce(function() { if(this.currentMode === undefined) { - selectionStartBefore = selectionStart; - selectionEndBefore = selectionEnd; + selectionStartBefore = selectionMgr.selectionStart; + selectionEndBefore = selectionMgr.selectionEnd; } }, 10); this.canUndo = function() { @@ -212,12 +368,12 @@ define([ function restoreState(state, selectionStart, selectionEnd) { // Update editor watcher.noWatch(function() { - if(previousTextContent != state.content) { + if(textContent != state.content) { setValueNoWatch(state.content); fileDesc.content = state.content; eventMgr.onContentChanged(fileDesc, state.content); } - setSelectionStartEnd(selectionStart, selectionEnd); + selectionMgr.setSelectionStartEnd(selectionStart, selectionEnd); var discussionListJSON = fileDesc.discussionListJSON; if(discussionListJSON != state.discussionListJSON) { var oldDiscussionList = fileDesc.discussionList; @@ -280,60 +436,31 @@ define([ contentElt.textContent = content; }; } - var undoManager = new UndoManager(); - editor.undoManager = undoManager; + var undoMgr = new UndoMgr(); + editor.undoMgr = undoMgr; function onComment() { if(watcher.isWatching === true) { - undoManager.currentMode = 'comment'; - undoManager.saveState(); + undoMgr.currentMode = 'comment'; + undoMgr.saveState(); } } eventMgr.addListener('onDiscussionCreated', onComment); eventMgr.addListener('onDiscussionRemoved', 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() { - saveSelectionState(); var currentTextContent = inputElt.textContent; if(fileChanged === false) { - if(currentTextContent == previousTextContent) { + if(currentTextContent == textContent) { return; } if(!/\n$/.test(currentTextContent)) { currentTextContent += '\n'; } - undoManager.currentMode = undoManager.currentMode || 'typing'; - var changes = diffMatchPatch.diff_main(previousTextContent, currentTextContent); + undoMgr.currentMode = undoMgr.currentMode || 'typing'; + var changes = diffMatchPatch.diff_main(textContent, currentTextContent); + textContent = currentTextContent; // Move comments according to changes var updateDiscussionList = false; var startOffset = 0; @@ -377,138 +504,27 @@ define([ if(updateDiscussionList === true) { fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage } - fileDesc.content = currentTextContent; - eventMgr.onContentChanged(fileDesc, currentTextContent); + fileDesc.content = textContent; + selectionMgr.saveSelectionState(); + eventMgr.onContentChanged(fileDesc, textContent); updateDiscussionList && eventMgr.onCommentsChanged(fileDesc); - previousTextContent = currentTextContent; - undoManager.saveState(); + undoMgr.saveState(); } else { if(!/\n$/.test(currentTextContent)) { currentTextContent += '\n'; fileDesc.content = currentTextContent; } - selectionStart = fileDesc.editorStart; - selectionEnd = fileDesc.editorEnd; - eventMgr.onFileOpen(fileDesc, currentTextContent); + textContent = currentTextContent; + selectionMgr.setSelectionStartEnd(fileDesc.editorStart, fileDesc.editorEnd); + eventMgr.onFileOpen(fileDesc, textContent); previewElt.scrollTop = fileDesc.previewScrollTop; scrollTop = fileDesc.editorScrollTop; inputElt.scrollTop = scrollTop; - previousTextContent = currentTextContent; 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) { inputElt = elt1; $inputElt = $(inputElt); @@ -549,7 +565,7 @@ define([ inputElt.focus = function() { $contentElt.focus(); - setSelectionStartEnd(selectionStart, selectionEnd); + selectionMgr.setSelectionStartEnd(); inputElt.scrollTop = scrollTop; }; $contentElt.focus(function() { @@ -561,17 +577,17 @@ define([ Object.defineProperty(inputElt, 'value', { get: function () { - return this.textContent; + return textContent; }, set: setValue }); Object.defineProperty(inputElt, 'selectionStart', { get: function () { - return selectionStart; + return selectionMgr.selectionStart; }, set: function (value) { - setSelectionStartEnd(value, selectionEnd); + selectionMgr.setSelectionStartEnd(value); }, enumerable: true, @@ -580,23 +596,16 @@ define([ Object.defineProperty(inputElt, 'selectionEnd', { get: function () { - return selectionEnd; + return selectionMgr.selectionEnd; }, set: function (value) { - setSelectionStartEnd(selectionStart, value); + selectionMgr.setSelectionStartEnd(undefined, value); }, enumerable: 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; $contentElt.on('keydown', function (evt) { if( @@ -607,7 +616,7 @@ define([ ) { return; } - saveSelectionState(); + selectionMgr.saveSelectionState(); var cmdOrCtrl = evt.metaKey || evt.ctrlKey; if(!cmdOrCtrl) { @@ -634,15 +643,15 @@ define([ }) .on('mouseup', function() { setTimeout(function() { - updateCursorCoordinates(); + selectionMgr.saveSelectionState(); }, 0); }) .on('paste', function () { - undoManager.currentMode = 'paste'; + undoMgr.currentMode = 'paste'; adjustCursorPosition(); }) .on('cut', function () { - undoManager.currentMode = 'cut'; + undoMgr.currentMode = 'cut'; adjustCursorPosition(); }); @@ -650,8 +659,8 @@ define([ options = options || {}; var text = inputElt.value, - ss = options.start || selectionStart, - se = options.end || selectionEnd, + ss = options.start || selectionMgr.selectionStart, + se = options.end || selectionMgr.selectionEnd, state = { ss: ss, se: se, @@ -662,7 +671,7 @@ define([ actions[action](state, options); inputElt.value = state.before + state.selection + state.after; - setSelectionStartEnd(state.ss, state.se); + selectionMgr.setSelectionStartEnd(state.ss, state.se); $inputElt.trigger('input'); }; @@ -719,7 +728,7 @@ define([ clearNewline = true; } - undoManager.currentMode = 'newlines'; + undoMgr.currentMode = 'newlines'; state.before += '\n' + indent; state.selection = ''; @@ -804,7 +813,7 @@ define([ if(fileChanged === true) { contentElt.innerHTML = ''; contentElt.appendChild(newSectionEltList); - setSelectionStartEnd(selectionStart, selectionEnd); + selectionMgr.setSelectionStartEnd(); } else { // Remove outdated sections @@ -829,8 +838,7 @@ define([ } childNode = nextNode; } - - setSelectionStartEnd(selectionStart, selectionEnd); + selectionMgr.setSelectionStartEnd(); } }); } @@ -866,5 +874,6 @@ define([ section.elt = sectionElt; } + eventMgr.onEditorCreated(editor); return editor; }); diff --git a/public/res/eventMgr.js b/public/res/eventMgr.js index e0e78827..ddb2f48f 100644 --- a/public/res/eventMgr.js +++ b/public/res/eventMgr.js @@ -170,6 +170,7 @@ define([ addEventHook("onPeriodicRun"); // To access modules that are loaded after extensions + addEventHook("onEditorCreated"); addEventHook("onFileMgrCreated"); addEventHook("onSynchronizerCreated"); addEventHook("onPublisherCreated"); diff --git a/public/res/extensions/comments.js b/public/res/extensions/comments.js index 3f98cf3d..719b15cd 100644 --- a/public/res/extensions/comments.js +++ b/public/res/extensions/comments.js @@ -32,6 +32,11 @@ define([ eventMgr = eventMgrParam; }; + var editor; + comments.onEditorCreated = function(editorParam) { + editor = editorParam; + }; + var offsetMap = {}; function setCommentEltCoordinates(commentElt, y) { var lineIndex = Math.round(y / 10); @@ -123,7 +128,7 @@ define([ commentElt.className += ' icon-split'; } commentElt.discussionIndex = discussion.discussionIndex; - var coordinates = inputElt.getOffsetCoordinates(discussion.selectionEnd); + var coordinates = editor.selectionMgr.getCoordinates(discussion.selectionEnd); var lineIndex = setCommentEltCoordinates(commentElt, coordinates.y); offsetMap[lineIndex] = (offsetMap[lineIndex] || 0) + 1; @@ -166,7 +171,7 @@ define([ } catch(e) {} var discussion = context.getDiscussion(); - context.selectionRange = inputElt.createRange(discussion.selectionStart, discussion.selectionEnd); + context.selectionRange = editor.selectionMgr.createRange(discussion.selectionStart, discussion.selectionEnd); // Highlight selected text context.rangyRange = rangy.createRange(); @@ -253,7 +258,7 @@ define([ } var discussion = currentContext.getDiscussion(); 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) { title += '...'; } @@ -277,28 +282,28 @@ define([ // If it's an existing discussion var discussion = context.getDiscussion(); if(discussion) { - context.selectionRange = inputElt.createRange(discussion.selectionStart, discussion.selectionEnd); - inputElt.setSelectionStartEnd(discussion.selectionStart, discussion.selectionEnd, false); + context.selectionRange = editor.selectionMgr.setSelectionStartEnd(discussion.selectionStart, discussion.selectionEnd, undefined, true); return; } // Get selected text - var selectionStart = inputElt.selectionStart; - var selectionEnd = inputElt.selectionEnd; + var selectionStart = editor.selectionMgr.selectionStart; + var selectionEnd = editor.selectionMgr.selectionEnd; if(selectionStart === selectionEnd) { - var after = inputElt.textContent.substring(selectionStart); + var textContent = editor.getValue(); + var after = textContent.substring(selectionStart); var match = /\S+/.exec(after); if(match) { selectionStart += match.index; if(match.index === 0) { - while(selectionStart && /\S/.test(inputElt.textContent[selectionStart - 1])) { + while(selectionStart && /\S/.test(textContent[selectionStart - 1])) { selectionStart--; } } selectionEnd += match.index + match[0].length; } } - context.selectionRange = inputElt.createRange(selectionStart, selectionEnd); + context.selectionRange = editor.selectionMgr.createRange(selectionStart, selectionEnd); currentFileDesc.newDiscussion = { selectionStart: selectionStart, selectionEnd: selectionEnd, diff --git a/public/res/libs/prism-markdown.js b/public/res/libs/prism-markdown.js index 94107b45..36908f24 100644 --- a/public/res/libs/prism-markdown.js +++ b/public/res/libs/prism-markdown.js @@ -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 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 = {}; md.pre = { pattern: /(^|(?:^|(?:^|\n)(?![ \t]*([*+\-]|\d+\.)[ \t]).*\n)\s*?\n)(\s*(?: {4}|\t).*(?:\n|$))+/g, @@ -65,14 +67,16 @@ Prism.languages.md = (function() { inside: { "md md-bracket-start": /^(\$\$|\\\\\[|\\\\\\\\\()/, "md md-bracket-end": /(\$\$|\\\\\]|\\\\\\\\\))/, - rest: Prism.languages.latex + lf: /\n/gm, + rest: latex } }; md['latex block'] = { pattern: /\\?\\begin\{[a-z]*\*?\}[\s\S]*?\\?\\end\{[a-z]*\*?\}/g, inside: { "keyword": /\\?\\(begin|end)/, - rest: Prism.languages.latex + lf: /\n/gm, + rest: latex } }; md.fndef = { @@ -212,7 +216,7 @@ Prism.languages.md = (function() { inside: { "md md-bracket-start": /^\$/, "md md-bracket-end": /\$$/, - rest: Prism.languages.latex + rest: latex } }; md.strong = { @@ -290,14 +294,4 @@ Prism.languages.md = (function() { md.linkref.inside["ref-start"].inside["md md-underlined-text"].inside = inside; 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 += ""); - } - }); - */ })(); diff --git a/public/res/themes/original.less b/public/res/themes/original.less index 610c399b..66f6f069 100644 --- a/public/res/themes/original.less +++ b/public/res/themes/original.less @@ -40,7 +40,7 @@ } */ -@primary: #9d9d9d; +@primary: #9a9a9a; @secondary-color: #a8a8a8; @navbar-default-bg: #474747; @btn-default-hover-bg: fade(@primary, 16%);