stylus/manage/manage.js
tophf fdbfb23547
API groups + use executeScript for early injection (#1149)
* parserlib: fast section extraction, tweaks and speedups
* csslint: "simple-not" rule
* csslint: enable and fix "selector-newline" rule
* simplify db: resolve with result
* simplify download()
* remove noCode param as it wastes more time/memory on copying
* styleManager: switch style<->data names to reflect their actual contents
* inline method bodies to avoid indirection and enable better autocomplete/hint/jump support in IDE
* upgrade getEventKeyName to handle mouse clicks
* don't trust location.href as it hides text fragment
* getAllKeys is implemented since Chrome48, FF44
* allow recoverable css errors + async'ify usercss.js
* openManage: unminimize windows
* remove the obsolete Chrome pre-65 workaround
* fix temporal dead zone in apply.js
* ff bug workaround for simple editor window
* consistent window scrolling in scrollToEditor and jumpToPos
* rework waitForSelector and collapsible <details>
* blank paint frame workaround for new Chrome
* extract stuff from edit.js and load on demand
* simplify regexpTester::isShown
* move MozDocMapper to sections-util.js
* extract fitSelectBox()
* initialize router earlier
* use helpPopup.close()
* fix autofocus in popups, follow-up to 5bb1b5ef
* clone objects in prefs.get() + cosmetics
* reuse getAll result for INC
2021-01-01 17:27:58 +03:00

154 lines
4.3 KiB
JavaScript

/* global API msg */// msg.js
/* global CHROME VIVALDI debounce */// toolbox.js
/* global Events handleBulkChange handleVisibilityChange */// events.js
/* global fitSelectBoxesIn switchUI showStyles */// render.js
/* global prefs */
/* global router */
/* global sorter */
/* global t */// localization.js
/* global
$
$$
$create
animateElement
setupLivePrefs
waitForSelector
*/// dom.js
'use strict';
/** @type {HTMLElement} */
let installed;
const changeQueue = [];
changeQueue.THROTTLE = 100; // ms
changeQueue.time = 0;
// define pref-mapped ids separately
const newUI = {
enabled: null, // the global option should come first
favicons: null,
faviconsGray: null,
sliders: null,
targets: null,
};
// ...add utility functions
Object.assign(newUI, {
ids: Object.keys(newUI),
prefKeyForId: id =>
id === 'sliders' ? `ui.${id}` :
id === 'enabled' ? 'manage.newUI' :
`manage.newUI.${id}`,
renderClass: () => {
const cl = document.documentElement.classList;
cl.toggle('newUI', newUI.enabled);
cl.toggle('oldUI', !newUI.enabled);
},
tpl: {
getToggle() {
return t.template[newUI.sliders ? 'toggleSlider' : 'toggleChecker'].cloneNode(true);
},
getEntry() {
const tpl = t.template[newUI.enabled ? 'styleNewUI' : 'style'].cloneNode(true);
if (newUI.enabled) {
const slot = $('toggle', tpl);
slot.parentElement.replaceChild(newUI.tpl.getToggle(), slot);
}
return tpl;
},
},
});
// ...read the actual values
for (const id of newUI.ids) {
newUI[id] = prefs.get(newUI.prefKeyForId(id));
}
newUI.renderClass();
(async function init() {
const query = router.getSearch('search');
const [styles, ids, el] = await Promise.all([
API.styles.getAll(),
query && API.styles.searchDB({query, mode: router.getSearch('searchMode')}),
// needed to avoid flicker due to an extra frame and layout shift
waitForSelector('#installed'),
prefs.ready,
]);
installed = el;
installed.on('click', Events.entryClicked);
installed.on('mouseover', Events.lazyAddEntryTitle, {passive: true});
installed.on('mouseout', Events.lazyAddEntryTitle, {passive: true});
$('#manage-options-button').onclick = () => router.updateHash('#stylus-options');
$('#sync-styles').onclick = () => router.updateHash('#stylus-options');
$$('#header a[href^="http"]').forEach(a => (a.onclick = Events.external));
document.on('visibilitychange', handleVisibilityChange);
setupLivePrefs();
router.update();
prefs.subscribe(newUI.ids.map(newUI.prefKeyForId), () => switchUI());
switchUI({styleOnly: true});
// translate CSS manually
document.styleSheets[0].insertRule(
`:root {${[
'genericDisabledLabel',
'updateAllCheckSucceededSomeEdited',
'filteredStylesAllHidden',
].map(id => `--${id}:"${CSS.escape(t(id))}";`).join('')
}}`);
if (!VIVALDI) {
fitSelectBoxesIn($('#filters'));
}
if (CHROME >= 80 && CHROME <= 88) {
// Wrong checkboxes are randomly checked after going back in history, https://crbug.com/1138598
window.on('pagehide', () => {
$$('input[type=checkbox]').forEach((el, i) => (el.name = `bug${i}`));
});
}
showStyles(styles, ids);
require([
'/manage/import-export',
'/manage/incremental-search',
'/manage/updater-ui',
]);
})();
msg.onExtension(onRuntimeMessage);
window.on('closeOptions', () => router.updateHash(''));
router.watch({hash: '#stylus-options'}, toggleEmbeddedOptions);
function onRuntimeMessage(msg) {
switch (msg.method) {
case 'styleUpdated':
case 'styleAdded':
case 'styleDeleted':
changeQueue.push(msg);
if (performance.now() - (changeQueue.time || 0) < changeQueue.THROTTLE) {
debounce(handleBulkChange, changeQueue.THROTTLE);
} else {
handleBulkChange();
}
break;
case 'styleApply':
case 'styleReplaceAll':
break;
default:
return;
}
setTimeout(sorter.updateStripes, 0, {onlyWhenColumnsChanged: true});
}
async function toggleEmbeddedOptions(state) {
const el = $('#stylus-embedded-options') ||
state && document.documentElement.appendChild($create('iframe', {
id: 'stylus-embedded-options',
src: '/options.html',
}));
if (state) {
el.focus();
} else if (el) {
el.contentDocument.body.classList.add('scaleout');
await animateElement(el, 'fadeout');
el.remove();
}
}