make manager load real fast
This commit is contained in:
parent
bc6c9c826a
commit
d1b9338707
|
@ -23,11 +23,11 @@
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
|
<script src="js/msg.js"></script>
|
||||||
<script src="js/prefs.js"></script>
|
<script src="js/prefs.js"></script>
|
||||||
<script src="js/localization.js"></script>
|
<script src="js/localization.js"></script>
|
||||||
<script src="js/script-loader.js"></script>
|
<script src="js/script-loader.js"></script>
|
||||||
<script src="js/storage-util.js"></script>
|
<script src="js/storage-util.js"></script>
|
||||||
<script src="js/msg.js"></script>
|
|
||||||
|
|
||||||
<script src="content/style-injector.js"></script>
|
<script src="content/style-injector.js"></script>
|
||||||
<script src="content/apply.js"></script>
|
<script src="content/apply.js"></script>
|
||||||
|
|
|
@ -33,7 +33,8 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
|
||||||
onExtension,
|
onExtension,
|
||||||
off,
|
off,
|
||||||
RX_NO_RECEIVER,
|
RX_NO_RECEIVER,
|
||||||
RX_PORT_CLOSED
|
RX_PORT_CLOSED,
|
||||||
|
isBg,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getBg() {
|
function getBg() {
|
||||||
|
|
15
js/prefs.js
15
js/prefs.js
|
@ -1,6 +1,8 @@
|
||||||
/* global promisifyChrome */
|
/* global promisifyChrome msg API */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// Needs msg.js loaded first
|
||||||
|
|
||||||
self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
||||||
const defaults = {
|
const defaults = {
|
||||||
'openEditInWindow': false, // new editor opens in a own browser window
|
'openEditInWindow': false, // new editor opens in a own browser window
|
||||||
|
@ -112,12 +114,11 @@ self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
|
||||||
'storage.sync': ['get', 'set'],
|
'storage.sync': ['get', 'set'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const initializing = browser.storage.sync.get('settings')
|
const initializing = (
|
||||||
.then(result => {
|
msg.isBg
|
||||||
if (result.settings) {
|
? browser.storage.sync.get('settings').then(res => res.settings)
|
||||||
setAll(result.settings, true);
|
: API.getPrefs()
|
||||||
}
|
).then(res => res && setAll(res, true));
|
||||||
});
|
|
||||||
|
|
||||||
chrome.storage.onChanged.addListener((changes, area) => {
|
chrome.storage.onChanged.addListener((changes, area) => {
|
||||||
if (area !== 'sync' || !changes.settings || !changes.settings.newValue) {
|
if (area !== 'sync' || !changes.settings || !changes.settings.newValue) {
|
||||||
|
|
|
@ -48,73 +48,3 @@ const loadScript = (() => {
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
(() => {
|
|
||||||
let subscribers, observer;
|
|
||||||
// natively declared <script> elements in html can't have onload= attribute
|
|
||||||
// due to the default extension CSP that forbids inline code (and we don't want to relax it),
|
|
||||||
// so we're using MutationObserver to add onload event listener to the script element to be loaded
|
|
||||||
window.onDOMscriptReady = (srcSuffix, timeout = 1000) => {
|
|
||||||
if (!subscribers) {
|
|
||||||
subscribers = new Map();
|
|
||||||
observer = new MutationObserver(observe);
|
|
||||||
observer.observe(document.head, {childList: true});
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const listeners = subscribers.get(srcSuffix);
|
|
||||||
if (listeners) {
|
|
||||||
listeners.push(resolve);
|
|
||||||
} else {
|
|
||||||
subscribers.set(srcSuffix, [resolve]);
|
|
||||||
}
|
|
||||||
// a resolved Promise won't reject anymore
|
|
||||||
setTimeout(() => {
|
|
||||||
emptyAfterCleanup(srcSuffix);
|
|
||||||
reject(new Error('Timeout'));
|
|
||||||
}, timeout);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
function observe(mutations) {
|
|
||||||
for (const {addedNodes} of mutations) {
|
|
||||||
for (const n of addedNodes) {
|
|
||||||
if (n.src && getSubscribersForSrc(n.src)) {
|
|
||||||
n.addEventListener('load', notifySubscribers, {once: true});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSubscribersForSrc(src) {
|
|
||||||
for (const [suffix, listeners] of subscribers.entries()) {
|
|
||||||
if (src.endsWith(suffix)) {
|
|
||||||
return {suffix, listeners};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function notifySubscribers(event) {
|
|
||||||
for (let data; (data = getSubscribersForSrc(this.src));) {
|
|
||||||
data.listeners.forEach(fn => fn(event));
|
|
||||||
if (emptyAfterCleanup(data.suffix)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function emptyAfterCleanup(suffix) {
|
|
||||||
if (!subscribers) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
subscribers.delete(suffix);
|
|
||||||
if (!subscribers.size) {
|
|
||||||
observer.disconnect();
|
|
||||||
observer = null;
|
|
||||||
subscribers = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
|
@ -149,8 +149,8 @@
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/prefs.js"></script>
|
|
||||||
<script src="js/msg.js"></script>
|
<script src="js/msg.js"></script>
|
||||||
|
<script src="js/prefs.js"></script>
|
||||||
<script src="js/router.js"></script>
|
<script src="js/router.js"></script>
|
||||||
<script src="content/style-injector.js"></script>
|
<script src="content/style-injector.js"></script>
|
||||||
<script src="content/apply.js"></script>
|
<script src="content/apply.js"></script>
|
||||||
|
|
|
@ -14,7 +14,7 @@ let initialized = false;
|
||||||
router.watch({search: ['search']}, ([search]) => {
|
router.watch({search: ['search']}, ([search]) => {
|
||||||
$('#search').value = search || '';
|
$('#search').value = search || '';
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
init();
|
initFilters();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
} else {
|
} else {
|
||||||
searchStyles();
|
searchStyles();
|
||||||
|
@ -36,7 +36,7 @@ HTMLSelectElement.prototype.adjustWidth = function () {
|
||||||
parent.replaceChild(this, singleSelect);
|
parent.replaceChild(this, singleSelect);
|
||||||
};
|
};
|
||||||
|
|
||||||
function init() {
|
function initFilters() {
|
||||||
$('#search').oninput = e => {
|
$('#search').oninput = e => {
|
||||||
router.updateSearch('search', e.target.value);
|
router.updateSearch('search', e.target.value);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
/* global messageBox styleSectionsEqual API onDOMready
|
/* global messageBox styleSectionsEqual API onDOMready
|
||||||
tryJSONparse scrollElementIntoView $ $$ API $create t animateElement
|
tryJSONparse scrollElementIntoView $ $$ API $create t animateElement
|
||||||
styleJSONseemsValid */
|
styleJSONseemsValid bulkChangeQueue */
|
||||||
/* exported bulkChangeQueue bulkChangeTime */
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const STYLISH_DUMP_FILE_EXT = '.txt';
|
const STYLISH_DUMP_FILE_EXT = '.txt';
|
||||||
const STYLUS_BACKUP_FILE_EXT = '.json';
|
const STYLUS_BACKUP_FILE_EXT = '.json';
|
||||||
|
|
||||||
let bulkChangeQueue = [];
|
|
||||||
let bulkChangeTime = 0;
|
|
||||||
|
|
||||||
onDOMready().then(() => {
|
onDOMready().then(() => {
|
||||||
$('#file-all-styles').onclick = () => exportToFile();
|
$('#file-all-styles').onclick = () => exportToFile();
|
||||||
$('#unfile-all-styles').onclick = () => importFromFile({fileTypeFilter: STYLUS_BACKUP_FILE_EXT});
|
$('#unfile-all-styles').onclick = () => importFromFile({fileTypeFilter: STYLUS_BACKUP_FILE_EXT});
|
||||||
|
@ -135,7 +131,7 @@ function importFromString(jsonString) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bulkChangeQueue.length = 0;
|
bulkChangeQueue.length = 0;
|
||||||
bulkChangeTime = performance.now();
|
bulkChangeQueue.time = performance.now();
|
||||||
return API.importManyStyles(items.map(i => i.item))
|
return API.importManyStyles(items.map(i => i.item))
|
||||||
.then(styles => {
|
.then(styles => {
|
||||||
for (let i = 0; i < styles.length; i++) {
|
for (let i = 0; i < styles.length; i++) {
|
||||||
|
|
119
manage/manage.js
119
manage/manage.js
|
@ -4,11 +4,10 @@ global messageBox getStyleWithNoCode
|
||||||
checkUpdate handleUpdateInstalled
|
checkUpdate handleUpdateInstalled
|
||||||
objectDiff
|
objectDiff
|
||||||
configDialog
|
configDialog
|
||||||
sorter msg prefs API onDOMready $ $$ $create template setupLivePrefs
|
sorter msg prefs API $ $$ $create template setupLivePrefs
|
||||||
t tWordBreak formatDate
|
t tWordBreak formatDate
|
||||||
getOwnTab getActiveTab openURL animateElement sessionStorageHash debounce
|
getOwnTab getActiveTab openURL animateElement sessionStorageHash debounce
|
||||||
scrollElementIntoView CHROME VIVALDI router
|
scrollElementIntoView CHROME VIVALDI router
|
||||||
bulkChangeTime:true bulkChangeQueue
|
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -18,6 +17,8 @@ const ENTRY_ID_PREFIX_RAW = 'style-';
|
||||||
const ENTRY_ID_PREFIX = '#' + ENTRY_ID_PREFIX_RAW;
|
const ENTRY_ID_PREFIX = '#' + ENTRY_ID_PREFIX_RAW;
|
||||||
|
|
||||||
const BULK_THROTTLE_MS = 100;
|
const BULK_THROTTLE_MS = 100;
|
||||||
|
const bulkChangeQueue = [];
|
||||||
|
bulkChangeQueue.time = 0;
|
||||||
|
|
||||||
// define pref-mapped ids separately
|
// define pref-mapped ids separately
|
||||||
const newUI = {
|
const newUI = {
|
||||||
|
@ -49,46 +50,10 @@ Promise.all([
|
||||||
API.getAllStyles(true),
|
API.getAllStyles(true),
|
||||||
// FIXME: integrate this into filter.js
|
// FIXME: integrate this into filter.js
|
||||||
router.getSearch('search') && API.searchDB({query: router.getSearch('search')}),
|
router.getSearch('search') && API.searchDB({query: router.getSearch('search')}),
|
||||||
Promise.all([
|
waitForSelector('#installed'), // needed to avoid flicker due to an extra frame and layout shift
|
||||||
onDOMready(),
|
prefs.initializing
|
||||||
prefs.initializing,
|
]).then(([styles, ids, el]) => {
|
||||||
])
|
installed = el;
|
||||||
.then(() => {
|
|
||||||
initGlobalEvents();
|
|
||||||
if (!VIVALDI) {
|
|
||||||
$$('#header select').forEach(el => el.adjustWidth());
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]).then(args => {
|
|
||||||
showStyles(...args);
|
|
||||||
});
|
|
||||||
|
|
||||||
msg.onExtension(onRuntimeMessage);
|
|
||||||
|
|
||||||
function onRuntimeMessage(msg) {
|
|
||||||
switch (msg.method) {
|
|
||||||
case 'styleUpdated':
|
|
||||||
case 'styleAdded':
|
|
||||||
case 'styleDeleted':
|
|
||||||
bulkChangeQueue.push(msg);
|
|
||||||
if (performance.now() - bulkChangeTime < BULK_THROTTLE_MS) {
|
|
||||||
debounce(handleBulkChange, BULK_THROTTLE_MS);
|
|
||||||
} else {
|
|
||||||
handleBulkChange();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'styleApply':
|
|
||||||
case 'styleReplaceAll':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setTimeout(sorter.updateStripes, 0, {onlyWhenColumnsChanged: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function initGlobalEvents() {
|
|
||||||
installed = $('#installed');
|
|
||||||
installed.onclick = handleEvent.entryClicked;
|
installed.onclick = handleEvent.entryClicked;
|
||||||
$('#manage-options-button').onclick = () => router.updateHash('#stylus-options');
|
$('#manage-options-button').onclick = () => router.updateHash('#stylus-options');
|
||||||
$('#sync-styles').onclick = () => router.updateHash('#stylus-options');
|
$('#sync-styles').onclick = () => router.updateHash('#stylus-options');
|
||||||
|
@ -96,31 +61,12 @@ function initGlobalEvents() {
|
||||||
// show date installed & last update on hover
|
// show date installed & last update on hover
|
||||||
installed.addEventListener('mouseover', handleEvent.lazyAddEntryTitle);
|
installed.addEventListener('mouseover', handleEvent.lazyAddEntryTitle);
|
||||||
installed.addEventListener('mouseout', handleEvent.lazyAddEntryTitle);
|
installed.addEventListener('mouseout', handleEvent.lazyAddEntryTitle);
|
||||||
|
|
||||||
document.addEventListener('visibilitychange', onVisibilityChange);
|
document.addEventListener('visibilitychange', onVisibilityChange);
|
||||||
|
|
||||||
$$('[data-toggle-on-click]').forEach(el => {
|
|
||||||
// dataset on SVG doesn't work in Chrome 49-??, works in 57+
|
|
||||||
const target = $(el.getAttribute('data-toggle-on-click'));
|
|
||||||
el.onclick = event => {
|
|
||||||
event.preventDefault();
|
|
||||||
target.classList.toggle('hidden');
|
|
||||||
if (target.classList.contains('hidden')) {
|
|
||||||
el.removeAttribute('open');
|
|
||||||
} else {
|
|
||||||
el.setAttribute('open', '');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// N.B. triggers existing onchange listeners
|
// N.B. triggers existing onchange listeners
|
||||||
setupLivePrefs();
|
setupLivePrefs();
|
||||||
sorter.init();
|
sorter.init();
|
||||||
|
|
||||||
prefs.subscribe(newUI.ids.map(newUI.prefKeyForId), () => switchUI());
|
prefs.subscribe(newUI.ids.map(newUI.prefKeyForId), () => switchUI());
|
||||||
|
|
||||||
switchUI({styleOnly: true});
|
switchUI({styleOnly: true});
|
||||||
|
|
||||||
// translate CSS manually
|
// translate CSS manually
|
||||||
document.head.appendChild($create('style', `
|
document.head.appendChild($create('style', `
|
||||||
.disabled h2::after {
|
.disabled h2::after {
|
||||||
|
@ -133,6 +79,39 @@ function initGlobalEvents() {
|
||||||
content: "${t('filteredStylesAllHidden')}";
|
content: "${t('filteredStylesAllHidden')}";
|
||||||
}
|
}
|
||||||
`));
|
`));
|
||||||
|
if (!VIVALDI) {
|
||||||
|
$$('#header select').forEach(el => el.adjustWidth());
|
||||||
|
}
|
||||||
|
if (CHROME >= 80 && CHROME <= 88) {
|
||||||
|
// Wrong checkboxes are randomly checked after going back in history, https://crbug.com/1138598
|
||||||
|
addEventListener('pagehide', () => {
|
||||||
|
$$('input[type=checkbox]').forEach((el, i) => (el.name = `bug${i}`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
showStyles(styles, ids);
|
||||||
|
});
|
||||||
|
|
||||||
|
msg.onExtension(onRuntimeMessage);
|
||||||
|
|
||||||
|
function onRuntimeMessage(msg) {
|
||||||
|
switch (msg.method) {
|
||||||
|
case 'styleUpdated':
|
||||||
|
case 'styleAdded':
|
||||||
|
case 'styleDeleted':
|
||||||
|
bulkChangeQueue.push(msg);
|
||||||
|
if (performance.now() - bulkChangeQueue.time < BULK_THROTTLE_MS) {
|
||||||
|
debounce(handleBulkChange, BULK_THROTTLE_MS);
|
||||||
|
} else {
|
||||||
|
handleBulkChange();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'styleApply':
|
||||||
|
case 'styleReplaceAll':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(sorter.updateStripes, 0, {onlyWhenColumnsChanged: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showStyles(styles = [], matchUrlIds) {
|
function showStyles(styles = [], matchUrlIds) {
|
||||||
|
@ -538,7 +517,7 @@ function handleBulkChange() {
|
||||||
const {id} = msg.style;
|
const {id} = msg.style;
|
||||||
if (msg.method === 'styleDeleted') {
|
if (msg.method === 'styleDeleted') {
|
||||||
handleDelete(id);
|
handleDelete(id);
|
||||||
bulkChangeTime = performance.now();
|
bulkChangeQueue.time = performance.now();
|
||||||
} else {
|
} else {
|
||||||
handleUpdateForId(id, msg);
|
handleUpdateForId(id, msg);
|
||||||
}
|
}
|
||||||
|
@ -549,7 +528,7 @@ function handleBulkChange() {
|
||||||
function handleUpdateForId(id, opts) {
|
function handleUpdateForId(id, opts) {
|
||||||
return API.getStyle(id, true).then(style => {
|
return API.getStyle(id, true).then(style => {
|
||||||
handleUpdate(style, opts);
|
handleUpdate(style, opts);
|
||||||
bulkChangeTime = performance.now();
|
bulkChangeQueue.time = performance.now();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,6 +702,20 @@ function highlightEditedStyle() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function waitForSelector(selector) {
|
||||||
|
// TODO: if used in other places, move to dom.js
|
||||||
|
// TODO: if used concurrently, rework to use just one observer internally
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const mo = new MutationObserver(() => {
|
||||||
|
const el = $(selector);
|
||||||
|
if (el) {
|
||||||
|
mo.disconnect();
|
||||||
|
resolve(el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mo.observe(document, {childList: true, subtree: true});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function embedOptions() {
|
function embedOptions() {
|
||||||
let options = $('#stylus-embedded-options');
|
let options = $('#stylus-embedded-options');
|
||||||
|
|
|
@ -180,8 +180,8 @@
|
||||||
<script src="js/dom.js"></script>
|
<script src="js/dom.js"></script>
|
||||||
<script src="js/messaging.js"></script>
|
<script src="js/messaging.js"></script>
|
||||||
<script src="js/localization.js"></script>
|
<script src="js/localization.js"></script>
|
||||||
<script src="js/prefs.js"></script>
|
|
||||||
<script src="js/msg.js"></script>
|
<script src="js/msg.js"></script>
|
||||||
|
<script src="js/prefs.js"></script>
|
||||||
<script src="content/style-injector.js"></script>
|
<script src="content/style-injector.js"></script>
|
||||||
<script src="content/apply.js"></script>
|
<script src="content/apply.js"></script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user