make sectioned editor open quickly again

This commit is contained in:
tophf 2020-10-09 23:51:02 +03:00
parent 1027b77899
commit e3378d4b8b
3 changed files with 50 additions and 83 deletions

View File

@ -279,12 +279,6 @@ input:invalid {
.section-editor .section:not(:first-child) { .section-editor .section:not(:first-child) {
border-top: 2px solid hsl(0, 0%, 80%); border-top: 2px solid hsl(0, 0%, 80%);
} }
.section-editor:not(.section-editor-ready) .section {
opacity: 0 !important;
}
.section-editor:not(.section-editor-ready) .CodeMirror {
height: 0;
}
.add-section:after { .add-section:after {
content: attr(short-text); content: attr(short-text);
} }

View File

@ -1,29 +0,0 @@
/* global CodeMirror */
/*
Initialization of the multi-sections editor is slow if there are many editors
e.g. https://github.com/openstyles/stylus/issues/178. So we only refresh the
editor when they were scroll into view.
*/
'use strict';
CodeMirror.defineExtension('refreshOnView', function () {
const cm = this;
if (typeof IntersectionObserver === 'undefined') {
// uh
cm.isRefreshed = true;
cm.refresh();
return;
}
const wrapper = cm.display.wrapper;
const observer = new IntersectionObserver(entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
// wrapper.style.visibility = 'visible';
cm.isRefreshed = true;
cm.refresh();
observer.disconnect();
}
}
});
observer.observe(wrapper);
});

View File

