add scope selector to style search in manager
This commit is contained in:
parent
a1acf53539
commit
8b98baba6a
|
@ -1285,14 +1285,30 @@
|
||||||
"message": "Weekly installs",
|
"message": "Weekly installs",
|
||||||
"description": "Text for label that shows the number of times a search result was installed during last week"
|
"description": "Text for label that shows the number of times a search result was installed during last week"
|
||||||
},
|
},
|
||||||
"searchStyles": {
|
"searchStylesAll": {
|
||||||
"message": "Search contents",
|
"message": "All",
|
||||||
"description": "Label for the search filter textbox on the Manage styles page"
|
"description": "Option for `find styles` scope selector in the manager."
|
||||||
|
},
|
||||||
|
"searchStylesCode": {
|
||||||
|
"message": "CSS code",
|
||||||
|
"description": "Option for `find styles` scope selector in the manager."
|
||||||
},
|
},
|
||||||
"searchStylesHelp": {
|
"searchStylesHelp": {
|
||||||
"message": "</> key focuses the search field.\nPlain text: search within the name, code, homepage URL and sites it is applied to. Words with less than 3 letters are ignored.\nStyles matching a full URL: prefix the search with <url:>, e.g. <url:https://github.com/openstyles/stylus>\nRegular expressions: include slashes and flags, e.g. </body.*?\\ba\\b/simguy>\nExact words: wrap the query in double quotes, e.g. <\".header ~ div\">",
|
"message": "</> or <Ctrl-F> key focuses the search field.\nDefault mode is plain text search for all space-separated terms in any order.\nExact words: wrap the query in double quotes, e.g. <\".header ~ div\">\nRegular expressions: include slashes and flags, e.g. </body.*?\\ba\\b/i>\n\"For URL\" in scope selector: finds styles that apply to a fully specified URL e.g. https://www.example.org/\n\"Metadata\" in scope selector: searches in names, \"applies to\" specifiers, installation URL, update URL, and the entire metadata block for usercss styles.",
|
||||||
"description": "Text in the minihelp displayed when clicking (i) icon to the right of the search input field on the Manage styles page"
|
"description": "Text in the minihelp displayed when clicking (i) icon to the right of the search input field on the Manage styles page"
|
||||||
},
|
},
|
||||||
|
"searchStylesMatchUrl": {
|
||||||
|
"message": "For URL",
|
||||||
|
"description": "Option for `find styles` scope selector in the manager. See searchMatchUrlHint for more info."
|
||||||
|
},
|
||||||
|
"searchStylesMeta": {
|
||||||
|
"message": "Metadata",
|
||||||
|
"description": "Option for `find styles` scope selector in the manager."
|
||||||
|
},
|
||||||
|
"searchStylesName": {
|
||||||
|
"message": "Name",
|
||||||
|
"description": "Option for `find styles` scope selector in the manager."
|
||||||
|
},
|
||||||
"sectionAdd": {
|
"sectionAdd": {
|
||||||
"message": "Add another section",
|
"message": "Add another section",
|
||||||
"description": "Label for the button to add a section"
|
"description": "Label for the button to add a section"
|
||||||
|
|
|
@ -309,33 +309,29 @@ function openEditor(params) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function openManage({options = false, search} = {}) {
|
async function openManage({options = false, search, searchMode} = {}) {
|
||||||
let url = chrome.runtime.getURL('manage.html');
|
let url = chrome.runtime.getURL('manage.html');
|
||||||
if (search) {
|
if (search) {
|
||||||
url += `?search=${encodeURIComponent(search)}`;
|
url += `?search=${encodeURIComponent(search)}&searchMode=${searchMode}`;
|
||||||
}
|
}
|
||||||
if (options) {
|
if (options) {
|
||||||
url += '#stylus-options';
|
url += '#stylus-options';
|
||||||
}
|
}
|
||||||
return findExistingTab({
|
let tab = await findExistingTab({
|
||||||
url,
|
url,
|
||||||
currentWindow: null,
|
currentWindow: null,
|
||||||
ignoreHash: true,
|
ignoreHash: true,
|
||||||
ignoreSearch: true,
|
ignoreSearch: true,
|
||||||
})
|
});
|
||||||
.then(tab => {
|
if (tab) {
|
||||||
if (tab) {
|
await activateTab(tab);
|
||||||
return Promise.all([
|
if (url !== (tab.pendingUrl || tab.url)) {
|
||||||
activateTab(tab),
|
await msg.sendTab(tab.id, {method: 'pushState', url}).catch(console.error);
|
||||||
(tab.pendingUrl || tab.url) !== url && msg.sendTab(tab.id, {method: 'pushState', url})
|
}
|
||||||
.catch(console.error),
|
return tab;
|
||||||
]);
|
}
|
||||||
}
|
tab = await getActiveTab();
|
||||||
return getActiveTab().then(tab => {
|
return isTabReplaceable(tab, url)
|
||||||
if (isTabReplaceable(tab, url)) {
|
? activateTab(tab, {url})
|
||||||
return activateTab(tab, {url});
|
: browser.tabs.create({url});
|
||||||
}
|
|
||||||
return browser.tabs.create({url});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +1,97 @@
|
||||||
/* global API_METHODS styleManager tryRegExp debounce */
|
/* global
|
||||||
|
API_METHODS
|
||||||
|
debounce
|
||||||
|
stringAsRegExp
|
||||||
|
styleManager
|
||||||
|
tryRegExp
|
||||||
|
usercss
|
||||||
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
// toLocaleLowerCase cache, autocleared after 1 minute
|
// toLocaleLowerCase cache, autocleared after 1 minute
|
||||||
const cache = new Map();
|
const cache = new Map();
|
||||||
// top-level style properties to be searched
|
const METAKEYS = ['customName', 'name', 'url', 'installationUrl', 'updateUrl'];
|
||||||
const PARTS = {
|
|
||||||
name: searchText,
|
const extractMeta = style =>
|
||||||
url: searchText,
|
style.usercssData
|
||||||
sourceCode: searchText,
|
? (style.sourceCode.match(usercss.RX_META) || [''])[0]
|
||||||
sections: searchSections,
|
: null;
|
||||||
};
|
|
||||||
|
const stripMeta = style =>
|
||||||
|
style.usercssData
|
||||||
|
? style.sourceCode.replace(usercss.RX_META, '')
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const MODES = Object.assign(Object.create(null), {
|
||||||
|
code: (style, test) =>
|
||||||
|
style.usercssData
|
||||||
|
? test(stripMeta(style))
|
||||||
|
: searchSections(style, test, 'code'),
|
||||||
|
|
||||||
|
meta: (style, test, part) =>
|
||||||
|
METAKEYS.some(key => test(style[key])) ||
|
||||||
|
test(part === 'all' ? style.sourceCode : extractMeta(style)) ||
|
||||||
|
searchSections(style, test, 'funcs'),
|
||||||
|
|
||||||
|
name: (style, test) =>
|
||||||
|
test(style.customName) ||
|
||||||
|
test(style.name),
|
||||||
|
|
||||||
|
all: (style, test) =>
|
||||||
|
MODES.meta(style, test, 'all') ||
|
||||||
|
!style.usercssData && MODES.code(style, test),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param params
|
* @param params
|
||||||
* @param {string} params.query - 1. url:someurl 2. text (may contain quoted parts like "qUot Ed")
|
* @param {string} params.query - 1. url:someurl 2. text (may contain quoted parts like "qUot Ed")
|
||||||
|
* @param {'name'|'meta'|'code'|'all'|'url'} [params.mode=all]
|
||||||
* @param {number[]} [params.ids] - if not specified, all styles are searched
|
* @param {number[]} [params.ids] - if not specified, all styles are searched
|
||||||
* @returns {number[]} - array of matched styles ids
|
* @returns {number[]} - array of matched styles ids
|
||||||
*/
|
*/
|
||||||
API_METHODS.searchDB = ({query, ids}) => {
|
API_METHODS.searchDB = async ({query, mode = 'all', ids}) => {
|
||||||
let rx, words, icase, matchUrl;
|
let res = [];
|
||||||
query = query.trim();
|
if (mode === 'url' && query) {
|
||||||
|
res = (await styleManager.getStylesByUrl(query)).map(r => r.data.id);
|
||||||
if (/^url:/i.test(query)) {
|
} else if (mode in MODES) {
|
||||||
matchUrl = query.slice(query.indexOf(':') + 1).trim();
|
const modeHandler = MODES[mode];
|
||||||
if (matchUrl) {
|
const m = /^\/(.+?)\/([gimsuy]*)$/.exec(query);
|
||||||
return styleManager.getStylesByUrl(matchUrl)
|
const rx = m && tryRegExp(m[1], m[2]);
|
||||||
.then(results => results.map(r => r.data.id));
|
const test = rx ? rx.test.bind(rx) : makeTester(query);
|
||||||
}
|
res = (await styleManager.getAllStyles())
|
||||||
}
|
.filter(style =>
|
||||||
if (query.startsWith('/') && /^\/(.+?)\/([gimsuy]*)$/.test(query)) {
|
(!ids || ids.includes(style.id)) &&
|
||||||
rx = tryRegExp(RegExp.$1, RegExp.$2);
|
(!query || modeHandler(style, test)))
|
||||||
}
|
.map(style => style.id);
|
||||||
if (!rx) {
|
|
||||||
words = query
|
|
||||||
.split(/(".*?")|\s+/)
|
|
||||||
.filter(Boolean)
|
|
||||||
.map(w => w.startsWith('"') && w.endsWith('"')
|
|
||||||
? w.slice(1, -1)
|
|
||||||
: w)
|
|
||||||
.filter(w => w.length > 1);
|
|
||||||
words = words.length ? words : [query];
|
|
||||||
icase = words.some(w => w === lower(w));
|
|
||||||
}
|
|
||||||
|
|
||||||
return styleManager.getAllStyles().then(styles => {
|
|
||||||
if (ids) {
|
|
||||||
const idSet = new Set(ids);
|
|
||||||
styles = styles.filter(s => idSet.has(s.id));
|
|
||||||
}
|
|
||||||
const results = [];
|
|
||||||
for (const style of styles) {
|
|
||||||
const id = style.id;
|
|
||||||
if (!query || words && !words.length) {
|
|
||||||
results.push(id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (const part in PARTS) {
|
|
||||||
const text = part === 'name' ? style.customName || style.name : style[part];
|
|
||||||
if (text && PARTS[part](text, rx, words, icase)) {
|
|
||||||
results.push(id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cache.size) debounce(clearCache, 60e3);
|
if (cache.size) debounce(clearCache, 60e3);
|
||||||
return results;
|
}
|
||||||
});
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
function searchText(text, rx, words, icase) {
|
function makeTester(query) {
|
||||||
if (rx) return rx.test(text);
|
const flags = `u${lower(query) === query ? 'i' : ''}`;
|
||||||
for (let pass = 1; pass <= (icase ? 2 : 1); pass++) {
|
const words = query
|
||||||
if (words.every(w => text.includes(w))) return true;
|
.split(/(".*?")|\s+/)
|
||||||
text = lower(text);
|
.filter(Boolean)
|
||||||
}
|
.map(w => w.startsWith('"') && w.endsWith('"')
|
||||||
|
? w.slice(1, -1)
|
||||||
|
: w)
|
||||||
|
.filter(w => w.length > 1);
|
||||||
|
const rxs = (words.length ? words : [query])
|
||||||
|
.map(w => stringAsRegExp(w, flags));
|
||||||
|
return text => rxs.every(rx => rx.test(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchSections(sections, rx, words, icase) {
|
function searchSections({sections}, test, part) {
|
||||||
|
const inCode = part === 'code' || part === 'all';
|
||||||
|
const inFuncs = part === 'funcs' || part === 'all';
|
||||||
for (const section of sections) {
|
for (const section of sections) {
|
||||||
for (const prop in section) {
|
for (const prop in section) {
|
||||||
const value = section[prop];
|
const value = section[prop];
|
||||||
if (typeof value === 'string') {
|
if (inCode && prop === 'code' && test(value) ||
|
||||||
if (searchText(value, rx, words, icase)) return true;
|
inFuncs && Array.isArray(value) && value.some(str => test(str))) {
|
||||||
} else if (Array.isArray(value)) {
|
return true;
|
||||||
if (value.some(str => searchText(str, rx, words, icase))) return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,9 +99,7 @@
|
||||||
|
|
||||||
function lower(text) {
|
function lower(text) {
|
||||||
let result = cache.get(text);
|
let result = cache.get(text);
|
||||||
if (result) return result;
|
if (!result) cache.set(text, result = text.toLocaleLowerCase());
|
||||||
result = text.toLocaleLowerCase();
|
|
||||||
cache.set(text, result);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -470,11 +470,7 @@ const styleManager = (() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sectionMatched) {
|
if (sectionMatched) {
|
||||||
result.push({
|
result.push({data, excluded, sloppy});
|
||||||
data: getStyleWithNoCode(data),
|
|
||||||
excluded,
|
|
||||||
sloppy,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -142,6 +142,7 @@ select {
|
||||||
transition: color .5s;
|
transition: color .5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select-wrapper,
|
||||||
.select-resizer {
|
.select-resizer {
|
||||||
display: inline-flex!important;
|
display: inline-flex!important;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
|
@ -12,7 +12,12 @@ const usercss = (() => {
|
||||||
};
|
};
|
||||||
const RX_META = /\/\*!?\s*==userstyle==[\s\S]*?==\/userstyle==\s*\*\//i;
|
const RX_META = /\/\*!?\s*==userstyle==[\s\S]*?==\/userstyle==\s*\*\//i;
|
||||||
const ERR_ARGS_IS_LIST = new Set(['missingMandatory', 'missingChar']);
|
const ERR_ARGS_IS_LIST = new Set(['missingMandatory', 'missingChar']);
|
||||||
return {buildMeta, buildCode, assignVars};
|
return {
|
||||||
|
RX_META,
|
||||||
|
buildMeta,
|
||||||
|
buildCode,
|
||||||
|
assignVars,
|
||||||
|
};
|
||||||
|
|
||||||
function buildMeta(sourceCode) {
|
function buildMeta(sourceCode) {
|
||||||
sourceCode = sourceCode.replace(/\r\n?/g, '\n');
|
sourceCode = sourceCode.replace(/\r\n?/g, '\n');
|
||||||
|
|
12
manage.html
12
manage.html
|
@ -266,9 +266,19 @@
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div id="search-wrapper">
|
<div id="search-wrapper">
|
||||||
<input id="search" type="search" i18n-placeholder="searchStyles" spellcheck="false"
|
<input id="search" type="search" i18n-placeholder="search" spellcheck="false"
|
||||||
data-filter=":not(.not-matching)"
|
data-filter=":not(.not-matching)"
|
||||||
data-filter-hide=".not-matching">
|
data-filter-hide=".not-matching">
|
||||||
|
<div class="select-wrapper">
|
||||||
|
<select id="searchMode">
|
||||||
|
<option i18n-text="searchStylesName" value="name"></option>
|
||||||
|
<option i18n-text="searchStylesMeta" value="meta" selected></option>
|
||||||
|
<option i18n-text="searchStylesCode" value="code"></option>
|
||||||
|
<option i18n-text="searchStylesMatchUrl" value="url"></option>
|
||||||
|
<option i18n-text="searchStylesAll" value="all"></option>
|
||||||
|
</select>
|
||||||
|
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
||||||
|
</div>
|
||||||
<a href="#" id="search-help" tabindex="0">
|
<a href="#" id="search-help" tabindex="0">
|
||||||
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -11,8 +11,9 @@ const filtersSelector = {
|
||||||
|
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
|
|
||||||
router.watch({search: ['search']}, ([search]) => {
|
router.watch({search: ['search', 'searchMode']}, ([search, mode]) => {
|
||||||
$('#search').value = search || '';
|
$('#search').value = search || '';
|
||||||
|
if (mode) $('#searchMode').value = mode;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initFilters();
|
initFilters();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
@ -37,15 +38,15 @@ HTMLSelectElement.prototype.adjustWidth = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function initFilters() {
|
function initFilters() {
|
||||||
$('#search').oninput = e => {
|
$('#search').oninput = $('#searchMode').oninput = function (e) {
|
||||||
router.updateSearch('search', e.target.value);
|
router.updateSearch(this.id, e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#search-help').onclick = event => {
|
$('#search-help').onclick = event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
messageBox({
|
messageBox({
|
||||||
className: 'help-text',
|
className: 'help-text',
|
||||||
title: t('searchStyles'),
|
title: t('search'),
|
||||||
contents:
|
contents:
|
||||||
$create('ul',
|
$create('ul',
|
||||||
t('searchStylesHelp').split('\n').map(line =>
|
t('searchStylesHelp').split('\n').map(line =>
|
||||||
|
@ -141,7 +142,7 @@ function initFilters() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function filterOnChange({target: el, forceRefilter}) {
|
function filterOnChange({target: el, forceRefilter, alreadySearched}) {
|
||||||
const getValue = el => (el.type === 'checkbox' ? el.checked : el.value.trim());
|
const getValue = el => (el.type === 'checkbox' ? el.checked : el.value.trim());
|
||||||
if (!forceRefilter) {
|
if (!forceRefilter) {
|
||||||
const value = getValue(el);
|
const value = getValue(el);
|
||||||
|
@ -164,7 +165,7 @@ function filterOnChange({target: el, forceRefilter}) {
|
||||||
unhide: buildFilter(false),
|
unhide: buildFilter(false),
|
||||||
});
|
});
|
||||||
if (installed) {
|
if (installed) {
|
||||||
reapplyFilter().then(sorter.updateStripes);
|
reapplyFilter(installed, alreadySearched).then(sorter.updateStripes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,10 +279,12 @@ function showFiltersStats() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function searchStyles({immediately, container} = {}) {
|
async function searchStyles({immediately, container} = {}) {
|
||||||
const el = $('#search');
|
const el = $('#search');
|
||||||
|
const elMode = $('#searchMode');
|
||||||
const query = el.value.trim();
|
const query = el.value.trim();
|
||||||
if (query === el.lastValue && !immediately && !container) {
|
const mode = elMode.value;
|
||||||
|
if (query === el.lastValue && mode === elMode.lastValue && !immediately && !container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!immediately) {
|
if (!immediately) {
|
||||||
|
@ -289,24 +292,24 @@ function searchStyles({immediately, container} = {}) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
el.lastValue = query;
|
el.lastValue = query;
|
||||||
|
elMode.lastValue = mode;
|
||||||
|
|
||||||
const entries = container && container.children || container || installed.children;
|
const all = installed.children;
|
||||||
return API.searchDB({
|
const entries = container && container.children || container || all;
|
||||||
query,
|
const idsToSearch = entries !== all && [...entries].map(el => el.styleId);
|
||||||
ids: [...entries].map(el => el.styleId),
|
const ids = entries[0]
|
||||||
}).then(ids => {
|
? await API.searchDB({query, mode, ids: idsToSearch})
|
||||||
ids = new Set(ids);
|
: [];
|
||||||
let needsRefilter = false;
|
let needsRefilter = false;
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
const isMatching = ids.has(entry.styleId);
|
const isMatching = ids.includes(entry.styleId);
|
||||||
if (entry.classList.contains('not-matching') !== !isMatching) {
|
if (entry.classList.contains('not-matching') !== !isMatching) {
|
||||||
entry.classList.toggle('not-matching', !isMatching);
|
entry.classList.toggle('not-matching', !isMatching);
|
||||||
needsRefilter = true;
|
needsRefilter = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (needsRefilter && !container) {
|
}
|
||||||
filterOnChange({forceRefilter: true});
|
if (needsRefilter && !container) {
|
||||||
}
|
filterOnChange({forceRefilter: true, alreadySearched: true});
|
||||||
return container;
|
}
|
||||||
});
|
return container;
|
||||||
}
|
}
|
||||||
|
|
|
@ -825,10 +825,6 @@ a:hover {
|
||||||
background-color: hsla(0, 0%, 50%, .4);
|
background-color: hsla(0, 0%, 50%, .4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#filters {
|
|
||||||
border: 1px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active #filters-stats {
|
.active #filters-stats {
|
||||||
background-color: darkcyan;
|
background-color: darkcyan;
|
||||||
border-color: darkcyan;
|
border-color: darkcyan;
|
||||||
|
@ -874,10 +870,11 @@ a:hover {
|
||||||
#search-wrapper, #sort-wrapper {
|
#search-wrapper, #sort-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
#searchMode {
|
||||||
|
margin-left: -1px;
|
||||||
|
}
|
||||||
#search-wrapper {
|
#search-wrapper {
|
||||||
margin-top: .35rem;
|
margin-top: .35rem;
|
||||||
}
|
}
|
||||||
|
@ -886,17 +883,12 @@ a:hover {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: calc(100% - 30px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#manage\.newUI\.sort {
|
#manage\.newUI\.sort {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search {
|
|
||||||
max-width: calc(100% - 30px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#search, #manage\.newUI\.sort {
|
#search, #manage\.newUI\.sort {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|
|
@ -75,7 +75,7 @@ const handleEvent = {};
|
||||||
const query = router.getSearch('search');
|
const query = router.getSearch('search');
|
||||||
const [styles, ids, el] = await Promise.all([
|
const [styles, ids, el] = await Promise.all([
|
||||||
API.getAllStyles(),
|
API.getAllStyles(),
|
||||||
query && API.searchDB({query}), // FIXME: integrate this into filter.js
|
query && API.searchDB({query, mode: router.getSearch('searchMode')}),
|
||||||
waitForSelector('#installed'), // needed to avoid flicker due to an extra frame and layout shift
|
waitForSelector('#installed'), // needed to avoid flicker due to an extra frame and layout shift
|
||||||
prefs.initializing,
|
prefs.initializing,
|
||||||
]);
|
]);
|
||||||
|
@ -102,7 +102,7 @@ const handleEvent = {};
|
||||||
].map(id => `--${id}:"${CSS.escape(t(id))}";`).join('')
|
].map(id => `--${id}:"${CSS.escape(t(id))}";`).join('')
|
||||||
}}`);
|
}}`);
|
||||||
if (!VIVALDI) {
|
if (!VIVALDI) {
|
||||||
$$('#header select').forEach(el => el.adjustWidth());
|
$$('#filters select').forEach(el => el.adjustWidth());
|
||||||
}
|
}
|
||||||
if (CHROME >= 80 && CHROME <= 88) {
|
if (CHROME >= 80 && CHROME <= 88) {
|
||||||
// Wrong checkboxes are randomly checked after going back in history, https://crbug.com/1138598
|
// Wrong checkboxes are randomly checked after going back in history, https://crbug.com/1138598
|
||||||
|
|
|
@ -137,7 +137,6 @@ function initPopup(frames) {
|
||||||
|
|
||||||
Object.assign($('#popup-manage-button'), {
|
Object.assign($('#popup-manage-button'), {
|
||||||
onclick: handleEvent.openManager,
|
onclick: handleEvent.openManager,
|
||||||
onmouseup: handleEvent.openManager,
|
|
||||||
oncontextmenu: handleEvent.openManager,
|
oncontextmenu: handleEvent.openManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -654,17 +653,10 @@ Object.assign(handleEvent, {
|
||||||
},
|
},
|
||||||
|
|
||||||
openManager(event) {
|
openManager(event) {
|
||||||
if (event.button === 2 && !tabURL) return;
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!this.eventHandled) {
|
const isSearch = tabURL && (event.shiftKey || event.button === 2);
|
||||||
// FIXME: this only works if popup is closed
|
API.openManage(isSearch ? {search: tabURL, searchMode: 'url'} : {});
|
||||||
this.eventHandled = true;
|
window.close();
|
||||||
API.openManage({
|
|
||||||
search: tabURL && (event.shiftKey || event.button === 2) ?
|
|
||||||
`url:${tabURL}` : null,
|
|
||||||
});
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
copyContent(event) {
|
copyContent(event) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user