createStyleElement speedup: reuse the template

This commit is contained in:
tophf 2017-04-10 11:26:30 +03:00
parent 8bec1d61bd
commit 7084dd1223
3 changed files with 77 additions and 48 deletions

View File

@ -78,6 +78,10 @@ a:hover {
margin-right: 0.1em; margin-right: 0.1em;
} }
.homepage[href=""] {
display: none;
}
.homepage .svg-icon { .homepage .svg-icon {
margin-top: -4px; margin-top: -4px;
margin-left: .5ex; margin-left: .5ex;
@ -319,6 +323,10 @@ summary {
letter-spacing: .1ex; letter-spacing: .1ex;
} }
.newUI .applies-to:not(.has-more) .expander {
display: none;
}
.newUI .has-favicons .applies-to .expander { .newUI .has-favicons .applies-to .expander {
padding-left: 20px; padding-left: 20px;
} }

View File

@ -25,7 +25,10 @@
</svg> </svg>
</a> </a>
</h2> </h2>
<p class="applies-to"><label i18n-text="appliesDisplay"></label></p> <p class="applies-to">
<label i18n-text="appliesDisplay"></label>
<span class="targets"></span>
</p>
<p class="actions"> <p class="actions">
<a class="style-edit-link" href="edit.html?id="> <a class="style-edit-link" href="edit.html?id=">
<button i18n-text="editStyleLabel"></button> <button i18n-text="editStyleLabel"></button>
@ -89,6 +92,7 @@
</p> </p>
<div class="applies-to"> <div class="applies-to">
<div class="targets"></div> <div class="targets"></div>
<span class="expander">...</span>
</div> </div>
</div> </div>
</template> </template>
@ -111,10 +115,6 @@
</details> </details>
</template> </template>
<template data-id="expandAppliesTo">
<span class="expander">...</span>
</template>
<script src="dom.js"></script> <script src="dom.js"></script>
<script src="health.js"></script> <script src="health.js"></script>
<script src="storage.js"></script> <script src="storage.js"></script>

101
manage.js
View File

@ -95,9 +95,8 @@ function showStyles(styles = []) {
.sort((a, b) => (a.name < b.name ? -1 : a.name == b.name ? 0 : 1)); .sort((a, b) => (a.name < b.name ? -1 : a.name == b.name ? 0 : 1));
const shouldRenderAll = (history.state || {}).scrollY > window.innerHeight; const shouldRenderAll = (history.state || {}).scrollY > window.innerHeight;
const renderBin = document.createDocumentFragment(); const renderBin = document.createDocumentFragment();
tDocLoader.stop();
renderStyles(0); renderStyles(0);
// TODO: remember how many styles fit one page to display just that portion first next time
function renderStyles(index) { function renderStyles(index) {
const t0 = performance.now(); const t0 = performance.now();
while (index < sorted.length) { while (index < sorted.length) {
@ -116,40 +115,57 @@ function showStyles(styles = []) {
} else if (shouldRenderAll && 'scrollY' in (history.state || {})) { } else if (shouldRenderAll && 'scrollY' in (history.state || {})) {
setTimeout(() => scrollTo(0, history.state.scrollY)); setTimeout(() => scrollTo(0, history.state.scrollY));
} }
if (newUI.enabled && newUI.favicons) {
debounce(handleEvent.loadFavicons, 16);
}
} }
} }
function createStyleElement({style, name}) { function createStyleElement({style, name}) {
// query the sub-elements just once, then reuse the references
if ((createStyleElement.parts || {}).newUI !== newUI.enabled) {
const entry = template[`style${newUI.enabled ? 'Compact' : ''}`].cloneNode(true); const entry = template[`style${newUI.enabled ? 'Compact' : ''}`].cloneNode(true);
entry.className += ' ' + createStyleElement.parts = {
(style.enabled ? 'enabled' : 'disabled') + newUI: newUI.enabled,
(style.updateUrl ? ' updatable' : ''); entry,
entry.id = 'style-' + style.id; entryClassBase: entry.className,
entry.styleId = style.id; checker: $('.checker', entry),
entry.styleNameLowerCase = name || style.name.toLocaleLowerCase(); nameLink: $('.style-name-link', entry),
editLink: $('.style-edit-link', entry) || {},
const editLink = $('.style-name-link', entry); editHrefBase: $('.style-name-link, .style-edit-link', entry).getAttribute('href'),
editLink.appendChild(document.createTextNode(style.name)); homepage: $('.homepage', entry),
editLink.href = editLink.getAttribute('href') + style.id; appliesTo: $('.applies-to', entry),
targets: $('.targets', entry),
const homepage = $('.homepage', entry); expander: $('.expander', entry),
if (style.url) { decorations: {
homepage.href = homepage.title = style.url;
} else {
homepage.remove();
}
const appliesTo = $('.applies-to', entry);
const decorations = {
urlPrefixesAfter: '*', urlPrefixesAfter: '*',
regexpsBefore: '/', regexpsBefore: '/',
regexpsAfter: '/', regexpsAfter: '/',
},
}; };
const displayed = new Set(); }
let container = newUI.enabled ? $('.targets', appliesTo) : appliesTo; const parts = createStyleElement.parts;
Object.assign(parts.entry, {
className: parts.entryClassBase + ' ' +
(style.enabled ? 'enabled' : 'disabled') +
(style.updateUrl ? ' updatable' : ''),
id: 'style-' + style.id,
styleId: style.id,
styleNameLowerCase: name || style.name.toLocaleLowerCase(),
});
parts.nameLink.textContent = style.name;
parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id;
parts.homepage.href = parts.homepage.title = style.url || '';
// .targets may be a large list so we clone it separately
// and paste into the cloned entry in the end
const targets = parts.targets.cloneNode(true);
let container = targets;
let numTargets = 0; let numTargets = 0;
let numIcons = 0; let numIcons = 0;
const displayed = new Set();
for (const type of TARGET_TYPES) { for (const type of TARGET_TYPES) {
for (const section of style.sections) { for (const section of style.sections) {
for (const targetValue of section[type] || []) { for (const targetValue of section[type] || []) {
@ -160,7 +176,7 @@ function createStyleElement({style, name}) {
const element = template.appliesToTarget.cloneNode(true); const element = template.appliesToTarget.cloneNode(true);
if (!newUI.enabled) { if (!newUI.enabled) {
if (numTargets == 10) { if (numTargets == 10) {
container = appliesTo.appendChild(template.extraAppliesTo.cloneNode(true)); container = container.appendChild(template.extraAppliesTo.cloneNode(true));
} else if (numTargets > 1) { } else if (numTargets > 1) {
container.appendChild(template.appliesToSeparator.cloneNode(true)); container.appendChild(template.appliesToSeparator.cloneNode(true));
} }
@ -181,33 +197,33 @@ function createStyleElement({style, name}) {
} }
element.appendChild( element.appendChild(
document.createTextNode( document.createTextNode(
(decorations[type + 'Before'] || '') + (parts.decorations[type + 'Before'] || '') +
targetValue + targetValue +
(decorations[type + 'After'] || ''))); (parts.decorations[type + 'After'] || '')));
container.appendChild(element); container.appendChild(element);
numTargets++; numTargets++;
} }
} }
} }
if (!numTargets) {
appliesTo.appendChild(template.appliesToEverything.cloneNode(true));
entry.classList.add('global');
}
if (newUI.enabled) { if (newUI.enabled) {
$('.checker', entry).checked = style.enabled; parts.checker.checked = style.enabled;
if (numTargets > newUI.targets) { parts.appliesTo.classList.toggle('has-more', numTargets > newUI.targets);
appliesTo.appendChild(template.expandAppliesTo.cloneNode(true)); // name is supplied by showStyles so we let it decide when to load the icons
} if (numIcons && !name) {
if (numIcons) {
debounce(handleEvent.loadFavicons); debounce(handleEvent.loadFavicons);
} }
} else {
const editLink = $('.style-edit-link', entry);
editLink.href = editLink.getAttribute('href') + style.id;
} }
return entry; const newEntry = parts.entry.cloneNode(true);
const newTargets = $('.targets', newEntry);
if (numTargets) {
newTargets.parentElement.replaceChild(targets, newTargets);
} else {
newTargets.appendChild(template.appliesToEverything.cloneNode(true));
newEntry.classList.add('global');
}
return newEntry;
} }
@ -378,6 +394,11 @@ function switchUI({styleOnly} = {}) {
if (!styleOnly && (stateToggled || missingFavicons)) { if (!styleOnly && (stateToggled || missingFavicons)) {
installed.innerHTML = ''; installed.innerHTML = '';
getStylesSafe().then(showStyles); getStylesSafe().then(showStyles);
} else if (targetsChanged) {
for (const targets of $$('.entry .targets')) {
const hasMore = targets.children.length > newUI.targets;
targets.parentElement.classList.toggle('has-more', hasMore);
}
} }
} }