@ -29,6 +29,9 @@ function createSectionsEditor({style, onTitleChanged}) {
updateLivePreview(); updateLivePreview();
}); });
updateHeader();
rerouteHotkeys(true);
$('#to-mozilla').addEventListener('click', showMozillaFormat); $('#to-mozilla').addEventListener('click', showMozillaFormat);
$('#to-mozilla-help').addEventListener('click', showToMozillaHelp); $('#to-mozilla-help').addEventListener('click', showToMozillaHelp);
$('#from-mozilla').addEventListener('click', () => showMozillaFormatImport()); $('#from-mozilla').addEventListener('click', () => showMozillaFormatImport());
@ -47,17 +50,24 @@ function createSectionsEditor({style, onTitleChanged}) {
.forEach(e => e.addEventListener('mousedown', toggleContextMenuDelete)); .forEach(e => e.addEventListener('mousedown', toggleContextMenuDelete));
} }
let sectionOrder = ''; const xo = window.IntersectionObserver && new IntersectionObserver(entries => {
const initializing = new Promise(resolve => initSection({ for (const {isIntersecting, target} of entries) {
sections: style.sections.slice(), if (isIntersecting) {
done:() => { target.CodeMirror.refresh();
dirty.clear(); xo.unobserve(target);
rerouteHotkeys(true);
resolve();
updateHeader();
sections.forEach(fitToContent);
} }
})); }
});
CodeMirror.defineExtension('refreshOnView', function () {
if (xo) {
xo.observe(this.display.wrapper);
} else {
this.refresh();
}
});
let sectionOrder = '';
const initializing = initSections(style.sections.slice());
const livePreview = createLivePreview(); const livePreview = createLivePreview();
livePreview.show(Boolean(style.id)); livePreview.show(Boolean(style.id));
@ -83,28 +93,22 @@ function createSectionsEditor({style, onTitleChanged}) {
}; };
function fitToContent(section) { function fitToContent(section) {
if (section.cm.isRefreshed) { if (section.cm.display.renderedView) {
resize(); resize();
} else { } else {
section.cm.on('update', resize); section.cm.on('update', resize);
} }
function resize() { function resize() {
let contentHeight = section.el.querySelector('.CodeMirror-sizer').offsetHeight; let contentHeight = section.cm.display.sizer.offsetHeight;
if (contentHeight < section.cm.defaultTextHeight()) { if (contentHeight < section.cm.defaultTextHeight()) {
return; return;
} }
contentHeight += 9; // border & resize grip contentHeight += 9; // border & resize grip
section.cm.off('update', resize); section.cm.off('update', resize);
const cmHeight = section.cm.getWrapperElement().offsetHeight; const cmHeight = section.cm.display.wrapper.offsetHeight;
const maxHeight = cmHeight + window.innerHeight - section.el.offsetHeight; const maxHeight = window.innerHeight - (section.el.offsetHeight - cmHeight);
section.cm.setSize(null, Math.min(contentHeight, maxHeight)); section.cm.setSize(null, Math.min(contentHeight, maxHeight));
if (sections.every(s => s.cm.isRefreshed)) {
fitToAvailableSpace();
}
setTimeout(() => {
container.classList.add('section-editor-ready');
}, 50);
} }
} }
@ -367,7 +371,7 @@ function createSectionsEditor({style, onTitleChanged}) {
if (replaceOldStyle) { if (replaceOldStyle) {
return replaceSections(sections); return replaceSections(sections);
} }
return new Promise(resolve => initSection({sections, done: resolve, focusOn: false})); return initSections(sections, {focusOn: false});
}) })
.then(() => { .then(() => {
$('.dismiss').dispatchEvent(new Event('click')); $('.dismiss').dispatchEvent(new Event('click'));
@ -472,38 +476,35 @@ function createSectionsEditor({style, onTitleChanged}) {
livePreview.update(getModel()); livePreview.update(getModel());
} }
function initSection({ function initSections(originalSections, {
sections: originalSections,
total = originalSections.length, total = originalSections.length,
focusOn = 0, focusOn = 0,
done } = {}) {
}) { let done;
container.classList.add('hidden'); return new Promise(resolve => {
chunk(); done = resolve;
chunk(true);
function chunk() { });
if (!originalSections.length) { function chunk(forceRefresh) {
setGlobalProgress();
if (focusOn !== false) {
setTimeout(() => sections[focusOn].cm.focus());
}
container.classList.remove('hidden');
for (const section of sections) {
section.cm.refreshOnView();
}
if (done) {
done();
}
return;
}
const t0 = performance.now(); const t0 = performance.now();
while (originalSections.length && performance.now() - t0 < 100) { while (originalSections.length && performance.now() - t0 < 100) {
insertSectionAfter(originalSections.shift()); insertSectionAfter(originalSections.shift(), undefined, forceRefresh);
dirty.clear();
if (focusOn !== false && sections[focusOn]) {
sections[focusOn].cm.focus();
focusOn = false;
}
} }
setGlobalProgress(total - originalSections.length, total); setGlobalProgress(total - originalSections.length, total);
if (!originalSections.length) {
setGlobalProgress();
fitToAvailableSpace();
done();
} else {
setTimeout(chunk); setTimeout(chunk);
} }
} }
}
function removeSection(section) { function removeSection(section) {
if (sections.every(s => s.isRemoved() || s === section)) { if (sections.every(s => s.isRemoved() || s === section)) {
@ -540,7 +541,7 @@ function createSectionsEditor({style, onTitleChanged}) {
updateLivePreview(); updateLivePreview();
} }
function insertSectionAfter(init, base) { function insertSectionAfter(init, base, forceRefresh) {
if (!init) { if (!init) {
init = {code: '', urlPrefixes: ['http://example.com']}; init = {code: '', urlPrefixes: ['http://example.com']};
} }
@ -565,7 +566,8 @@ function createSectionsEditor({style, onTitleChanged}) {
sections.push(section); sections.push(section);
container.appendChild(section.el); container.appendChild(section.el);
} }
section.render(); section.cm[forceRefresh ? 'refresh' : 'refreshOnView']();
fitToContent(section);
updateSectionOrder(); updateSectionOrder();
section.onChange(updateLivePreview); section.onChange(updateLivePreview);
updateLivePreview(); updateLivePreview();
@ -599,7 +601,7 @@ function createSectionsEditor({style, onTitleChanged}) {
} }
sections.length = 0; sections.length = 0;
container.textContent = ''; container.textContent = '';
return new Promise(resolve => initSection({sections: originalSections, done: resolve})); return initSections(originalSections);
} }
function replaceStyle(newStyle, codeIsUpdated) { function replaceStyle(newStyle, codeIsUpdated) {