extract fitSelectBox()
This commit is contained in:
parent
9ffa754246
commit
df2e8221d2
|
@ -7,6 +7,7 @@ define(require => {
|
||||||
tryRegExp,
|
tryRegExp,
|
||||||
} = require('/js/toolbox');
|
} = require('/js/toolbox');
|
||||||
const {API} = require('/js/msg');
|
const {API} = require('/js/msg');
|
||||||
|
const usercss = require('./usercss-api-helper');
|
||||||
|
|
||||||
// toLocaleLowerCase cache, autocleared after 1 minute
|
// toLocaleLowerCase cache, autocleared after 1 minute
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
|
@ -103,13 +104,13 @@ define(require => {
|
||||||
|
|
||||||
function extractMeta(style) {
|
function extractMeta(style) {
|
||||||
return style.usercssData
|
return style.usercssData
|
||||||
? (style.sourceCode.match(API.usercss.rxMETA) || [''])[0]
|
? (style.sourceCode.match(usercss.rxMETA) || [''])[0]
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stripMeta(style) {
|
function stripMeta(style) {
|
||||||
return style.usercssData
|
return style.usercssData
|
||||||
? style.sourceCode.replace(API.usercss.rxMETA, '')
|
? style.sourceCode.replace(usercss.rxMETA, '')
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,10 +141,6 @@ define(require => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* @type Prefs
|
|
||||||
* @namespace Prefs
|
|
||||||
*/
|
|
||||||
const prefs = {
|
const prefs = {
|
||||||
|
|
||||||
STORAGE_KEY,
|
STORAGE_KEY,
|
||||||
|
|
|
@ -13,7 +13,8 @@ define(require => {
|
||||||
const debounceTimers = new Map();
|
const debounceTimers = new Map();
|
||||||
let URLS, deepCopy, deepEqual, deepMerge;
|
let URLS, deepCopy, deepEqual, deepMerge;
|
||||||
|
|
||||||
const toolbox = {
|
/** @type {Toolbox} */
|
||||||
|
const toolbox = /** @namespace Toolbox */ {
|
||||||
|
|
||||||
CHROME,
|
CHROME,
|
||||||
FIREFOX,
|
FIREFOX,
|
||||||
|
|
|
@ -217,7 +217,7 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="select-resizer">
|
<div class="select-resizer">
|
||||||
<select id="manage.onlyEnabled.invert">
|
<select id="manage.onlyEnabled.invert" class="fit-width">
|
||||||
<option i18n-text="manageOnlyEnabled" value="false"></option>
|
<option i18n-text="manageOnlyEnabled" value="false"></option>
|
||||||
<option i18n-text="manageOnlyDisabled" value="true"></option>
|
<option i18n-text="manageOnlyDisabled" value="true"></option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -235,7 +235,7 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="select-resizer">
|
<div class="select-resizer">
|
||||||
<select id="manage.onlyLocal.invert" i18n-title="manageOnlyLocalTooltip">
|
<select id="manage.onlyLocal.invert" i18n-title="manageOnlyLocalTooltip" class="fit-width">
|
||||||
<option i18n-text="manageOnlyLocal" value="false"></option>
|
<option i18n-text="manageOnlyLocal" value="false"></option>
|
||||||
<option i18n-text="manageOnlyExternal" value="true"></option>
|
<option i18n-text="manageOnlyExternal" value="true"></option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -253,7 +253,7 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<div class="select-resizer">
|
<div class="select-resizer">
|
||||||
<select id="manage.onlyUsercss.invert">
|
<select id="manage.onlyUsercss.invert" class="fit-width">
|
||||||
<option i18n-text="manageOnlyUsercss" value="false"></option>
|
<option i18n-text="manageOnlyUsercss" value="false"></option>
|
||||||
<option i18n-text="manageOnlyNonUsercss" value="true"></option>
|
<option i18n-text="manageOnlyNonUsercss" value="true"></option>
|
||||||
</select>
|
</select>
|
||||||
|
@ -276,7 +276,7 @@
|
||||||
data-filter=":not(.not-matching)"
|
data-filter=":not(.not-matching)"
|
||||||
data-filter-hide=".not-matching">
|
data-filter-hide=".not-matching">
|
||||||
<div class="select-wrapper">
|
<div class="select-wrapper">
|
||||||
<select id="searchMode">
|
<select id="searchMode" class="fit-width">
|
||||||
<option i18n-text="searchStylesName" value="name"></option>
|
<option i18n-text="searchStylesName" value="name"></option>
|
||||||
<option i18n-text="searchStylesMeta" value="meta" selected></option>
|
<option i18n-text="searchStylesMeta" value="meta" selected></option>
|
||||||
<option i18n-text="searchStylesCode" value="code"></option>
|
<option i18n-text="searchStylesCode" value="code"></option>
|
||||||
|
|
|
@ -35,17 +35,6 @@ define(require => {
|
||||||
|
|
||||||
const Events = {
|
const Events = {
|
||||||
|
|
||||||
ENTRY_ROUTES: {
|
|
||||||
'input, .enable, .disable': 'toggle',
|
|
||||||
'.style-name': 'name',
|
|
||||||
'.homepage': 'external',
|
|
||||||
'.check-update': 'check',
|
|
||||||
'.update': 'update',
|
|
||||||
'.delete': 'delete',
|
|
||||||
'.applies-to .expander': 'expandTargets',
|
|
||||||
'.configure-usercss': 'config',
|
|
||||||
},
|
|
||||||
|
|
||||||
addEntryTitle(link) {
|
addEntryTitle(link) {
|
||||||
const style = link.closest('.entry').styleMeta;
|
const style = link.closest('.entry').styleMeta;
|
||||||
const ucd = style.usercssData;
|
const ucd = style.usercssData;
|
||||||
|
@ -130,8 +119,7 @@ define(require => {
|
||||||
for (const selector in Events.ENTRY_ROUTES) {
|
for (const selector in Events.ENTRY_ROUTES) {
|
||||||
for (let el = target; el && el !== entry; el = el.parentElement) {
|
for (let el = target; el && el !== entry; el = el.parentElement) {
|
||||||
if (el.matches(selector)) {
|
if (el.matches(selector)) {
|
||||||
const handler = Events.ENTRY_ROUTES[selector];
|
return Events.ENTRY_ROUTES[selector].call(el, event, entry);
|
||||||
return Events[handler].call(el, event, entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,6 +152,17 @@ define(require => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Events.ENTRY_ROUTES = {
|
||||||
|
'input, .enable, .disable': Events.toggle,
|
||||||
|
'.style-name': Events.name,
|
||||||
|
'.homepage': Events.external,
|
||||||
|
'.check-update': Events.check,
|
||||||
|
'.update': Events.update,
|
||||||
|
'.delete': Events.delete,
|
||||||
|
'.applies-to .expander': Events.expandTargets,
|
||||||
|
'.configure-usercss': Events.config,
|
||||||
|
};
|
||||||
|
|
||||||
async function handleUpdateForId(id, opts) {
|
async function handleUpdateForId(id, opts) {
|
||||||
handleUpdate(await API.styles.get(id), opts);
|
handleUpdate(await API.styles.get(id), opts);
|
||||||
bulkChangeQueue.time = performance.now();
|
bulkChangeQueue.time = performance.now();
|
||||||
|
|
|
@ -62,20 +62,6 @@ define(require => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
HTMLSelectElement.prototype.adjustWidth = function () {
|
|
||||||
const sel = this.selectedOptions[0];
|
|
||||||
if (!sel) return;
|
|
||||||
const wOld = parseFloat(this.style.width);
|
|
||||||
const opts = [...this];
|
|
||||||
opts.forEach(opt => opt !== sel && opt.remove());
|
|
||||||
this.style.width = '';
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
const w = this.offsetWidth;
|
|
||||||
if (w && wOld !== w) this.style.width = w + 'px';
|
|
||||||
this.append(...opts);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function initFilters() {
|
function initFilters() {
|
||||||
$('#search').oninput = $('#searchMode').oninput = function (e) {
|
$('#search').oninput = $('#searchMode').oninput = function (e) {
|
||||||
router.updateSearch(this.id, e.target.value);
|
router.updateSearch(this.id, e.target.value);
|
||||||
|
@ -112,10 +98,6 @@ define(require => {
|
||||||
slaveData.filter = filter;
|
slaveData.filter = filter;
|
||||||
slaveData.filterHide = valueMap.get(!value);
|
slaveData.filterHide = valueMap.get(!value);
|
||||||
debounce(filterOnChange, 0, event);
|
debounce(filterOnChange, 0, event);
|
||||||
// avoid triggering MutationObserver during page load
|
|
||||||
if (document.readyState === 'complete') {
|
|
||||||
el.adjustWidth();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
el.onchange({target: el});
|
el.onchange({target: el});
|
||||||
});
|
});
|
||||||
|
@ -150,14 +132,6 @@ define(require => {
|
||||||
router.updateSearch('search', '');
|
router.updateSearch('search', '');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Adjust width after selects are visible
|
|
||||||
prefs.subscribe('manage.filters.expanded', () => {
|
|
||||||
const el = $('#filters');
|
|
||||||
if (el.open) {
|
|
||||||
$$('.filter-selection select', el).forEach(select => select.adjustWidth());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
filterOnChange({forceRefilter: true});
|
filterOnChange({forceRefilter: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
118
manage/manage.js
118
manage/manage.js
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
define(require => {
|
define(async require => {
|
||||||
const {API, msg} = require('/js/msg');
|
const {API, msg} = require('/js/msg');
|
||||||
const {
|
const {
|
||||||
CHROME,
|
CHROME,
|
||||||
|
@ -21,7 +21,8 @@ define(require => {
|
||||||
const {
|
const {
|
||||||
BULK_THROTTLE_MS,
|
BULK_THROTTLE_MS,
|
||||||
bulkChangeQueue,
|
bulkChangeQueue,
|
||||||
waitingForContainer,
|
containerPromise,
|
||||||
|
fitSelectBoxInOpenDetails,
|
||||||
showStyles,
|
showStyles,
|
||||||
switchUI,
|
switchUI,
|
||||||
} = require('./render');
|
} = require('./render');
|
||||||
|
@ -32,54 +33,56 @@ define(require => {
|
||||||
handleVisibilityChange,
|
handleVisibilityChange,
|
||||||
} = require('./events');
|
} = require('./events');
|
||||||
|
|
||||||
(async () => {
|
|
||||||
const query = router.getSearch('search');
|
|
||||||
const [styles, ids, container] = await Promise.all([
|
|
||||||
API.styles.getAll(),
|
|
||||||
query && API.searchDB({query, mode: router.getSearch('searchMode')}),
|
|
||||||
waitingForContainer,
|
|
||||||
prefs.initializing,
|
|
||||||
]);
|
|
||||||
container.onclick = Events.entryClicked;
|
|
||||||
$('#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));
|
|
||||||
// show date installed & last update on hover
|
|
||||||
container.on('mouseover', Events.lazyAddEntryTitle, {passive: true});
|
|
||||||
container.on('mouseout', Events.lazyAddEntryTitle, {passive: true});
|
|
||||||
document.on('visibilitychange', handleVisibilityChange);
|
|
||||||
// N.B. triggers existing onchange listeners
|
|
||||||
setupLivePrefs();
|
|
||||||
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) {
|
|
||||||
$$('.filter-selection select').forEach(el => el.adjustWidth());
|
|
||||||
}
|
|
||||||
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([
|
|
||||||
'./import-export',
|
|
||||||
'./incremental-search',
|
|
||||||
]);
|
|
||||||
})();
|
|
||||||
|
|
||||||
msg.onExtension(onRuntimeMessage);
|
msg.onExtension(onRuntimeMessage);
|
||||||
router.watch({hash: '#stylus-options'}, state => (state ? embedOptions : unembedOptions)());
|
router.watch({hash: '#stylus-options'}, toggleEmbeddedOptions);
|
||||||
window.on('closeOptions', () => router.updateHash(''));
|
window.on('closeOptions', () => router.updateHash(''));
|
||||||
|
|
||||||
|
const query = router.getSearch('search');
|
||||||
|
const [styles, ids, container] = await Promise.all([
|
||||||
|
API.styles.getAll(),
|
||||||
|
query && API.searchDB({query, mode: router.getSearch('searchMode')}),
|
||||||
|
containerPromise,
|
||||||
|
prefs.initializing,
|
||||||
|
]);
|
||||||
|
|
||||||
|
container.on('click', Events.entryClicked);
|
||||||
|
container.on('mouseover', Events.lazyAddEntryTitle, {passive: true});
|
||||||
|
container.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();
|
||||||
|
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) {
|
||||||
|
fitSelectBoxInOpenDetails($('#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([
|
||||||
|
'./import-export',
|
||||||
|
'./incremental-search',
|
||||||
|
]);
|
||||||
|
|
||||||
function onRuntimeMessage(msg) {
|
function onRuntimeMessage(msg) {
|
||||||
switch (msg.method) {
|
switch (msg.method) {
|
||||||
case 'styleUpdated':
|
case 'styleUpdated':
|
||||||
|
@ -101,21 +104,18 @@ define(require => {
|
||||||
setTimeout(sorter.updateStripes, 0, {onlyWhenColumnsChanged: true});
|
setTimeout(sorter.updateStripes, 0, {onlyWhenColumnsChanged: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
function embedOptions() {
|
async function toggleEmbeddedOptions(state) {
|
||||||
const options = $('#stylus-embedded-options') ||
|
const el = $('#stylus-embedded-options') ||
|
||||||
document.documentElement.appendChild($create('iframe', {
|
state && document.documentElement.appendChild($create('iframe', {
|
||||||
id: 'stylus-embedded-options',
|
id: 'stylus-embedded-options',
|
||||||
src: '/options.html',
|
src: '/options.html',
|
||||||
}));
|
}));
|
||||||
options.focus();
|
if (state) {
|
||||||
}
|
el.focus();
|
||||||
|
} else if (el) {
|
||||||
async function unembedOptions() {
|
el.contentDocument.body.classList.add('scaleout');
|
||||||
const options = $('#stylus-embedded-options');
|
await animateElement(el, 'fadeout');
|
||||||
if (options) {
|
el.remove();
|
||||||
options.contentWindow.document.body.classList.add('scaleout');
|
|
||||||
await animateElement(options, 'fadeout');
|
|
||||||
options.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,7 +36,7 @@ define(require => {
|
||||||
BULK_THROTTLE_MS: 100,
|
BULK_THROTTLE_MS: 100,
|
||||||
bulkChangeQueue: [],
|
bulkChangeQueue: [],
|
||||||
// needed to avoid flicker due to an extra frame and layout shift
|
// needed to avoid flicker due to an extra frame and layout shift
|
||||||
waitingForContainer: waitForSelector('#installed').then(el => (installed = el)),
|
containerPromise: waitForSelector('#installed').then(el => (installed = el)),
|
||||||
|
|
||||||
$entry(styleOrId, root = installed) {
|
$entry(styleOrId, root = installed) {
|
||||||
return $(`#${ENTRY_ID_PREFIX_RAW}${styleOrId.id || styleOrId}`, root);
|
return $(`#${ENTRY_ID_PREFIX_RAW}${styleOrId.id || styleOrId}`, root);
|
||||||
|
@ -184,6 +184,26 @@ define(require => {
|
||||||
entry._numTargets = numTargets;
|
entry._numTargets = numTargets;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLDetailsElement} el
|
||||||
|
* @param {string} targetSel
|
||||||
|
*/
|
||||||
|
fitSelectBoxInOpenDetails(el, targetSel = 'select.fit-width') {
|
||||||
|
const run = () => {
|
||||||
|
if (el.open) {
|
||||||
|
fitSelectBox(...$$(targetSel, el));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
el.on('change', ({target}) => {
|
||||||
|
if (el.open && target.matches(targetSel)) {
|
||||||
|
fitSelectBox(target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
new MutationObserver(run)
|
||||||
|
.observe(el, {attributeFilter: ['open'], attributes: true});
|
||||||
|
run();
|
||||||
|
},
|
||||||
|
|
||||||
getFaviconImgSrc(container = installed) {
|
getFaviconImgSrc(container = installed) {
|
||||||
if (!newUI.enabled || !newUI.favicons) return;
|
if (!newUI.enabled || !newUI.favicons) return;
|
||||||
const regexpRemoveNegativeLookAhead = /(\?!([^)]+\))|\(\?![\w(]+[^)]+[\w|)]+)/g;
|
const regexpRemoveNegativeLookAhead = /(\?!([^)]+\))|\(\?![\w(]+[^)]+[\w|)]+)/g;
|
||||||
|
@ -355,6 +375,26 @@ define(require => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fitSelectBox(...elems) {
|
||||||
|
const data = [];
|
||||||
|
for (const el of elems) {
|
||||||
|
const sel = el.selectedOptions[0];
|
||||||
|
if (!sel) return;
|
||||||
|
const oldWidth = parseFloat(el.style.width);
|
||||||
|
const elOpts = [...el];
|
||||||
|
data.push({el, elOpts, oldWidth});
|
||||||
|
elOpts.forEach(opt => opt !== sel && opt.remove());
|
||||||
|
el.style.width = '';
|
||||||
|
}
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
for (const {el, elOpts, oldWidth} of data) {
|
||||||
|
const w = el.offsetWidth;
|
||||||
|
if (w && oldWidth !== w) el.style.width = w + 'px';
|
||||||
|
el.append(...elOpts);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function highlightEditedStyle() {
|
function highlightEditedStyle() {
|
||||||
if (!sessionStore.justEditedStyleId) return;
|
if (!sessionStore.justEditedStyleId) return;
|
||||||
const entry = render.$entry(sessionStore.justEditedStyleId);
|
const entry = render.$entry(sessionStore.justEditedStyleId);
|
||||||
|
@ -375,6 +415,7 @@ define(require => {
|
||||||
const x = Math.max(0, left);
|
const x = Math.max(0, left);
|
||||||
const y = Math.max(0, top);
|
const y = Math.max(0, top);
|
||||||
const first = document.elementFromPoint(x, y);
|
const first = document.elementFromPoint(x, y);
|
||||||
|
if (!first) return requestAnimationFrame(loadFavicons.bind(null, ...arguments));
|
||||||
const lastOffset = first.offsetTop + window.innerHeight;
|
const lastOffset = first.offsetTop + window.innerHeight;
|
||||||
const numTargets = newUI.targets;
|
const numTargets = newUI.targets;
|
||||||
let entry = first && first.closest('.entry') || installed.children[0];
|
let entry = first && first.closest('.entry') || installed.children[0];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user