keep scroll position and selections in tab's session
This commit is contained in:
parent
1d226aac8b
commit
3905722cdf
19
edit/edit.js
19
edit/edit.js
|
@ -56,13 +56,23 @@ lazyInit();
|
||||||
.then(initTheme),
|
.then(initTheme),
|
||||||
onDOMready(),
|
onDOMready(),
|
||||||
]);
|
]);
|
||||||
|
const scrollInfo = style.id && tryJSONparse(sessionStore['editorScrollInfo' + style.id]);
|
||||||
/** @namespace EditorBase */
|
/** @namespace EditorBase */
|
||||||
Object.assign(editor, {
|
Object.assign(editor, {
|
||||||
style,
|
style,
|
||||||
dirty,
|
dirty,
|
||||||
|
scrollInfo,
|
||||||
updateName,
|
updateName,
|
||||||
updateToc,
|
updateToc,
|
||||||
toggleStyle,
|
toggleStyle,
|
||||||
|
applyScrollInfo(cm, si = ((scrollInfo || {}).cms || [])[0]) {
|
||||||
|
if (si && si.sel) {
|
||||||
|
cm.operation(() => {
|
||||||
|
cm.setSelections(...si.sel, {scroll: false});
|
||||||
|
cm.scrollIntoView(cm.getCursor(), si.parentHeight / 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
prefs.subscribe('editor.linter', updateLinter);
|
prefs.subscribe('editor.linter', updateLinter);
|
||||||
prefs.subscribe('editor.keyMap', showHotkeyInTooltip);
|
prefs.subscribe('editor.keyMap', showHotkeyInTooltip);
|
||||||
|
@ -410,6 +420,15 @@ function onRuntimeMessage(request) {
|
||||||
|
|
||||||
function beforeUnload(e) {
|
function beforeUnload(e) {
|
||||||
sessionStore.windowPos = JSON.stringify(canSaveWindowPos() && prefs.get('windowPosition'));
|
sessionStore.windowPos = JSON.stringify(canSaveWindowPos() && prefs.get('windowPosition'));
|
||||||
|
sessionStore['editorScrollInfo' + editor.style.id] = JSON.stringify({
|
||||||
|
scrollY: window.scrollY,
|
||||||
|
cms: editor.getEditors().map(cm => /** @namespace EditorScrollInfo */({
|
||||||
|
focus: cm.hasFocus(),
|
||||||
|
height: cm.display.wrapper.style.height.replace('100vh', ''),
|
||||||
|
parentHeight: cm.display.wrapper.parentElement.offsetHeight,
|
||||||
|
sel: cm.isClean() && [cm.doc.sel.ranges, cm.doc.sel.primIndex],
|
||||||
|
})),
|
||||||
|
});
|
||||||
const activeElement = document.activeElement;
|
const activeElement = document.activeElement;
|
||||||
if (activeElement) {
|
if (activeElement) {
|
||||||
// blurring triggers 'change' or 'input' event if needed
|
// blurring triggers 'change' or 'input' event if needed
|
||||||
|
|
|
@ -17,20 +17,26 @@
|
||||||
|
|
||||||
/* exported createSection */
|
/* exported createSection */
|
||||||
|
|
||||||
/** @returns {EditorSection} */
|
/**
|
||||||
function createSection(originalSection, genId) {
|
* @param {StyleSection} originalSection
|
||||||
|
* @param {function():number} genId
|
||||||
|
* @param {EditorScrollInfo} [si]
|
||||||
|
* @returns {EditorSection}
|
||||||
|
*/
|
||||||
|
function createSection(originalSection, genId, si) {
|
||||||
const {dirty} = editor;
|
const {dirty} = editor;
|
||||||
const sectionId = genId();
|
const sectionId = genId();
|
||||||
const el = template.section.cloneNode(true);
|
const el = template.section.cloneNode(true);
|
||||||
const elLabel = $('.code-label', el);
|
const elLabel = $('.code-label', el);
|
||||||
const cm = cmFactory.create(wrapper => {
|
const cm = cmFactory.create(wrapper => {
|
||||||
// making it tall during initial load so IntersectionObserver sees only one adjacent CM
|
// making it tall during initial load so IntersectionObserver sees only one adjacent CM
|
||||||
wrapper.style.height = '100vh';
|
wrapper.style.height = si ? si.height : '100vh';
|
||||||
elLabel.after(wrapper);
|
elLabel.after(wrapper);
|
||||||
}, {
|
}, {
|
||||||
value: originalSection.code,
|
value: originalSection.code,
|
||||||
});
|
});
|
||||||
el.CodeMirror = cm; // used by getAssociatedEditor
|
el.CodeMirror = cm; // used by getAssociatedEditor
|
||||||
|
editor.applyScrollInfo(cm, si);
|
||||||
|
|
||||||
const changeListeners = new Set();
|
const changeListeners = new Set();
|
||||||
|
|
||||||
|
|
|
@ -486,7 +486,7 @@ function SectionsEditor() {
|
||||||
livePreview.update(getModel());
|
livePreview.update(getModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSections(originalSections, {
|
function initSections(src, {
|
||||||
focusOn = 0,
|
focusOn = 0,
|
||||||
replace = false,
|
replace = false,
|
||||||
pristine = false,
|
pristine = false,
|
||||||
|
@ -497,26 +497,35 @@ function SectionsEditor() {
|
||||||
container.textContent = '';
|
container.textContent = '';
|
||||||
}
|
}
|
||||||
let done;
|
let done;
|
||||||
const total = originalSections.length;
|
let index = 0;
|
||||||
originalSections = originalSections.slice();
|
let y = 0;
|
||||||
|
const total = src.length;
|
||||||
|
let si = editor.scrollInfo;
|
||||||
|
if (si && si.cms && si.cms.length === src.length) {
|
||||||
|
si.scrollY2 = si.scrollY + window.innerHeight;
|
||||||
|
container.style.height = si.scrollY2 + 'px';
|
||||||
|
scrollTo(0, si.scrollY);
|
||||||
|
} else {
|
||||||
|
si = null;
|
||||||
|
}
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
done = resolve;
|
done = resolve;
|
||||||
chunk(true);
|
chunk(!si);
|
||||||
});
|
});
|
||||||
function chunk(forceRefresh) {
|
function chunk(forceRefresh) {
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
while (originalSections.length && performance.now() - t0 < 100) {
|
while (index < total && performance.now() - t0 < 100) {
|
||||||
insertSectionAfter(originalSections.shift(), undefined, forceRefresh);
|
if (si) forceRefresh = y < si.scrollY2 && (y += si.cms[index].parentHeight) > si.scrollY;
|
||||||
|
insertSectionAfter(src[index], undefined, forceRefresh, si && si.cms[index]);
|
||||||
if (pristine) dirty.clear();
|
if (pristine) dirty.clear();
|
||||||
if (focusOn !== false && sections[focusOn]) {
|
if (index === focusOn && !si) sections[index].cm.focus();
|
||||||
sections[focusOn].cm.focus();
|
index++;
|
||||||
focusOn = false;
|
|
||||||
}
|
}
|
||||||
}
|
setGlobalProgress(index, total);
|
||||||
setGlobalProgress(total - originalSections.length, total);
|
if (index === total) {
|
||||||
if (!originalSections.length) {
|
|
||||||
setGlobalProgress();
|
setGlobalProgress();
|
||||||
requestAnimationFrame(fitToAvailableSpace);
|
if (!si) requestAnimationFrame(fitToAvailableSpace);
|
||||||
|
container.style.removeProperty('height');
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
setTimeout(chunk);
|
setTimeout(chunk);
|
||||||
|
@ -565,18 +574,19 @@ function SectionsEditor() {
|
||||||
* @param {StyleSection} [init]
|
* @param {StyleSection} [init]
|
||||||
* @param {EditorSection} [base]
|
* @param {EditorSection} [base]
|
||||||
* @param {boolean} [forceRefresh]
|
* @param {boolean} [forceRefresh]
|
||||||
|
* @param {EditorScrollInfo} [si]
|
||||||
*/
|
*/
|
||||||
function insertSectionAfter(init, base, forceRefresh) {
|
function insertSectionAfter(init, base, forceRefresh, si) {
|
||||||
if (!init) {
|
if (!init) {
|
||||||
init = {code: '', urlPrefixes: ['http://example.com']};
|
init = {code: '', urlPrefixes: ['http://example.com']};
|
||||||
}
|
}
|
||||||
const section = createSection(init, genId);
|
const section = createSection(init, genId, si);
|
||||||
const {cm} = section;
|
const {cm} = section;
|
||||||
sections.splice(base ? sections.indexOf(base) + 1 : sections.length, 0, section);
|
sections.splice(base ? sections.indexOf(base) + 1 : sections.length, 0, section);
|
||||||
container.insertBefore(section.el, base ? base.el.nextSibling : null);
|
container.insertBefore(section.el, base ? base.el.nextSibling : null);
|
||||||
refreshOnView(cm, forceRefresh);
|
refreshOnView(cm, forceRefresh);
|
||||||
registerEvents(section);
|
registerEvents(section);
|
||||||
if (!base || init.code) {
|
if ((!si || !si.height) && (!base || init.code)) {
|
||||||
// Fit a) during startup or b) when the clone button is clicked on a section with some code
|
// Fit a) during startup or b) when the clone button is clicked on a section with some code
|
||||||
fitToContent(section);
|
fitToContent(section);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ function SourceEditor() {
|
||||||
'editor.appliesToLineWidget': (k, val) => sectionWidget.toggle(val),
|
'editor.appliesToLineWidget': (k, val) => sectionWidget.toggle(val),
|
||||||
'editor.toc.expanded': (k, val) => sectionFinder.onOff(editor.updateToc, val),
|
'editor.toc.expanded': (k, val) => sectionFinder.onOff(editor.updateToc, val),
|
||||||
}, {now: true});
|
}, {now: true});
|
||||||
|
editor.applyScrollInfo(cm);
|
||||||
cm.clearHistory();
|
cm.clearHistory();
|
||||||
cm.markClean();
|
cm.markClean();
|
||||||
savedGeneration = cm.changeGeneration();
|
savedGeneration = cm.changeGeneration();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user