Stackedit/src/services/editorSvcUtils.js
2018-03-12 00:45:54 +00:00

154 lines
4.9 KiB
JavaScript

import DiffMatchPatch from 'diff-match-patch';
import cledit from './cledit';
import animationSvc from './animationSvc';
import store from '../store';
const diffMatchPatch = new DiffMatchPatch();
export default {
/**
* Get an object describing the position of the scroll bar in the file.
*/
getScrollPosition(elt = store.getters['layout/styles'].showEditor
? this.editorElt
: this.previewElt,
) {
const dimensionKey = elt === this.editorElt
? 'editorDimension'
: 'previewDimension';
const scrollTop = elt.parentNode.scrollTop;
let result;
if (this.previewCtxMeasured) {
this.previewCtxMeasured.sectionDescList.some((sectionDesc, sectionIdx) => {
if (scrollTop >= sectionDesc[dimensionKey].endOffset) {
return false;
}
const posInSection = (scrollTop - sectionDesc[dimensionKey].startOffset) /
(sectionDesc[dimensionKey].height || 1);
result = {
sectionIdx,
posInSection,
};
return true;
});
}
return result;
},
/**
* Restore the scroll position from the current file content state.
*/
restoreScrollPosition() {
const scrollPosition = store.getters['contentState/current'].scrollPosition;
if (scrollPosition && this.previewCtxMeasured) {
const sectionDesc = this.previewCtxMeasured.sectionDescList[scrollPosition.sectionIdx];
if (sectionDesc) {
const editorScrollTop = sectionDesc.editorDimension.startOffset +
(sectionDesc.editorDimension.height * scrollPosition.posInSection);
this.editorElt.parentNode.scrollTop = Math.floor(editorScrollTop);
const previewScrollTop = sectionDesc.previewDimension.startOffset +
(sectionDesc.previewDimension.height * scrollPosition.posInSection);
this.previewElt.parentNode.scrollTop = Math.floor(previewScrollTop);
}
}
},
/**
* Get the offset in the preview corresponding to the offset of the markdown in the editor
*/
getPreviewOffset(
editorOffset,
sectionDescList = (this.previewCtxWithDiffs || {}).sectionDescList,
) {
if (!sectionDescList) {
return null;
}
let offset = editorOffset;
let previewOffset = 0;
sectionDescList.some((sectionDesc) => {
if (!sectionDesc.textToPreviewDiffs) {
previewOffset = null;
return true;
}
if (sectionDesc.section.text.length >= offset) {
previewOffset += diffMatchPatch.diff_xIndex(sectionDesc.textToPreviewDiffs, offset);
return true;
}
offset -= sectionDesc.section.text.length;
previewOffset += sectionDesc.previewText.length;
return false;
});
return previewOffset;
},
/**
* Get the offset of the markdown in the editor corresponding to the offset in the preview
*/
getEditorOffset(
previewOffset,
sectionDescList = (this.previewCtxWithDiffs || {}).sectionDescList,
) {
if (!sectionDescList) {
return null;
}
let offset = previewOffset;
let editorOffset = 0;
sectionDescList.some((sectionDesc) => {
if (!sectionDesc.textToPreviewDiffs) {
editorOffset = null;
return true;
}
if (sectionDesc.previewText.length >= offset) {
const previewToTextDiffs = sectionDesc.textToPreviewDiffs
.map(diff => [-diff[0], diff[1]]);
editorOffset += diffMatchPatch.diff_xIndex(previewToTextDiffs, offset);
return true;
}
offset -= sectionDesc.previewText.length;
editorOffset += sectionDesc.section.text.length;
return false;
});
return editorOffset;
},
/**
* Get the coordinates of an offset in the preview
*/
getPreviewOffsetCoordinates(offset) {
const start = cledit.Utils.findContainer(this.previewElt, offset && offset - 1);
const end = cledit.Utils.findContainer(this.previewElt, offset || offset + 1);
const range = document.createRange();
range.setStart(start.container, start.offsetInContainer);
range.setEnd(end.container, end.offsetInContainer);
const rect = range.getBoundingClientRect();
const contentRect = this.previewElt.getBoundingClientRect();
return {
top: Math.round((rect.top - contentRect.top) + this.previewElt.scrollTop),
height: Math.round(rect.height),
left: Math.round((rect.right - contentRect.left) + this.previewElt.scrollLeft),
};
},
/**
* Scroll the preview (or the editor if preview is hidden) to the specified anchor
*/
scrollToAnchor(anchor) {
let scrollTop = 0;
const scrollerElt = this.previewElt.parentNode;
const elt = document.getElementById(anchor);
if (elt) {
scrollTop = elt.offsetTop;
}
const maxScrollTop = scrollerElt.scrollHeight - scrollerElt.offsetHeight;
if (scrollTop < 0) {
scrollTop = 0;
} else if (scrollTop > maxScrollTop) {
scrollTop = maxScrollTop;
}
animationSvc.animate(scrollerElt)
.scrollTop(scrollTop)
.duration(360)
.start();
},
};