diff --git a/manage/manage.css b/manage/manage.css index 57b5b730..6a6a2efd 100644 --- a/manage/manage.css +++ b/manage/manage.css @@ -312,6 +312,7 @@ select { .newUI .entry { display: table-row; + contain: strict; } .newUI .entry.odd { @@ -606,6 +607,7 @@ select { box-sizing: border-box; padding-right: 1rem; line-height: 18px; + contain: layout style; } .newUI .applies-to .expander { @@ -644,6 +646,7 @@ select { backface-visibility: hidden; opacity: .25; display: none; + contain: layout style size; } .newUI .has-favicons .target { diff --git a/manage/manage.js b/manage/manage.js index 3595b6c3..3d7e1688 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -139,6 +139,9 @@ function showStyles(styles = []) { renderBin.appendChild(createStyleElement(sorted[index++])); } filterAndAppend({container: renderBin}); + if (newUI.enabled && newUI.favicons) { + debounce(handleEvent.loadFavicons); + } if (index < sorted.length) { requestAnimationFrame(renderStyles); return; @@ -146,9 +149,6 @@ function showStyles(styles = []) { if ('scrollY' in (history.state || {}) && !sessionStorage.justEditedStyleId) { setTimeout(window.scrollTo, 0, 0, history.state.scrollY); } - if (newUI.enabled && newUI.favicons) { - debounce(handleEvent.loadFavicons, 16); - } if (sessionStorage.justEditedStyleId) { const entry = $(ENTRY_ID_PREFIX + sessionStorage.justEditedStyleId); delete sessionStorage.justEditedStyleId; @@ -212,20 +212,17 @@ function createStyleElement({style, name, index}) { $('.actions', entry).appendChild(template.configureIcon.cloneNode(true)); } - // name being supplied signifies we're invoked by showStyles() - // which debounces its main loop thus loading the postponed favicons - createStyleTargetsElement({entry, style, postponeFavicons: name}); + createStyleTargetsElement({entry, style}); return entry; } -function createStyleTargetsElement({entry, style, postponeFavicons}) { +function createStyleTargetsElement({entry, style}) { const parts = createStyleElement.parts; const targets = parts.targets.cloneNode(true); let container = targets; let numTargets = 0; - let numIcons = 0; const displayed = new Set(); for (const type of TARGET_TYPES) { for (const section of style.sections) { @@ -270,9 +267,6 @@ function createStyleTargetsElement({entry, style, postponeFavicons}) { if (numTargets > newUI.targets) { $('.applies-to', entry).classList.add('has-more'); } - if (numIcons && !postponeFavicons) { - debounce(handleEvent.loadFavicons); - } } const entryTargets = $('.targets', entry); if (numTargets) { @@ -395,13 +389,34 @@ Object.assign(handleEvent, { this.closest('.applies-to').classList.toggle('expanded'); }, - loadFavicons(container = document.body) { - for (const img of $$('img', container)) { - if (img.dataset.src) { - img.src = img.dataset.src; - delete img.dataset.src; + loadFavicons({all = false} = {}) { + if (!installed.firstElementChild) return; + let favicons = []; + if (all) { + favicons = $$('img[data-src]', installed); + } else { + const {left, top} = installed.firstElementChild.getBoundingClientRect(); + const x = Math.max(0, left); + const y = Math.max(0, top); + const first = document.elementFromPoint(x, y); + const lastOffset = first.offsetTop + window.innerHeight; + const numTargets = prefs.get('manage.newUI.targets'); + let entry = first && first.closest('.entry') || installed.children[0]; + while (entry && entry.offsetTop <= lastOffset) { + favicons.push(...$$('img', entry).slice(0, numTargets).filter(img => img.dataset.src)); + entry = entry.nextElementSibling; } } + let i = 0; + for (const img of favicons) { + img.src = img.dataset.src; + delete img.dataset.src; + // loading too many icons at once will block the page while the new layout is recalculated + if (++i > 100) break; + } + if ($('img[data-src]', installed)) { + debounce(handleEvent.loadFavicons, 1, {all: true}); + } }, config(event, {styleMeta}) { @@ -549,7 +564,7 @@ function switchUI({styleOnly} = {}) { for (const style of styles) { const entry = $(ENTRY_ID_PREFIX + style.id); if (entry) { - createStyleTargetsElement({entry, style, postponeFavicons: true}); + createStyleTargetsElement({entry, style}); } } debounce(handleEvent.loadFavicons);