extract popup search + show error + CtrlF
This commit is contained in:
parent
3907116328
commit
a74ae5ac4f
|
@ -1,4 +1,4 @@
|
||||||
/* global $$ waitForSelector */// dom.js
|
/* global $$ $ waitForSelector */// dom.js
|
||||||
/* global download */// toolbox.js
|
/* global download */// toolbox.js
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -117,13 +117,22 @@ Object.assign(t, {
|
||||||
return t.toFragment(root);
|
return t.toFragment(root);
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchTemplate: async (url, name) => t.template[name] ||
|
fetchTemplate: async (url, name) => {
|
||||||
|
let res = t.template[name];
|
||||||
|
if (!res) {
|
||||||
|
res = t.parse(await download(url), '*');
|
||||||
|
if (!$$('template', res).map(t.createTemplate).length) {
|
||||||
t.createTemplate({
|
t.createTemplate({
|
||||||
content: t.toFragment(t.parse(await download(url))),
|
content: t.toFragment($('body', res)),
|
||||||
dataset: {id: name},
|
dataset: {id: name},
|
||||||
}),
|
});
|
||||||
|
}
|
||||||
|
res = t.template[name];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
parse: str => new DOMParser().parseFromString(str, 'text/html').body,
|
parse: (str, pick = 'body') => $(pick, new DOMParser().parseFromString(str, 'text/html')),
|
||||||
|
|
||||||
sanitizeHtml(root) {
|
sanitizeHtml(root) {
|
||||||
const toRemove = [];
|
const toRemove = [];
|
||||||
|
|
88
popup.html
88
popup.html
|
@ -98,65 +98,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template data-id="searchResult">
|
|
||||||
<div class="search-result">
|
|
||||||
<a class="search-result-title"><span></span></a>
|
|
||||||
<div class="search-result-info">
|
|
||||||
<img class="search-result-screenshot" i18n="title:installButton">
|
|
||||||
<div class="search-result-status"></div>
|
|
||||||
<div class="search-result-actions">
|
|
||||||
<button class="search-result-install" i18n="installButton"></button>
|
|
||||||
<button class="search-result-uninstall" i18n="deleteStyleLabel"></button>
|
|
||||||
<button class="search-result-customize" i18n="configureStyle"></button>
|
|
||||||
</div>
|
|
||||||
<dl class="search-result-meta">
|
|
||||||
<div data-type="author">
|
|
||||||
<dt i18n="author"></dt>
|
|
||||||
<dd><a target="_blank" i18n="title:author"></a></dd>
|
|
||||||
</div>
|
|
||||||
<div data-type="rating">
|
|
||||||
<dt i18n="searchResultRating"></dt>
|
|
||||||
<dd i18n="title:searchResultRating"></dd>
|
|
||||||
</div>
|
|
||||||
<div data-type="updated">
|
|
||||||
<dt i18n="searchResultUpdated"></dt>
|
|
||||||
<dd i18n="title:searchResultUpdated"><time></time></dd>
|
|
||||||
</div>
|
|
||||||
<div data-type="weekly">
|
|
||||||
<dt i18n="searchResultWeeklyCount"></dt>
|
|
||||||
<dd i18n="title:searchResultWeeklyCount"></dd>
|
|
||||||
</div>
|
|
||||||
<div data-type="total">
|
|
||||||
<dt i18n="searchResultInstallCount"></dt>
|
|
||||||
<dd i18n="title:searchResultInstallCount"></dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
<div class="search-result-description"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template data-id="searchNav">
|
|
||||||
<div>
|
|
||||||
<button data-type="prev" i18n="title:paginationPrevious" disabled>◄</button>
|
|
||||||
<label>
|
|
||||||
<span data-type="page" i18n="title:paginationCurrent">-</span>
|
|
||||||
/
|
|
||||||
<span data-type="total" i18n="title:paginationEstimated">-</span>
|
|
||||||
</label>
|
|
||||||
<button data-type="next" i18n="title:paginationNext" disabled>►</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template data-id="emptySearchResult">
|
|
||||||
<div class="search-result-empty"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template data-id="searchResultNotMatching">
|
|
||||||
<p class="not-matching-explainer"
|
|
||||||
i18n="searchResultNotMatching, title:searchResultNotMatchingNote"></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="js/polyfill.js"></script>
|
<script src="js/polyfill.js"></script>
|
||||||
<script src="js/msg.js"></script>
|
<script src="js/msg.js"></script>
|
||||||
<script src="js/toolbox.js"></script>
|
<script src="js/toolbox.js"></script>
|
||||||
|
@ -214,7 +155,7 @@
|
||||||
><button class="if-not-blocked split-btn-pedal" i18n="menu-site:popupManageSiteStyles"></button>
|
><button class="if-not-blocked split-btn-pedal" i18n="menu-site:popupManageSiteStyles"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="split-btn if-not-blocked" id="find-split">
|
<div class="split-btn if-not-blocked" id="find-split">
|
||||||
<button id="find-styles-btn" i18n="findStyles"></button
|
<button id="find-styles-btn" i18n="findStyles" title="Ctrl-F"></button
|
||||||
><button class="split-btn-pedal"
|
><button class="split-btn-pedal"
|
||||||
menu-usoa="UserStyles Archive"
|
menu-usoa="UserStyles Archive"
|
||||||
menu-usw="UserStyles World"
|
menu-usw="UserStyles World"
|
||||||
|
@ -231,33 +172,6 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="search-results-error" class="hidden"></div>
|
|
||||||
<div id="search-results" class="hidden">
|
|
||||||
<div class="search-results-nav" data-type="top"></div>
|
|
||||||
<div id="search-params">
|
|
||||||
<input id="search-query" type="search" i18n="placeholder:search, title:searchStyleQueryHint">
|
|
||||||
<div class="select-resizer">
|
|
||||||
<select id="search-order" i18n="title:sortStylesHelpTitle">
|
|
||||||
<option value="n" i18n="genericTitle">
|
|
||||||
<option value="u" i18n="searchResultUpdated">
|
|
||||||
<option value="t" i18n="searchResultInstallCount">
|
|
||||||
<option value="w" i18n="searchResultWeeklyCount">
|
|
||||||
<option value="r" i18n="searchResultRating">
|
|
||||||
</select>
|
|
||||||
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
|
||||||
</div>
|
|
||||||
<label>
|
|
||||||
<span class="checkbox-container">
|
|
||||||
<input id="search-globals" type="checkbox" checked>
|
|
||||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
|
||||||
</span>
|
|
||||||
<span i18n="searchGlobalStyles"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="search-results-list"></div>
|
|
||||||
<div class="search-results-nav" data-type="bottom"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Here we can use the above elements before DOMContentLoaded -->
|
<!-- Here we can use the above elements before DOMContentLoaded -->
|
||||||
<script src="popup/events.js"></script>
|
<script src="popup/events.js"></script>
|
||||||
<script src="popup/popup.js"></script>
|
<script src="popup/popup.js"></script>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* global $ $$ $create setupLivePrefs */// dom.js
|
/* global $ $$ $create getEventKeyName setupLivePrefs */// dom.js
|
||||||
/* global ABOUT_BLANK getStyleDataMerged preinit */// preinit.js
|
/* global ABOUT_BLANK getStyleDataMerged preinit */// preinit.js
|
||||||
/* global API msg */// msg.js
|
/* global API msg */// msg.js
|
||||||
/* global Events */
|
/* global Events */
|
||||||
|
@ -86,13 +86,30 @@ async function initPopup(frames) {
|
||||||
setupLivePrefs();
|
setupLivePrefs();
|
||||||
|
|
||||||
const elFind = $('#find-styles-btn');
|
const elFind = $('#find-styles-btn');
|
||||||
elFind.onclick = async e => {
|
const elFindDeps = async () => {
|
||||||
const inline = e.type === 'click';
|
if (!t.template.searchUI) {
|
||||||
if (inline) elFind.disabled = true;
|
document.body.append(await t.fetchTemplate('/popup/search.html', 'searchUI'));
|
||||||
await require(['/popup/search']);
|
}
|
||||||
if (!inline) Events.searchSite(e);
|
await require([
|
||||||
|
'/popup/search.css',
|
||||||
|
'/popup/search',
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
elFind.on('split-btn', elFind.onclick);
|
elFind.on('click', async () => {
|
||||||
|
elFind.disabled = true;
|
||||||
|
await elFindDeps();
|
||||||
|
Events.searchInline();
|
||||||
|
});
|
||||||
|
elFind.on('split-btn', async e => {
|
||||||
|
await elFindDeps();
|
||||||
|
Events.searchSite(e);
|
||||||
|
});
|
||||||
|
window.on('keydown', e => {
|
||||||
|
if (getEventKeyName(e) === 'Ctrl-F') {
|
||||||
|
e.preventDefault();
|
||||||
|
elFind.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Object.assign($('#popup-manage-button'), {
|
Object.assign($('#popup-manage-button'), {
|
||||||
onclick: Events.openManager,
|
onclick: Events.openManager,
|
||||||
|
|
84
popup/search.html
Normal file
84
popup/search.html
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<template data-id="searchUI">
|
||||||
|
<div id="search-results-error" hidden></div>
|
||||||
|
<div id="search-results" hidden>
|
||||||
|
<div class="search-results-nav" data-type="top"></div>
|
||||||
|
<div id="search-params">
|
||||||
|
<input id="search-query" type="search" i18n="placeholder:search, title:searchStyleQueryHint">
|
||||||
|
<div class="select-resizer">
|
||||||
|
<select id="search-order" i18n="title:sortStylesHelpTitle">
|
||||||
|
<option value="n" i18n="genericTitle">
|
||||||
|
<option value="u" i18n="searchResultUpdated">
|
||||||
|
<option value="t" i18n="searchResultInstallCount">
|
||||||
|
<option value="w" i18n="searchResultWeeklyCount">
|
||||||
|
<option value="r" i18n="searchResultRating">
|
||||||
|
</select>
|
||||||
|
<svg class="svg-icon select-arrow"><use xlink:href="#svg-icon-select-arrow"/></svg>
|
||||||
|
</div>
|
||||||
|
<label class="checkbox-wrapper" i18n="searchGlobalStyles">
|
||||||
|
<input id="search-globals" type="checkbox" checked>
|
||||||
|
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="search-results-list"></div>
|
||||||
|
<div class="search-results-nav" data-type="bottom"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template data-id="searchNav">
|
||||||
|
<div>
|
||||||
|
<button data-type="prev" i18n="title:paginationPrevious" disabled>◄</button>
|
||||||
|
<label>
|
||||||
|
<span data-type="page" i18n="title:paginationCurrent">-</span>
|
||||||
|
/
|
||||||
|
<span data-type="total" i18n="title:paginationEstimated">-</span>
|
||||||
|
</label>
|
||||||
|
<button data-type="next" i18n="title:paginationNext" disabled>►</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template data-id="searchResult">
|
||||||
|
<div class="search-result">
|
||||||
|
<a class="search-result-title"><span></span></a>
|
||||||
|
<div class="search-result-info">
|
||||||
|
<img class="search-result-screenshot" i18n="title:installButton">
|
||||||
|
<div class="search-result-status"></div>
|
||||||
|
<div class="search-result-actions">
|
||||||
|
<button class="search-result-install" i18n="installButton"></button>
|
||||||
|
<button class="search-result-uninstall" i18n="deleteStyleLabel"></button>
|
||||||
|
<button class="search-result-customize" i18n="configureStyle"></button>
|
||||||
|
</div>
|
||||||
|
<dl class="search-result-meta">
|
||||||
|
<div data-type="author">
|
||||||
|
<dt i18n="author"></dt>
|
||||||
|
<dd><a target="_blank" i18n="title:author"></a></dd>
|
||||||
|
</div>
|
||||||
|
<div data-type="rating">
|
||||||
|
<dt i18n="searchResultRating"></dt>
|
||||||
|
<dd i18n="title:searchResultRating"></dd>
|
||||||
|
</div>
|
||||||
|
<div data-type="updated">
|
||||||
|
<dt i18n="searchResultUpdated"></dt>
|
||||||
|
<dd i18n="title:searchResultUpdated"><time></time></dd>
|
||||||
|
</div>
|
||||||
|
<div data-type="weekly">
|
||||||
|
<dt i18n="searchResultWeeklyCount"></dt>
|
||||||
|
<dd i18n="title:searchResultWeeklyCount"></dd>
|
||||||
|
</div>
|
||||||
|
<div data-type="total">
|
||||||
|
<dt i18n="searchResultInstallCount"></dt>
|
||||||
|
<dd i18n="title:searchResultInstallCount"></dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
<div class="search-result-description"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template data-id="emptySearchResult">
|
||||||
|
<div class="search-result-empty"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template data-id="searchResultNotMatching">
|
||||||
|
<p class="not-matching-explainer"
|
||||||
|
i18n="searchResultNotMatching, title:searchResultNotMatchingNote"></p>
|
||||||
|
</template>
|
|
@ -8,8 +8,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
require(['/popup/search.css']);
|
|
||||||
|
|
||||||
const RESULT_ID_PREFIX = t.template.searchResult.className + '-';
|
const RESULT_ID_PREFIX = t.template.searchResult.className + '-';
|
||||||
const RESULT_SEL = '.' + t.template.searchResult.className;
|
const RESULT_SEL = '.' + t.template.searchResult.className;
|
||||||
const INDEX_URL = URLS.usoArchiveRaw[0] + 'search-index.json';
|
const INDEX_URL = URLS.usoArchiveRaw[0] + 'search-index.json';
|
||||||
|
@ -71,10 +69,10 @@
|
||||||
const entry = el.closest(RESULT_SEL);
|
const entry = el.closest(RESULT_SEL);
|
||||||
return {entry, result: entry && entry._result};
|
return {entry, result: entry && entry._result};
|
||||||
};
|
};
|
||||||
const $classList = sel => (sel instanceof Node ? sel : $(sel)).classList;
|
Events.searchInline = () => {
|
||||||
const show = sel => $classList(sel).remove('hidden');
|
calcCategory();
|
||||||
const hide = sel => $classList(sel).add('hidden');
|
ready = start();
|
||||||
|
};
|
||||||
Events.searchSite = event => {
|
Events.searchSite = event => {
|
||||||
// use a less specific category if the inline search wasn't used yet
|
// use a less specific category if the inline search wasn't used yet
|
||||||
if (!category) calcCategory({retry: 1});
|
if (!category) calcCategory({retry: 1});
|
||||||
|
@ -94,7 +92,6 @@
|
||||||
`/scripts/by-site/${tryURL(tabURL).hostname.replace(/^www\./, '')}?language=css${add('&q=', q)}`;
|
`/scripts/by-site/${tryURL(tabURL).hostname.replace(/^www\./, '')}?language=css${add('&q=', q)}`;
|
||||||
Events.openURLandHide.call({href}, event);
|
Events.openURLandHide.call({href}, event);
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#search-globals').onchange = function () {
|
$('#search-globals').onchange = function () {
|
||||||
searchGlobals = this.checked;
|
searchGlobals = this.checked;
|
||||||
ready = ready.then(start);
|
ready = ready.then(start);
|
||||||
|
@ -165,9 +162,6 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
calcCategory();
|
|
||||||
ready = start();
|
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
displayedPage = Math.min(totalPages, displayedPage + 1);
|
displayedPage = Math.min(totalPages, displayedPage + 1);
|
||||||
scrollToFirstResult = true;
|
scrollToFirstResult = true;
|
||||||
|
@ -182,15 +176,15 @@
|
||||||
|
|
||||||
function error(reason) {
|
function error(reason) {
|
||||||
dom.error.textContent = reason;
|
dom.error.textContent = reason;
|
||||||
show(dom.error);
|
dom.error.hidden = false;
|
||||||
hide(dom.list);
|
dom.list.hidden = true;
|
||||||
if (dom.error.getBoundingClientRect().bottom < 0) {
|
if (dom.error.getBoundingClientRect().bottom < 0) {
|
||||||
dom.error.scrollIntoView({behavior: 'smooth', block: 'start'});
|
dom.error.scrollIntoView({behavior: 'smooth', block: 'start'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
resetUI.timer = setTimeout(resetUI, 500);
|
resetUI.timer = resetUI.timer || setTimeout(resetUI, 500);
|
||||||
try {
|
try {
|
||||||
results = [];
|
results = [];
|
||||||
for (let retry = 0; !results.length && retry <= 2; retry++) {
|
for (let retry = 0; !results.length && retry <= 2; retry++) {
|
||||||
|
@ -202,22 +196,24 @@
|
||||||
results = results.filter(r => !allSupportedIds.has(r.i));
|
results = results.filter(r => !allSupportedIds.has(r.i));
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
(results.length ? show : hide)(dom.list);
|
dom.list.hidden = !results.length;
|
||||||
if (!results.length && !$('#search-query').value) {
|
if (!results.length && !$('#search-query').value) {
|
||||||
error(t('searchResultNoneFound'));
|
error(t('searchResultNoneFound'));
|
||||||
|
} else {
|
||||||
|
resetUI();
|
||||||
}
|
}
|
||||||
} catch (reason) {
|
} catch (reason) {
|
||||||
error(reason);
|
error(reason);
|
||||||
}
|
}
|
||||||
clearTimeout(resetUI.timer);
|
clearTimeout(resetUI.timer);
|
||||||
resetUI();
|
resetUI.timer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetUI() {
|
function resetUI() {
|
||||||
document.body.classList.add('search-results-shown');
|
document.body.classList.add('search-results-shown');
|
||||||
show(dom.container);
|
dom.container.hidden = false;
|
||||||
show(dom.list);
|
dom.list.hidden = false;
|
||||||
hide(dom.error);
|
dom.error.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user