2017-11-10 23:39:51 +00:00
|
|
|
import DiffMatchPatch from 'diff-match-patch';
|
2018-02-17 11:18:30 +00:00
|
|
|
import cledit from './cledit';
|
2017-11-10 23:39:51 +00:00
|
|
|
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.
|
|
|
|
*/
|
2017-12-10 23:49:20 +00:00
|
|
|
getScrollPosition(elt = store.getters['layout/styles'].showEditor
|
|
|
|
? this.editorElt
|
|
|
|
: this.previewElt,
|
|
|
|
) {
|
|
|
|
const dimensionKey = elt === this.editorElt
|
|
|
|
? 'editorDimension'
|
|
|
|
: 'previewDimension';
|
|
|
|
const scrollTop = elt.parentNode.scrollTop;
|
2017-11-10 23:39:51 +00:00
|
|
|
let result;
|
2018-03-12 00:45:54 +00:00
|
|
|
if (this.previewCtxMeasured) {
|
|
|
|
this.previewCtxMeasured.sectionDescList.some((sectionDesc, sectionIdx) => {
|
2017-12-10 23:49:20 +00:00
|
|
|
if (scrollTop >= sectionDesc[dimensionKey].endOffset) {
|
2017-11-10 23:39:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-12-10 23:49:20 +00:00
|
|
|
const posInSection = (scrollTop - sectionDesc[dimensionKey].startOffset) /
|
|
|
|
(sectionDesc[dimensionKey].height || 1);
|
2017-11-10 23:39:51 +00:00
|
|
|
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;
|
2018-03-12 00:45:54 +00:00
|
|
|
if (scrollPosition && this.previewCtxMeasured) {
|
|
|
|
const sectionDesc = this.previewCtxMeasured.sectionDescList[scrollPosition.sectionIdx];
|
2017-11-10 23:39:51 +00:00
|
|
|
if (sectionDesc) {
|
2017-11-26 20:58:24 +00:00
|
|
|
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);
|
2017-11-10 23:39:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the offset in the preview corresponding to the offset of the markdown in the editor
|
|
|
|
*/
|
2018-03-12 00:45:54 +00:00
|
|
|
getPreviewOffset(
|
|
|
|
editorOffset,
|
|
|
|
sectionDescList = (this.previewCtxWithDiffs || {}).sectionDescList,
|
|
|
|
) {
|
2017-11-26 20:58:24 +00:00
|
|
|
if (!sectionDescList) {
|
2017-11-10 23:39:51 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
let offset = editorOffset;
|
|
|
|
let previewOffset = 0;
|
2017-11-26 20:58:24 +00:00
|
|
|
sectionDescList.some((sectionDesc) => {
|
|
|
|
if (!sectionDesc.textToPreviewDiffs) {
|
|
|
|
previewOffset = null;
|
|
|
|
return true;
|
|
|
|
}
|
2017-11-10 23:39:51 +00:00
|
|
|
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
|
|
|
|
*/
|
2018-03-12 00:45:54 +00:00
|
|
|
getEditorOffset(
|
|
|
|
previewOffset,
|
|
|
|
sectionDescList = (this.previewCtxWithDiffs || {}).sectionDescList,
|
|
|
|
) {
|
2017-11-26 20:58:24 +00:00
|
|
|
if (!sectionDescList) {
|
2017-11-10 23:39:51 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
let offset = previewOffset;
|
|
|
|
let editorOffset = 0;
|
2017-11-26 20:58:24 +00:00
|
|
|
sectionDescList.some((sectionDesc) => {
|
|
|
|
if (!sectionDesc.textToPreviewDiffs) {
|
|
|
|
editorOffset = null;
|
|
|
|
return true;
|
|
|
|
}
|
2017-11-10 23:39:51 +00:00
|
|
|
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;
|
|
|
|
},
|
|
|
|
|
2017-11-15 08:12:56 +00:00
|
|
|
/**
|
|
|
|
* 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),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2017-11-10 23:39:51 +00:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
},
|
|
|
|
};
|