diff --git a/edit.html b/edit.html
index a0fde99d..5d7d0c00 100644
--- a/edit.html
+++ b/edit.html
@@ -23,11 +23,11 @@
+
-
diff --git a/js/msg.js b/js/msg.js
index 26dba45d..53f17bfa 100644
--- a/js/msg.js
+++ b/js/msg.js
@@ -33,7 +33,8 @@ self.msg = self.INJECTED === 1 ? self.msg : (() => {
onExtension,
off,
RX_NO_RECEIVER,
- RX_PORT_CLOSED
+ RX_PORT_CLOSED,
+ isBg,
};
function getBg() {
diff --git a/js/prefs.js b/js/prefs.js
index bb3ba650..c7fb981c 100644
--- a/js/prefs.js
+++ b/js/prefs.js
@@ -1,6 +1,8 @@
-/* global promisifyChrome */
+/* global promisifyChrome msg API */
'use strict';
+// Needs msg.js loaded first
+
self.prefs = self.INJECTED === 1 ? self.prefs : (() => {
const defaults = {
'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'],
});
- const initializing = browser.storage.sync.get('settings')
- .then(result => {
- if (result.settings) {
- setAll(result.settings, true);
- }
- });
+ const initializing = (
+ msg.isBg
+ ? browser.storage.sync.get('settings').then(res => res.settings)
+ : API.getPrefs()
+ ).then(res => res && setAll(res, true));
chrome.storage.onChanged.addListener((changes, area) => {
if (area !== 'sync' || !changes.settings || !changes.settings.newValue) {
diff --git a/js/script-loader.js b/js/script-loader.js
index ada07824..2517951f 100644
--- a/js/script-loader.js
+++ b/js/script-loader.js
@@ -48,73 +48,3 @@ const loadScript = (() => {
));
};
})();
-
-
-(() => {
- let subscribers, observer;
- // natively declared
-
+
diff --git a/manage/filters.js b/manage/filters.js
index 11e11feb..3d670dfe 100644
--- a/manage/filters.js
+++ b/manage/filters.js
@@ -14,7 +14,7 @@ let initialized = false;
router.watch({search: ['search']}, ([search]) => {
$('#search').value = search || '';
if (!initialized) {
- init();
+ initFilters();
initialized = true;
} else {
searchStyles();
@@ -36,7 +36,7 @@ HTMLSelectElement.prototype.adjustWidth = function () {
parent.replaceChild(this, singleSelect);
};
-function init() {
+function initFilters() {
$('#search').oninput = e => {
router.updateSearch('search', e.target.value);
};
diff --git a/manage/import-export.js b/manage/import-export.js
index 7d08fc89..15261baf 100644
--- a/manage/import-export.js
+++ b/manage/import-export.js
@@ -1,15 +1,11 @@
/* global messageBox styleSectionsEqual API onDOMready
tryJSONparse scrollElementIntoView $ $$ API $create t animateElement
- styleJSONseemsValid */
-/* exported bulkChangeQueue bulkChangeTime */
+ styleJSONseemsValid bulkChangeQueue */
'use strict';
const STYLISH_DUMP_FILE_EXT = '.txt';
const STYLUS_BACKUP_FILE_EXT = '.json';
-let bulkChangeQueue = [];
-let bulkChangeTime = 0;
-
onDOMready().then(() => {
$('#file-all-styles').onclick = () => exportToFile();
$('#unfile-all-styles').onclick = () => importFromFile({fileTypeFilter: STYLUS_BACKUP_FILE_EXT});
@@ -135,7 +131,7 @@ function importFromString(jsonString) {
}
});
bulkChangeQueue.length = 0;
- bulkChangeTime = performance.now();
+ bulkChangeQueue.time = performance.now();
return API.importManyStyles(items.map(i => i.item))
.then(styles => {
for (let i = 0; i < styles.length; i++) {
diff --git a/manage/manage.js b/manage/manage.js
index 1d1d28a1..888da2e8 100644
--- a/manage/manage.js
+++ b/manage/manage.js
@@ -4,11 +4,10 @@ global messageBox getStyleWithNoCode
checkUpdate handleUpdateInstalled
objectDiff
configDialog
- sorter msg prefs API onDOMready $ $$ $create template setupLivePrefs
+ sorter msg prefs API $ $$ $create template setupLivePrefs
t tWordBreak formatDate
getOwnTab getActiveTab openURL animateElement sessionStorageHash debounce
scrollElementIntoView CHROME VIVALDI router
- bulkChangeTime:true bulkChangeQueue
*/
'use strict';
@@ -18,6 +17,8 @@ const ENTRY_ID_PREFIX_RAW = 'style-';
const ENTRY_ID_PREFIX = '#' + ENTRY_ID_PREFIX_RAW;
const BULK_THROTTLE_MS = 100;
+const bulkChangeQueue = [];
+bulkChangeQueue.time = 0;
// define pref-mapped ids separately
const newUI = {
@@ -49,46 +50,10 @@ Promise.all([
API.getAllStyles(true),
// FIXME: integrate this into filter.js
router.getSearch('search') && API.searchDB({query: router.getSearch('search')}),
- Promise.all([
- onDOMready(),
- prefs.initializing,
- ])
- .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');
+ waitForSelector('#installed'), // needed to avoid flicker due to an extra frame and layout shift
+ prefs.initializing
+]).then(([styles, ids, el]) => {
+ installed = el;
installed.onclick = handleEvent.entryClicked;
$('#manage-options-button').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
installed.addEventListener('mouseover', handleEvent.lazyAddEntryTitle);
installed.addEventListener('mouseout', handleEvent.lazyAddEntryTitle);
-
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
setupLivePrefs();
sorter.init();
-
prefs.subscribe(newUI.ids.map(newUI.prefKeyForId), () => switchUI());
-
switchUI({styleOnly: true});
-
// translate CSS manually
document.head.appendChild($create('style', `
.disabled h2::after {
@@ -133,6 +79,39 @@ function initGlobalEvents() {
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) {
@@ -538,7 +517,7 @@ function handleBulkChange() {
const {id} = msg.style;
if (msg.method === 'styleDeleted') {
handleDelete(id);
- bulkChangeTime = performance.now();
+ bulkChangeQueue.time = performance.now();
} else {
handleUpdateForId(id, msg);
}
@@ -549,7 +528,7 @@ function handleBulkChange() {
function handleUpdateForId(id, opts) {
return API.getStyle(id, true).then(style => {
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() {
let options = $('#stylus-embedded-options');
diff --git a/popup.html b/popup.html
index 677edb81..1a39b3a4 100644
--- a/popup.html
+++ b/popup.html
@@ -180,8 +180,8 @@
-
+