cledit refactoring
This commit is contained in:
parent
f0721c9405
commit
d57d2bb969
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Prism from 'prismjs';
|
import Prism from 'prismjs';
|
||||||
import cledit from '../libs/cledit';
|
import cledit from '../services/cledit';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['value', 'lang', 'disabled'],
|
props: ['value', 'lang', 'disabled'],
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
import editorSvc from '../services/editorSvc';
|
import editorSvc from '../services/editorSvc';
|
||||||
import cledit from '../libs/cledit';
|
import cledit from '../services/cledit';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
import EditorClassApplier from './common/EditorClassApplier';
|
import EditorClassApplier from './common/EditorClassApplier';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import cledit from '../../libs/cledit';
|
import cledit from '../../services/cledit';
|
||||||
import editorSvc from '../../services/editorSvc';
|
import editorSvc from '../../services/editorSvc';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import cledit from '../../libs/cledit';
|
import cledit from '../../services/cledit';
|
||||||
import editorSvc from '../../services/editorSvc';
|
import editorSvc from '../../services/editorSvc';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
import { mapGetters, mapMutations, mapActions } from 'vuex';
|
import { mapGetters, mapMutations, mapActions } from 'vuex';
|
||||||
import Prism from 'prismjs';
|
import Prism from 'prismjs';
|
||||||
import UserImage from '../UserImage';
|
import UserImage from '../UserImage';
|
||||||
import cledit from '../../libs/cledit';
|
import cledit from '../../services/cledit';
|
||||||
import editorSvc from '../../services/editorSvc';
|
import editorSvc from '../../services/editorSvc';
|
||||||
import markdownConversionSvc from '../../services/markdownConversionSvc';
|
import markdownConversionSvc from '../../services/markdownConversionSvc';
|
||||||
import utils from '../../services/utils';
|
import utils from '../../services/utils';
|
||||||
|
@ -37,15 +37,6 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
let lastTextContent = getTextContent();
|
let lastTextContent = getTextContent();
|
||||||
const highlighter = new cledit.Highlighter(editor);
|
const highlighter = new cledit.Highlighter(editor);
|
||||||
|
|
||||||
let sectionList;
|
|
||||||
|
|
||||||
function parseSections(content, isInit) {
|
|
||||||
sectionList = highlighter.parseSections(content, isInit);
|
|
||||||
editor.$allElements = Array.prototype.slice
|
|
||||||
.call(contentElt.querySelectorAll('.cledit-section *'));
|
|
||||||
return sectionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable new-cap */
|
/* eslint-disable new-cap */
|
||||||
const diffMatchPatch = new DiffMatchPatch();
|
const diffMatchPatch = new DiffMatchPatch();
|
||||||
/* eslint-enable new-cap */
|
/* eslint-enable new-cap */
|
||||||
@ -152,7 +143,11 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
}, 10);
|
}, 10);
|
||||||
|
|
||||||
let watcher;
|
let watcher;
|
||||||
|
let skipSaveSelection;
|
||||||
function checkContentChange(mutations) {
|
function checkContentChange(mutations) {
|
||||||
|
if (contentElt.textContent.indexOf('.') >= 0) {
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
watcher.noWatch(() => {
|
watcher.noWatch(() => {
|
||||||
const removedSections = [];
|
const removedSections = [];
|
||||||
const modifiedSections = [];
|
const modifiedSections = [];
|
||||||
@ -186,9 +181,13 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
marker.adjustOffset(diffs);
|
marker.adjustOffset(diffs);
|
||||||
});
|
});
|
||||||
|
|
||||||
selectionMgr.saveSelectionState();
|
if (!skipSaveSelection) {
|
||||||
const parsedSections = parseSections(newTextContent);
|
selectionMgr.saveSelectionState();
|
||||||
editor.$trigger('contentChanged', newTextContent, diffs, parsedSections);
|
}
|
||||||
|
skipSaveSelection = false;
|
||||||
|
|
||||||
|
const sectionList = highlighter.parseSections(newTextContent);
|
||||||
|
editor.$trigger('contentChanged', newTextContent, diffs, sectionList);
|
||||||
if (!ignoreUndo) {
|
if (!ignoreUndo) {
|
||||||
undoMgr.addDiffs(lastTextContent, newTextContent, diffs);
|
undoMgr.addDiffs(lastTextContent, newTextContent, diffs);
|
||||||
undoMgr.setDefaultMode('typing');
|
undoMgr.setDefaultMode('typing');
|
||||||
@ -270,12 +269,12 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
|
|
||||||
contentElt.addEventListener('keydown', keydownHandler((evt) => {
|
contentElt.addEventListener('keydown', keydownHandler((evt) => {
|
||||||
selectionMgr.saveSelectionState();
|
selectionMgr.saveSelectionState();
|
||||||
adjustCursorPosition();
|
|
||||||
|
|
||||||
// Perform keystroke
|
// Perform keystroke
|
||||||
|
let contentChanging = false;
|
||||||
const textContent = getTextContent();
|
const textContent = getTextContent();
|
||||||
const min = Math.min(selectionMgr.selectionStart, selectionMgr.selectionEnd);
|
let min = Math.min(selectionMgr.selectionStart, selectionMgr.selectionEnd);
|
||||||
const max = Math.max(selectionMgr.selectionStart, selectionMgr.selectionEnd);
|
let max = Math.max(selectionMgr.selectionStart, selectionMgr.selectionEnd);
|
||||||
const state = {
|
const state = {
|
||||||
before: textContent.slice(0, min),
|
before: textContent.slice(0, min),
|
||||||
after: textContent.slice(max),
|
after: textContent.slice(max),
|
||||||
@ -286,15 +285,26 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
if (!keystroke.handler(evt, state, editor)) {
|
if (!keystroke.handler(evt, state, editor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
editor.setContent(state.before + state.selection + state.after, false, min);
|
const newContent = state.before + state.selection + state.after;
|
||||||
const min1 = state.before.length;
|
if (newContent !== getTextContent()) {
|
||||||
const max1 = min + state.selection.length;
|
editor.setContent(newContent, false, min);
|
||||||
|
contentChanging = true;
|
||||||
|
skipSaveSelection = true;
|
||||||
|
}
|
||||||
|
min = state.before.length;
|
||||||
|
max = min + state.selection.length;
|
||||||
selectionMgr.setSelectionStartEnd(
|
selectionMgr.setSelectionStartEnd(
|
||||||
state.isBackwardSelection ? max1 : min1,
|
state.isBackwardSelection ? max : min,
|
||||||
state.isBackwardSelection ? min : max1,
|
state.isBackwardSelection ? min : max,
|
||||||
|
!contentChanging, // Expect a restore selection on mutation event
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!contentChanging) {
|
||||||
|
// Optimization to avoid saving selection
|
||||||
|
adjustCursorPosition();
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
contentElt.addEventListener('compositionstart', () => {
|
contentElt.addEventListener('compositionstart', () => {
|
||||||
@ -406,8 +416,8 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedSections = parseSections(lastTextContent, true);
|
const sectionList = highlighter.parseSections(lastTextContent, true);
|
||||||
editor.$trigger('contentChanged', lastTextContent, [0, lastTextContent], parsedSections);
|
editor.$trigger('contentChanged', lastTextContent, [0, lastTextContent], sectionList);
|
||||||
if (options.selectionStart !== undefined && options.selectionEnd !== undefined) {
|
if (options.selectionStart !== undefined && options.selectionEnd !== undefined) {
|
||||||
editor.setSelection(options.selectionStart, options.selectionEnd);
|
editor.setSelection(options.selectionStart, options.selectionEnd);
|
||||||
} else {
|
} else {
|
||||||
@ -423,4 +433,4 @@ function cledit(contentElt, scrollEltOpt) {
|
|||||||
return editor;
|
return editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = cledit;
|
export default cledit;
|
||||||
|
@ -11,7 +11,6 @@ function createStyleSheet(document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Highlighter(editor) {
|
function Highlighter(editor) {
|
||||||
const self = this;
|
|
||||||
cledit.Utils.createEventHooks(this);
|
cledit.Utils.createEventHooks(this);
|
||||||
|
|
||||||
if (!styleElts.cl_some(styleElt => document.head.contains(styleElt))) {
|
if (!styleElts.cl_some(styleElt => document.head.contains(styleElt))) {
|
||||||
@ -63,7 +62,7 @@ function Highlighter(editor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.parseSections = (content, isInit) => {
|
this.parseSections = (content, isInit) => {
|
||||||
if (this.isComposing) {
|
if (true) {
|
||||||
return sectionList;
|
return sectionList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,14 +132,14 @@ function Highlighter(editor) {
|
|||||||
sectionList = leftSections.concat(modifiedSections).concat(rightSections);
|
sectionList = leftSections.concat(modifiedSections).concat(rightSections);
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlight(section) {
|
const highlight = (section) => {
|
||||||
const html = editor.options.sectionHighlighter(section).replace(/\n/g, lfHtml);
|
const html = editor.options.sectionHighlighter(section).replace(/\n/g, lfHtml);
|
||||||
const sectionElt = document.createElement('div');
|
const sectionElt = document.createElement('div');
|
||||||
sectionElt.className = 'cledit-section';
|
sectionElt.className = 'cledit-section';
|
||||||
sectionElt.innerHTML = html;
|
sectionElt.innerHTML = html;
|
||||||
section.setElement(sectionElt);
|
section.setElement(sectionElt);
|
||||||
self.$trigger('sectionHighlighted', section);
|
this.$trigger('sectionHighlighted', section);
|
||||||
}
|
};
|
||||||
|
|
||||||
const newSectionEltList = document.createDocumentFragment();
|
const newSectionEltList = document.createDocumentFragment();
|
||||||
modifiedSections.cl_each((section) => {
|
modifiedSections.cl_each((section) => {
|
||||||
@ -183,7 +182,8 @@ function Highlighter(editor) {
|
|||||||
childNode = nextNode;
|
childNode = nextNode;
|
||||||
}
|
}
|
||||||
this.addTrailingNode();
|
this.addTrailingNode();
|
||||||
self.$trigger('highlighted');
|
this.$trigger('highlighted');
|
||||||
|
|
||||||
if (editor.selectionMgr.hasFocus()) {
|
if (editor.selectionMgr.hasFocus()) {
|
||||||
editor.selectionMgr.restoreSelection();
|
editor.selectionMgr.restoreSelection();
|
||||||
editor.selectionMgr.updateCursorCoordinates();
|
editor.selectionMgr.updateCursorCoordinates();
|
||||||
|
@ -6,7 +6,6 @@ function SelectionMgr(editor) {
|
|||||||
const scrollElt = editor.$scrollElt;
|
const scrollElt = editor.$scrollElt;
|
||||||
cledit.Utils.createEventHooks(this);
|
cledit.Utils.createEventHooks(this);
|
||||||
|
|
||||||
const self = this;
|
|
||||||
let lastSelectionStart = 0;
|
let lastSelectionStart = 0;
|
||||||
let lastSelectionEnd = 0;
|
let lastSelectionEnd = 0;
|
||||||
this.selectionStart = 0;
|
this.selectionStart = 0;
|
||||||
@ -28,7 +27,7 @@ function SelectionMgr(editor) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.createRange = function (start, end) {
|
this.createRange = (start, end) => {
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
const startContainer = isNaN(start) ? start : this.findContainer(start < 0 ? 0 : start);
|
const startContainer = isNaN(start) ? start : this.findContainer(start < 0 ? 0 : start);
|
||||||
let endContainer = startContainer;
|
let endContainer = startContainer;
|
||||||
@ -72,14 +71,14 @@ function SelectionMgr(editor) {
|
|||||||
adjustScroll = false;
|
adjustScroll = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.updateCursorCoordinates = function (adjustScrollParam) {
|
this.updateCursorCoordinates = (adjustScrollParam) => {
|
||||||
adjustScroll = adjustScroll || adjustScrollParam;
|
adjustScroll = adjustScroll || adjustScrollParam;
|
||||||
debouncedUpdateCursorCoordinates();
|
debouncedUpdateCursorCoordinates();
|
||||||
};
|
};
|
||||||
|
|
||||||
let oldSelectionRange;
|
let oldSelectionRange;
|
||||||
|
|
||||||
function checkSelection(selectionRange) {
|
const checkSelection = (selectionRange) => {
|
||||||
if (!oldSelectionRange ||
|
if (!oldSelectionRange ||
|
||||||
oldSelectionRange.startContainer !== selectionRange.startContainer ||
|
oldSelectionRange.startContainer !== selectionRange.startContainer ||
|
||||||
oldSelectionRange.startOffset !== selectionRange.startOffset ||
|
oldSelectionRange.startOffset !== selectionRange.startOffset ||
|
||||||
@ -87,11 +86,11 @@ function SelectionMgr(editor) {
|
|||||||
oldSelectionRange.endOffset !== selectionRange.endOffset
|
oldSelectionRange.endOffset !== selectionRange.endOffset
|
||||||
) {
|
) {
|
||||||
oldSelectionRange = selectionRange;
|
oldSelectionRange = selectionRange;
|
||||||
self.$trigger('selectionChanged', self.selectionStart, self.selectionEnd, selectionRange);
|
this.$trigger('selectionChanged', this.selectionStart, this.selectionEnd, selectionRange);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.hasFocus = () => contentElt === document.activeElement;
|
this.hasFocus = () => contentElt === document.activeElement;
|
||||||
|
|
||||||
@ -118,19 +117,22 @@ function SelectionMgr(editor) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveLastSelection = debounce(() => {
|
const saveLastSelection = debounce(() => {
|
||||||
lastSelectionStart = self.selectionStart;
|
lastSelectionStart = this.selectionStart;
|
||||||
lastSelectionEnd = self.selectionEnd;
|
lastSelectionEnd = this.selectionEnd;
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
function setSelection(start = self.selectionStart, end = this.selectionEnd) {
|
const setSelection = (start = this.selectionStart, end = this.selectionEnd) => {
|
||||||
self.selectionStart = start < 0 ? 0 : start;
|
this.selectionStart = start < 0 ? 0 : start;
|
||||||
self.selectionEnd = end < 0 ? 0 : end;
|
this.selectionEnd = end < 0 ? 0 : end;
|
||||||
saveLastSelection();
|
saveLastSelection();
|
||||||
}
|
};
|
||||||
|
|
||||||
this.setSelectionStartEnd = (start, end) => {
|
this.setSelectionStartEnd = (start, end, restoreSelection = true) => {
|
||||||
setSelection(start, end);
|
setSelection(start, end);
|
||||||
return this.hasFocus() && this.restoreSelection();
|
if (restoreSelection && this.hasFocus()) {
|
||||||
|
return this.restoreSelection();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.saveSelectionState = (() => {
|
this.saveSelectionState = (() => {
|
||||||
@ -217,182 +219,199 @@ function SelectionMgr(editor) {
|
|||||||
if (childA === childB) {
|
if (childA === childB) {
|
||||||
// This shouldn't be possible
|
// This shouldn't be possible
|
||||||
throw module.createError('comparePoints got to case 4 and childA and childB are the same!');
|
throw module.createError('comparePoints got to case 4 and childA and childB are the same!');
|
||||||
} else {
|
|
||||||
n = root.firstChild;
|
|
||||||
while (n) {
|
|
||||||
if (n === childA) {
|
|
||||||
return -1;
|
|
||||||
} else if (n === childB) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
n = n.nextSibling;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
n = root.firstChild;
|
||||||
|
while (n) {
|
||||||
|
if (n === childA) {
|
||||||
|
return -1;
|
||||||
|
} else if (n === childB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
n = n.nextSibling;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
const save = () => {
|
||||||
let result;
|
let result;
|
||||||
if (self.hasFocus()) {
|
if (this.hasFocus()) {
|
||||||
const selectionStart = self.selectionStart;
|
let selectionStart = this.selectionStart;
|
||||||
const selectionEnd = self.selectionEnd;
|
let selectionEnd = this.selectionEnd;
|
||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
if (selection.rangeCount > 0) {
|
if (selection.rangeCount > 0) {
|
||||||
const selectionRange = selection.getRangeAt(0);
|
const selectionRange = selection.getRangeAt(0);
|
||||||
const node = selectionRange.startContainer;
|
let node = selectionRange.startContainer;
|
||||||
if ((contentElt.compareDocumentPosition(node) & window.Node.DOCUMENT_POSITION_CONTAINED_BY) || contentElt === node) {
|
// eslint-disable-next-line no-bitwise
|
||||||
var offset = selectionRange.startOffset
|
if ((contentElt.compareDocumentPosition(node)
|
||||||
|
& window.Node.DOCUMENT_POSITION_CONTAINED_BY)
|
||||||
|
|| contentElt === node
|
||||||
|
) {
|
||||||
|
let offset = selectionRange.startOffset;
|
||||||
if (node.firstChild && offset > 0) {
|
if (node.firstChild && offset > 0) {
|
||||||
node = node.childNodes[offset - 1]
|
node = node.childNodes[offset - 1];
|
||||||
offset = node.textContent.length
|
offset = node.textContent.length;
|
||||||
}
|
}
|
||||||
var container = node
|
let container = node;
|
||||||
while (node !== contentElt) {
|
while (node !== contentElt) {
|
||||||
while ((node = node.previousSibling)) {
|
node = node.previousSibling;
|
||||||
offset += (node.textContent || '').length
|
while (node) {
|
||||||
|
offset += (node.textContent || '').length;
|
||||||
|
node = node.previousSibling;
|
||||||
}
|
}
|
||||||
node = container = container.parentNode
|
node = container.parentNode;
|
||||||
|
container = node;
|
||||||
}
|
}
|
||||||
var selectionText = selectionRange + ''
|
let selectionText = `${selectionRange}`;
|
||||||
// Fix end of line when only br is selected
|
// Fix end of line when only br is selected
|
||||||
var brElt = selectionRange.endContainer.firstChild
|
const brElt = selectionRange.endContainer.firstChild;
|
||||||
if (brElt && brElt.tagName === 'BR' && selectionRange.endOffset === 1) {
|
if (brElt && brElt.tagName === 'BR' && selectionRange.endOffset === 1) {
|
||||||
selectionText += '\n'
|
selectionText += '\n';
|
||||||
}
|
}
|
||||||
if (comparePoints(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset) === 1) {
|
if (comparePoints(
|
||||||
selectionStart = offset + selectionText.length
|
selection.anchorNode,
|
||||||
selectionEnd = offset
|
selection.anchorOffset,
|
||||||
|
selection.focusNode,
|
||||||
|
selection.focusOffset) === 1
|
||||||
|
) {
|
||||||
|
selectionStart = offset + selectionText.length;
|
||||||
|
selectionEnd = offset;
|
||||||
} else {
|
} else {
|
||||||
selectionStart = offset
|
selectionStart = offset;
|
||||||
selectionEnd = offset + selectionText.length
|
selectionEnd = offset + selectionText.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectionStart === selectionEnd && selectionStart === editor.getContent().length) {
|
if (selectionStart === selectionEnd && selectionStart === editor.getContent().length) {
|
||||||
// If cursor is after the trailingNode
|
// If cursor is after the trailingNode
|
||||||
selectionStart = --selectionEnd
|
selectionEnd -= 1;
|
||||||
result = self.setSelectionStartEnd(selectionStart, selectionEnd)
|
selectionStart = selectionEnd;
|
||||||
|
result = this.setSelectionStartEnd(selectionStart, selectionEnd);
|
||||||
} else {
|
} else {
|
||||||
setSelection(selectionStart, selectionEnd)
|
setSelection(selectionStart, selectionEnd);
|
||||||
result = checkSelection(selectionRange)
|
result = checkSelection(selectionRange);
|
||||||
result = result || lastSelectionStart !== self.selectionStart // selectionRange doesn't change when selection is at the start of a section
|
// selectionRange doesn't change when selection is at the start of a section
|
||||||
|
result = result || lastSelectionStart !== this.selectionStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
}
|
};
|
||||||
|
|
||||||
function saveCheckChange() {
|
const saveCheckChange = () => save() && (
|
||||||
return save() && (lastSelectionStart !== self.selectionStart || lastSelectionEnd !== self.selectionEnd)
|
lastSelectionStart !== this.selectionStart || lastSelectionEnd !== this.selectionEnd);
|
||||||
}
|
|
||||||
|
|
||||||
var nextTickAdjustScroll = false
|
let nextTickAdjustScroll = false;
|
||||||
var debouncedSave = debounce(function () {
|
const longerDebouncedSave = debounce(() => {
|
||||||
self.updateCursorCoordinates(saveCheckChange() && nextTickAdjustScroll)
|
this.updateCursorCoordinates(saveCheckChange() && nextTickAdjustScroll);
|
||||||
// In some cases we have to wait a little longer to see the selection change (Cmd+A on Chrome OSX)
|
nextTickAdjustScroll = false;
|
||||||
longerDebouncedSave()
|
}, 10);
|
||||||
})
|
const debouncedSave = debounce(() => {
|
||||||
var longerDebouncedSave = debounce(function () {
|
this.updateCursorCoordinates(saveCheckChange() && nextTickAdjustScroll);
|
||||||
self.updateCursorCoordinates(saveCheckChange() && nextTickAdjustScroll)
|
// In some cases we have to wait a little longer to see the
|
||||||
nextTickAdjustScroll = false
|
// selection change (Cmd+A on Chrome OSX)
|
||||||
}, 10)
|
longerDebouncedSave();
|
||||||
|
});
|
||||||
|
|
||||||
return function (debounced, adjustScroll, forceAdjustScroll) {
|
return (debounced, adjustScrollParam, forceAdjustScroll) => {
|
||||||
if (forceAdjustScroll) {
|
if (forceAdjustScroll) {
|
||||||
lastSelectionStart = undefined
|
lastSelectionStart = undefined;
|
||||||
lastSelectionEnd = undefined
|
lastSelectionEnd = undefined;
|
||||||
}
|
}
|
||||||
if (debounced) {
|
if (debounced) {
|
||||||
nextTickAdjustScroll = nextTickAdjustScroll || adjustScroll
|
nextTickAdjustScroll = nextTickAdjustScroll || adjustScrollParam;
|
||||||
return debouncedSave()
|
debouncedSave();
|
||||||
} else {
|
} else {
|
||||||
save()
|
save();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})()
|
})();
|
||||||
|
|
||||||
this.getSelectedText = function () {
|
this.getSelectedText = () => {
|
||||||
var min = Math.min(this.selectionStart, this.selectionEnd)
|
const min = Math.min(this.selectionStart, this.selectionEnd);
|
||||||
var max = Math.max(this.selectionStart, this.selectionEnd)
|
const max = Math.max(this.selectionStart, this.selectionEnd);
|
||||||
return editor.getContent().substring(min, max)
|
return editor.getContent().substring(min, max);
|
||||||
}
|
};
|
||||||
|
|
||||||
this.getCoordinates = function (inputOffset, container, offsetInContainer) {
|
this.getCoordinates = (inputOffset, containerParam, offsetInContainerParam) => {
|
||||||
|
let container = containerParam;
|
||||||
|
let offsetInContainer = offsetInContainerParam;
|
||||||
if (!container) {
|
if (!container) {
|
||||||
var offset = this.findContainer(inputOffset)
|
const offset = this.findContainer(inputOffset);
|
||||||
container = offset.container
|
container = offset.container;
|
||||||
offsetInContainer = offset.offsetInContainer
|
offsetInContainer = offset.offsetInContainer;
|
||||||
}
|
}
|
||||||
var containerElt = container
|
let containerElt = container;
|
||||||
if (!containerElt.hasChildNodes()) {
|
if (!containerElt.hasChildNodes()) {
|
||||||
containerElt = container.parentNode
|
containerElt = container.parentNode;
|
||||||
}
|
}
|
||||||
var isInvisible = false
|
let isInvisible = false;
|
||||||
var index = editor.$allElements.indexOf(containerElt)
|
while (containerElt.offsetHeight === 0) {
|
||||||
while (containerElt.offsetHeight === 0 && index > 0) {
|
isInvisible = true;
|
||||||
isInvisible = true
|
if (containerElt.previousSibling) {
|
||||||
containerElt = editor.$allElements[--index]
|
containerElt = containerElt.previousSibling;
|
||||||
|
} else {
|
||||||
|
containerElt = containerElt.parentNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var rect
|
let rect;
|
||||||
var contentRect
|
let left = 'left';
|
||||||
var left = 'left'
|
|
||||||
if (isInvisible || container.textContent === '\n') {
|
if (isInvisible || container.textContent === '\n') {
|
||||||
rect = containerElt.getBoundingClientRect()
|
rect = containerElt.getBoundingClientRect();
|
||||||
} else {
|
} else {
|
||||||
var selectedChar = editor.getContent()[inputOffset]
|
const selectedChar = editor.getContent()[inputOffset];
|
||||||
var startOffset = {
|
let startOffset = {
|
||||||
container: container,
|
container,
|
||||||
offsetInContainer: offsetInContainer
|
offsetInContainer,
|
||||||
}
|
};
|
||||||
var endOffset = {
|
let endOffset = {
|
||||||
container: container,
|
container,
|
||||||
offsetInContainer: offsetInContainer
|
offsetInContainer,
|
||||||
}
|
};
|
||||||
if (inputOffset > 0 && (selectedChar === undefined || selectedChar === '\n')) {
|
if (inputOffset > 0 && (selectedChar === undefined || selectedChar === '\n')) {
|
||||||
left = 'right'
|
left = 'right';
|
||||||
if (startOffset.offsetInContainer === 0) {
|
if (startOffset.offsetInContainer === 0) {
|
||||||
// Need to calculate offset-1
|
// Need to calculate offset-1
|
||||||
startOffset = inputOffset - 1
|
startOffset = inputOffset - 1;
|
||||||
} else {
|
} else {
|
||||||
startOffset.offsetInContainer -= 1
|
startOffset.offsetInContainer -= 1;
|
||||||
}
|
}
|
||||||
|
} else if (endOffset.offsetInContainer === container.textContent.length) {
|
||||||
|
// Need to calculate offset+1
|
||||||
|
endOffset = inputOffset + 1;
|
||||||
} else {
|
} else {
|
||||||
if (endOffset.offsetInContainer === container.textContent.length) {
|
endOffset.offsetInContainer += 1;
|
||||||
// Need to calculate offset+1
|
|
||||||
endOffset = inputOffset + 1
|
|
||||||
} else {
|
|
||||||
endOffset.offsetInContainer += 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var range = this.createRange(startOffset, endOffset)
|
const range = this.createRange(startOffset, endOffset);
|
||||||
rect = range.getBoundingClientRect()
|
rect = range.getBoundingClientRect();
|
||||||
}
|
}
|
||||||
contentRect = contentElt.getBoundingClientRect()
|
const contentRect = contentElt.getBoundingClientRect();
|
||||||
return {
|
return {
|
||||||
top: Math.round(rect.top - contentRect.top + contentElt.scrollTop),
|
top: Math.round((rect.top - contentRect.top) + contentElt.scrollTop),
|
||||||
height: Math.round(rect.height),
|
height: Math.round(rect.height),
|
||||||
left: Math.round(rect[left] - contentRect.left + contentElt.scrollLeft)
|
left: Math.round((rect[left] - contentRect.left) + contentElt.scrollLeft),
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
this.getClosestWordOffset = function (offset) {
|
this.getClosestWordOffset = (offset) => {
|
||||||
var offsetStart = 0
|
let offsetStart = 0;
|
||||||
var offsetEnd = 0
|
let offsetEnd = 0;
|
||||||
var nextOffset = 0
|
let nextOffset = 0;
|
||||||
editor.getContent().split(/\s/).cl_some(function (word) {
|
editor.getContent().split(/\s/).cl_some((word) => {
|
||||||
if (word) {
|
if (word) {
|
||||||
offsetStart = nextOffset
|
offsetStart = nextOffset;
|
||||||
offsetEnd = nextOffset + word.length
|
offsetEnd = nextOffset + word.length;
|
||||||
if (offsetEnd > offset) {
|
if (offsetEnd > offset) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nextOffset += word.length + 1
|
nextOffset += word.length + 1;
|
||||||
})
|
return false;
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
start: offsetStart,
|
start: offsetStart,
|
||||||
end: offsetEnd
|
end: offsetEnd,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
cledit.SelectionMgr = SelectionMgr
|
cledit.SelectionMgr = SelectionMgr;
|
||||||
|
@ -1,178 +1,176 @@
|
|||||||
var DiffMatchPatch = require('diff-match-patch');
|
import DiffMatchPatch from 'diff-match-patch';
|
||||||
var cledit = require('./cleditCore')
|
import cledit from './cleditCore';
|
||||||
|
|
||||||
function UndoMgr(editor) {
|
function UndoMgr(editor) {
|
||||||
cledit.Utils.createEventHooks(this)
|
cledit.Utils.createEventHooks(this);
|
||||||
|
|
||||||
/* eslint-disable new-cap */
|
/* eslint-disable new-cap */
|
||||||
var diffMatchPatch = new DiffMatchPatch()
|
const diffMatchPatch = new DiffMatchPatch();
|
||||||
/* eslint-enable new-cap */
|
/* eslint-enable new-cap */
|
||||||
|
|
||||||
var self = this
|
const self = this;
|
||||||
var selectionMgr
|
let selectionMgr;
|
||||||
var undoStack = []
|
const undoStack = [];
|
||||||
var redoStack = []
|
const redoStack = [];
|
||||||
var currentState
|
let currentState;
|
||||||
var previousPatches = []
|
let previousPatches = [];
|
||||||
var currentPatches = []
|
let currentPatches = [];
|
||||||
var debounce = cledit.Utils.debounce
|
const debounce = cledit.Utils.debounce;
|
||||||
|
|
||||||
self.options = {
|
this.options = {
|
||||||
undoStackMaxSize: 200,
|
undoStackMaxSize: 200,
|
||||||
bufferStateUntilIdle: 1000,
|
bufferStateUntilIdle: 1000,
|
||||||
patchHandler: {
|
patchHandler: {
|
||||||
makePatches: function (oldContent, newContent, diffs) {
|
makePatches(oldContent, newContent, diffs) {
|
||||||
return diffMatchPatch.patch_make(oldContent, diffs)
|
return diffMatchPatch.patch_make(oldContent, diffs);
|
||||||
},
|
},
|
||||||
applyPatches: function (patches, content) {
|
applyPatches(patches, content) {
|
||||||
return diffMatchPatch.patch_apply(patches, content)[0]
|
return diffMatchPatch.patch_apply(patches, content)[0];
|
||||||
},
|
},
|
||||||
reversePatches: function (patches) {
|
reversePatches(patches) {
|
||||||
patches = diffMatchPatch.patch_deepCopy(patches).reverse()
|
const reversedPatches = diffMatchPatch.patch_deepCopy(patches).reverse();
|
||||||
patches.cl_each(function (patch) {
|
reversedPatches.cl_each((patch) => {
|
||||||
patch.diffs.cl_each(function (diff) {
|
patch.diffs.cl_each((diff) => {
|
||||||
diff[0] = -diff[0]
|
diff[0] = -diff[0];
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
return patches
|
return reversedPatches;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
function State() { }
|
|
||||||
|
|
||||||
|
let stateMgr;
|
||||||
function StateMgr() {
|
function StateMgr() {
|
||||||
var currentTime, lastTime
|
let currentTime;
|
||||||
var lastMode
|
let lastTime;
|
||||||
|
let lastMode;
|
||||||
|
|
||||||
this.isBufferState = function () {
|
this.isBufferState = () => {
|
||||||
currentTime = Date.now()
|
currentTime = Date.now();
|
||||||
return this.currentMode !== 'single' &&
|
return this.currentMode !== 'single' &&
|
||||||
this.currentMode === lastMode &&
|
this.currentMode === lastMode &&
|
||||||
currentTime - lastTime < self.options.bufferStateUntilIdle
|
currentTime - lastTime < self.options.bufferStateUntilIdle;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.setDefaultMode = function (mode) {
|
this.setDefaultMode = (mode) => {
|
||||||
this.currentMode = this.currentMode || mode
|
this.currentMode = this.currentMode || mode;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.resetMode = function () {
|
this.resetMode = () => {
|
||||||
stateMgr.currentMode = undefined
|
stateMgr.currentMode = undefined;
|
||||||
lastMode = undefined
|
lastMode = undefined;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.saveMode = function () {
|
this.saveMode = () => {
|
||||||
lastMode = this.currentMode
|
lastMode = this.currentMode;
|
||||||
this.currentMode = undefined
|
this.currentMode = undefined;
|
||||||
lastTime = currentTime
|
lastTime = currentTime;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class State {
|
||||||
|
addToUndoStack() {
|
||||||
|
undoStack.push(this);
|
||||||
|
this.patches = previousPatches;
|
||||||
|
previousPatches = [];
|
||||||
|
}
|
||||||
|
addToRedoStack() {
|
||||||
|
redoStack.push(this);
|
||||||
|
this.patches = previousPatches;
|
||||||
|
previousPatches = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToStack(stack) {
|
stateMgr = new StateMgr();
|
||||||
return function () {
|
this.setCurrentMode = (mode) => {
|
||||||
stack.push(this)
|
stateMgr.currentMode = mode;
|
||||||
this.patches = previousPatches
|
};
|
||||||
previousPatches = []
|
this.setDefaultMode = stateMgr.setDefaultMode.cl_bind(stateMgr);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
State.prototype.addToUndoStack = addToStack(undoStack)
|
this.addDiffs = (oldContent, newContent, diffs) => {
|
||||||
State.prototype.addToRedoStack = addToStack(redoStack)
|
const patches = this.options.patchHandler.makePatches(oldContent, newContent, diffs);
|
||||||
|
patches.cl_each(patch => currentPatches.push(patch));
|
||||||
var stateMgr = new StateMgr()
|
};
|
||||||
this.setCurrentMode = function (mode) {
|
|
||||||
stateMgr.currentMode = mode
|
|
||||||
}
|
|
||||||
this.setDefaultMode = stateMgr.setDefaultMode.cl_bind(stateMgr)
|
|
||||||
|
|
||||||
this.addDiffs = function (oldContent, newContent, diffs) {
|
|
||||||
var patches = self.options.patchHandler.makePatches(oldContent, newContent, diffs)
|
|
||||||
currentPatches.push.apply(currentPatches, patches)
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveCurrentPatches() {
|
function saveCurrentPatches() {
|
||||||
// Move currentPatches into previousPatches
|
// Move currentPatches into previousPatches
|
||||||
Array.prototype.push.apply(previousPatches, currentPatches)
|
Array.prototype.push.apply(previousPatches, currentPatches);
|
||||||
currentPatches = []
|
currentPatches = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.saveState = debounce(function () {
|
this.saveState = debounce(() => {
|
||||||
redoStack.length = 0
|
redoStack.length = 0;
|
||||||
if (!stateMgr.isBufferState()) {
|
if (!stateMgr.isBufferState()) {
|
||||||
currentState.addToUndoStack()
|
currentState.addToUndoStack();
|
||||||
|
|
||||||
// Limit the size of the stack
|
// Limit the size of the stack
|
||||||
while (undoStack.length > self.options.undoStackMaxSize) {
|
while (undoStack.length > this.options.undoStackMaxSize) {
|
||||||
undoStack.shift()
|
undoStack.shift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveCurrentPatches()
|
saveCurrentPatches();
|
||||||
currentState = new State()
|
currentState = new State();
|
||||||
stateMgr.saveMode()
|
stateMgr.saveMode();
|
||||||
self.$trigger('undoStateChange')
|
this.$trigger('undoStateChange');
|
||||||
})
|
});
|
||||||
|
|
||||||
this.canUndo = function () {
|
this.canUndo = () => !!undoStack.length;
|
||||||
return !!undoStack.length
|
this.canRedo = () => !!redoStack.length;
|
||||||
}
|
|
||||||
|
|
||||||
this.canRedo = function () {
|
const restoreState = (patchesParam, isForward) => {
|
||||||
return !!redoStack.length
|
let patches = patchesParam;
|
||||||
}
|
|
||||||
|
|
||||||
function restoreState(patches, isForward) {
|
|
||||||
// Update editor
|
// Update editor
|
||||||
var content = editor.getContent()
|
const content = editor.getContent();
|
||||||
if (!isForward) {
|
if (!isForward) {
|
||||||
patches = self.options.patchHandler.reversePatches(patches)
|
patches = this.options.patchHandler.reversePatches(patches);
|
||||||
}
|
}
|
||||||
|
|
||||||
var newContent = self.options.patchHandler.applyPatches(patches, content)
|
const newContent = this.options.patchHandler.applyPatches(patches, content);
|
||||||
var newContentText = newContent.text || newContent
|
const newContentText = newContent.text || newContent;
|
||||||
var range = editor.setContent(newContentText, true)
|
const range = editor.setContent(newContentText, true);
|
||||||
var selection = newContent.selection || {
|
const selection = newContent.selection || {
|
||||||
start: range.end,
|
start: range.end,
|
||||||
end: range.end
|
end: range.end,
|
||||||
}
|
};
|
||||||
|
|
||||||
selectionMgr.setSelectionStartEnd(selection.start, selection.end)
|
selectionMgr.setSelectionStartEnd(selection.start, selection.end);
|
||||||
selectionMgr.updateCursorCoordinates(true)
|
selectionMgr.updateCursorCoordinates(true);
|
||||||
|
|
||||||
stateMgr.resetMode()
|
stateMgr.resetMode();
|
||||||
self.$trigger('undoStateChange')
|
this.$trigger('undoStateChange');
|
||||||
editor.adjustCursorPosition()
|
editor.adjustCursorPosition();
|
||||||
}
|
};
|
||||||
|
|
||||||
this.undo = function () {
|
this.undo = () => {
|
||||||
var state = undoStack.pop()
|
const state = undoStack.pop();
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
saveCurrentPatches()
|
saveCurrentPatches();
|
||||||
currentState.addToRedoStack()
|
currentState.addToRedoStack();
|
||||||
restoreState(currentState.patches)
|
restoreState(currentState.patches);
|
||||||
previousPatches = state.patches
|
previousPatches = state.patches;
|
||||||
currentState = state
|
currentState = state;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.redo = function () {
|
this.redo = () => {
|
||||||
var state = redoStack.pop()
|
const state = redoStack.pop();
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
currentState.addToUndoStack()
|
currentState.addToUndoStack();
|
||||||
restoreState(state.patches, true)
|
restoreState(state.patches, true);
|
||||||
previousPatches = state.patches
|
previousPatches = state.patches;
|
||||||
currentState = state
|
currentState = state;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.init = function (options) {
|
this.init = (options) => {
|
||||||
self.options.cl_extend(options || {})
|
this.options.cl_extend(options || {});
|
||||||
selectionMgr = editor.selectionMgr
|
selectionMgr = editor.selectionMgr;
|
||||||
if (!currentState) {
|
if (!currentState) {
|
||||||
currentState = new State()
|
currentState = new State();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
cledit.UndoMgr = UndoMgr
|
cledit.UndoMgr = UndoMgr;
|
||||||
|
@ -1,123 +1,128 @@
|
|||||||
var cledit = require('./cleditCore')
|
import cledit from './cleditCore';
|
||||||
|
|
||||||
var Utils = {
|
const Utils = {
|
||||||
isGecko: 'MozAppearance' in document.documentElement.style,
|
isGecko: 'MozAppearance' in document.documentElement.style,
|
||||||
isWebkit: 'WebkitAppearance' in document.documentElement.style,
|
isWebkit: 'WebkitAppearance' in document.documentElement.style,
|
||||||
isMsie: 'msTransform' in document.documentElement.style,
|
isMsie: 'msTransform' in document.documentElement.style,
|
||||||
isMac: navigator.userAgent.indexOf('Mac OS X') !== -1
|
isMac: navigator.userAgent.indexOf('Mac OS X') !== -1,
|
||||||
}
|
};
|
||||||
|
|
||||||
// Faster than setTimeout(0). Credit: https://github.com/stefanpenner/es6-promise
|
// Faster than setTimeout(0). Credit: https://github.com/stefanpenner/es6-promise
|
||||||
Utils.defer = (function () {
|
Utils.defer = (() => {
|
||||||
var queue = new Array(1000)
|
const queue = new Array(1000);
|
||||||
var queueLength = 0
|
let queueLength = 0;
|
||||||
function flush() {
|
function flush() {
|
||||||
for (var i = 0; i < queueLength; i++) {
|
for (let i = 0; i < queueLength; i += 1) {
|
||||||
try {
|
try {
|
||||||
queue[i]()
|
queue[i]();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e.message, e.stack)
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(e.message, e.stack);
|
||||||
}
|
}
|
||||||
queue[i] = undefined
|
queue[i] = undefined;
|
||||||
}
|
}
|
||||||
queueLength = 0
|
queueLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var iterations = 0
|
let iterations = 0;
|
||||||
var observer = new window.MutationObserver(flush)
|
const observer = new window.MutationObserver(flush);
|
||||||
var node = document.createTextNode('')
|
const node = document.createTextNode('');
|
||||||
observer.observe(node, { characterData: true })
|
observer.observe(node, { characterData: true });
|
||||||
|
|
||||||
return function (fn) {
|
return (fn) => {
|
||||||
queue[queueLength++] = fn
|
queue[queueLength] = fn;
|
||||||
|
queueLength += 1;
|
||||||
if (queueLength === 1) {
|
if (queueLength === 1) {
|
||||||
node.data = (iterations = ++iterations % 2)
|
iterations = (iterations + 1) % 2;
|
||||||
|
node.data = iterations;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})()
|
})();
|
||||||
|
|
||||||
Utils.debounce = function (func, wait) {
|
Utils.debounce = (func, wait) => {
|
||||||
var timeoutId, isExpected
|
let timeoutId;
|
||||||
|
let isExpected;
|
||||||
return wait
|
return wait
|
||||||
? function () {
|
? () => {
|
||||||
clearTimeout(timeoutId)
|
clearTimeout(timeoutId);
|
||||||
timeoutId = setTimeout(func, wait)
|
timeoutId = setTimeout(func, wait);
|
||||||
}
|
}
|
||||||
: function () {
|
: () => {
|
||||||
if (!isExpected) {
|
if (!isExpected) {
|
||||||
isExpected = true
|
isExpected = true;
|
||||||
Utils.defer(function () {
|
Utils.defer(() => {
|
||||||
isExpected = false
|
isExpected = false;
|
||||||
func()
|
func();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
Utils.createEventHooks = function (object) {
|
Utils.createEventHooks = (object) => {
|
||||||
var listenerMap = Object.create(null)
|
const listenerMap = Object.create(null);
|
||||||
object.$trigger = function (eventType) {
|
object.$trigger = (eventType, ...args) => {
|
||||||
var listeners = listenerMap[eventType]
|
const listeners = listenerMap[eventType];
|
||||||
if (listeners) {
|
if (listeners) {
|
||||||
var args = Array.prototype.slice.call(arguments, 1)
|
listeners.cl_each((listener) => {
|
||||||
listeners.cl_each(function (listener) {
|
|
||||||
try {
|
try {
|
||||||
listener.apply(object, args)
|
listener.apply(object, args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e.message, e.stack)
|
console.error(e.message, e.stack);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
object.on = function (eventType, listener) {
|
object.on = (eventType, listener) => {
|
||||||
var listeners = listenerMap[eventType]
|
let listeners = listenerMap[eventType];
|
||||||
if (!listeners) {
|
if (!listeners) {
|
||||||
listeners = []
|
listeners = [];
|
||||||
listenerMap[eventType] = listeners
|
listenerMap[eventType] = listeners;
|
||||||
}
|
}
|
||||||
listeners.push(listener)
|
listeners.push(listener);
|
||||||
}
|
};
|
||||||
object.off = function (eventType, listener) {
|
object.off = (eventType, listener) => {
|
||||||
var listeners = listenerMap[eventType]
|
const listeners = listenerMap[eventType];
|
||||||
if (listeners) {
|
if (listeners) {
|
||||||
var index = listeners.indexOf(listener)
|
const index = listeners.indexOf(listener);
|
||||||
if (~index) {
|
if (index !== -1) {
|
||||||
listeners.splice(index, 1)
|
listeners.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
Utils.findContainer = function (elt, offset) {
|
Utils.findContainer = (elt, offset) => {
|
||||||
var containerOffset = 0
|
let containerOffset = 0;
|
||||||
var container
|
let container;
|
||||||
|
let child = elt;
|
||||||
do {
|
do {
|
||||||
container = elt
|
container = child;
|
||||||
elt = elt.firstChild
|
child = child.firstChild;
|
||||||
if (elt) {
|
if (child) {
|
||||||
do {
|
do {
|
||||||
var len = elt.textContent.length
|
const len = child.textContent.length;
|
||||||
if (containerOffset <= offset && containerOffset + len > offset) {
|
if (containerOffset <= offset && containerOffset + len > offset) {
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
containerOffset += len
|
containerOffset += len;
|
||||||
} while ((elt = elt.nextSibling))
|
child = child.nextSibling;
|
||||||
|
} while (child);
|
||||||
}
|
}
|
||||||
} while (elt && elt.firstChild && elt.nodeType !== 3)
|
} while (child && child.firstChild && child.nodeType !== 3);
|
||||||
|
|
||||||
if (elt) {
|
if (child) {
|
||||||
return {
|
return {
|
||||||
container: elt,
|
container: child,
|
||||||
offsetInContainer: offset - containerOffset
|
offsetInContainer: offset - containerOffset,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
while (container.lastChild) {
|
while (container.lastChild) {
|
||||||
container = container.lastChild
|
container = container.lastChild;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
container: container,
|
container,
|
||||||
offsetInContainer: container.nodeType === 3 ? container.textContent.length : 0
|
offsetInContainer: container.nodeType === 3 ? container.textContent.length : 0,
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
cledit.Utils = Utils
|
cledit.Utils = Utils;
|
||||||
|
@ -1,33 +1,34 @@
|
|||||||
var cledit = require('./cleditCore')
|
import cledit from './cleditCore';
|
||||||
|
|
||||||
function Watcher(editor, listener) {
|
function Watcher(editor, listener) {
|
||||||
this.isWatching = false
|
this.isWatching = false;
|
||||||
var contentObserver
|
let contentObserver;
|
||||||
this.startWatching = function () {
|
this.startWatching = () => {
|
||||||
this.stopWatching()
|
this.stopWatching();
|
||||||
this.isWatching = true
|
this.isWatching = true;
|
||||||
contentObserver = new window.MutationObserver(listener)
|
contentObserver = new window.MutationObserver(listener);
|
||||||
contentObserver.observe(editor.$contentElt, {
|
contentObserver.observe(editor.$contentElt, {
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true,
|
subtree: true,
|
||||||
characterData: true
|
characterData: true,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
this.stopWatching = function () {
|
this.stopWatching = () => {
|
||||||
if (contentObserver) {
|
if (contentObserver) {
|
||||||
contentObserver.disconnect()
|
contentObserver.disconnect();
|
||||||
contentObserver = undefined
|
contentObserver = undefined;
|
||||||
}
|
}
|
||||||
this.isWatching = false
|
this.isWatching = false;
|
||||||
}
|
};
|
||||||
this.noWatch = function (cb) {
|
this.noWatch = (cb) => {
|
||||||
if (this.isWatching === true) {
|
if (this.isWatching === true) {
|
||||||
this.stopWatching()
|
this.stopWatching();
|
||||||
cb()
|
cb();
|
||||||
return this.startWatching()
|
this.startWatching();
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
}
|
}
|
||||||
cb()
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cledit.Watcher = Watcher
|
cledit.Watcher = Watcher;
|
||||||
|
@ -2,7 +2,7 @@ import Vue from 'vue';
|
|||||||
import DiffMatchPatch from 'diff-match-patch';
|
import DiffMatchPatch from 'diff-match-patch';
|
||||||
import Prism from 'prismjs';
|
import Prism from 'prismjs';
|
||||||
import markdownItPandocRenderer from 'markdown-it-pandoc-renderer';
|
import markdownItPandocRenderer from 'markdown-it-pandoc-renderer';
|
||||||
import cledit from '../libs/cledit';
|
import cledit from './cledit';
|
||||||
import pagedown from '../libs/pagedown';
|
import pagedown from '../libs/pagedown';
|
||||||
import htmlSanitizer from '../libs/htmlSanitizer';
|
import htmlSanitizer from '../libs/htmlSanitizer';
|
||||||
import markdownConversionSvc from './markdownConversionSvc';
|
import markdownConversionSvc from './markdownConversionSvc';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import DiffMatchPatch from 'diff-match-patch';
|
import DiffMatchPatch from 'diff-match-patch';
|
||||||
import cledit from '../libs/cledit';
|
import cledit from './cledit';
|
||||||
import utils from './utils';
|
import utils from './utils';
|
||||||
import diffUtils from './diffUtils';
|
import diffUtils from './diffUtils';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import DiffMatchPatch from 'diff-match-patch';
|
import DiffMatchPatch from 'diff-match-patch';
|
||||||
import cledit from '../libs/cledit';
|
import cledit from './cledit';
|
||||||
import animationSvc from './animationSvc';
|
import animationSvc from './animationSvc';
|
||||||
import store from '../store';
|
import store from '../store';
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import cledit from '../../libs/cledit';
|
import cledit from '../cledit';
|
||||||
import editorSvc from '../editorSvc';
|
import editorSvc from '../editorSvc';
|
||||||
|
|
||||||
const Keystroke = cledit.Keystroke;
|
const Keystroke = cledit.Keystroke;
|
||||||
|
@ -2,7 +2,7 @@ import DiffMatchPatch from 'diff-match-patch';
|
|||||||
import moduleTemplate from './moduleTemplate';
|
import moduleTemplate from './moduleTemplate';
|
||||||
import empty from '../data/emptyContent';
|
import empty from '../data/emptyContent';
|
||||||
import utils from '../services/utils';
|
import utils from '../services/utils';
|
||||||
import cledit from '../libs/cledit';
|
import cledit from '../services/cledit';
|
||||||
|
|
||||||
const diffMatchPatch = new DiffMatchPatch();
|
const diffMatchPatch = new DiffMatchPatch();
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import createLogger from 'vuex/dist/logger';
|
// import createLogger from 'vuex/dist/logger';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
import utils from '../services/utils';
|
import utils from '../services/utils';
|
||||||
@ -120,7 +120,7 @@ const store = new Vuex.Store({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
strict: debug,
|
strict: debug,
|
||||||
plugins: debug ? [createLogger()] : [],
|
// plugins: debug ? [createLogger()] : [],
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user