show installed styles in popup finder

fixes #1488
This commit is contained in:
tophf 2022-10-12 20:04:45 +03:00
parent 79dff2775b
commit 1725c0ecb9
3 changed files with 66 additions and 43 deletions

View File

@ -199,6 +199,18 @@ const styleMan = (() => {
getOrder: () => orderWrap.value,
/** @returns {Promise<string | {[remoteId:string]: styleId}>}>} */
async getRemoteInfo(id) {
if (ready.then) await ready;
if (id) return calcRemoteId(id2style(id));
const res = {};
for (const {style} of dataMap.values()) {
const [rid, vars] = calcRemoteId(style);
if (rid) res[rid] = [style.id, vars];
}
return res;
},
/** @returns {Promise<StyleSectionsToApply>} */
async getSectionsByUrl(url, id, isInitialApply) {
if (ready.then) await ready;
@ -366,6 +378,17 @@ const styleMan = (() => {
return id2style(uuidIndex.get(uuid));
}
function calcRemoteId({md5Url, updateUrl, usercssData: ucd} = {}) {
let id;
id = (id = /\d+/.test(md5Url) || URLS.extractUsoArchiveId(updateUrl)) && `uso-${id}`
|| (id = URLS.extractUSwId(updateUrl)) && `usw-${id}`
|| '';
return id && [
id,
ucd && !isEmptyObj(ucd.vars),
];
}
/** @returns {StyleObj} */
function createNewStyle() {
return /** @namespace StyleObj */ {

View File

@ -134,6 +134,10 @@
width: 100%;
}
.search-result[data-installed] {
box-shadow: 1px 1px 10px darkcyan;
border-color: darkcyan;
}
.search-result:not([data-installed]) .search-result-actions {
opacity: 0;
transition: opacity .5s;

View File

@ -2,7 +2,7 @@
/* global $entry tabURL */// popup.js
/* global API */// msg.js
/* global Events */
/* global FIREFOX URLS debounce download stringAsRegExp tryRegExp tryURL */// toolbox.js
/* global FIREFOX URLS debounce download isEmptyObj stringAsRegExp tryRegExp tryURL */// toolbox.js
/* global prefs */
/* global t */// localization.js
'use strict';
@ -27,7 +27,7 @@
/**
* @typedef IndexEntry
* @prop {'uso' | 'uso-android'} f - format
* @prop {Number} i - id
* @prop {Number} i - id, later replaced with string like `uso-123`
* @prop {string} n - name
* @prop {string} c - category
* @prop {Number} u - updatedTime
@ -39,8 +39,8 @@
* @prop {string} sn - screenshotName
* @prop {boolean} sa - screenshotArchived
*
* @prop {boolean} _installed
* @prop {number} _installedStyleId
* @prop {number} _styleId - installed style id
* @prop {boolean} _styleVars - installed style has vars
* @prop {number} _year
*/
/** @type IndexEntry[] */
@ -73,6 +73,7 @@
const entry = el.closest(RESULT_SEL);
return {entry, result: entry && entry._result};
};
const rid2id = rid => rid.split('-')[1];
Events.searchInline = () => {
calcCategory();
ready = start();
@ -158,18 +159,22 @@
window.on('styleDeleted', ({detail: {style: {id}}}) => {
restoreScrollPosition();
const result = results.find(r => r._installedStyleId === id);
if (result) {
API.uso.pingback(result.i, false);
renderActionButtons(result.i, -1);
const r = results.find(r => r._styleId === id);
if (r) {
if (r.f) API.uso.pingback(rid2id(r.i), false);
delete r._styleId;
renderActionButtons(r.i);
}
});
window.on('styleAdded', async ({detail: {style}}) => {
restoreScrollPosition();
const id = calcId(style) || calcId(await API.styles.get(style.id));
if (id && results.find(r => r.i === id)) {
renderActionButtons(id, style.id);
const ri = await API.styles.getRemoteInfo(style.id);
const r = ri && results.find(r => ri[0] === r.i);
if (r) {
r._styleId = style.id;
r._styleVars = ri[1];
renderActionButtons(ri[0]);
}
});
@ -209,9 +214,10 @@
results = await search({retry});
}
if (results.length) {
const installedStyles = await API.styles.getAll();
const allSupportedIds = new Set(installedStyles.map(calcId));
results = results.filter(r => !allSupportedIds.has(r.i));
const info = await API.styles.getRemoteInfo();
for (const r of results) {
[r._styleId, r._styleVars] = info[r.i] || [];
}
}
if (!keepYears) resultsAllYears = results;
renderYears();
@ -330,7 +336,7 @@
function createSearchResultNode(result) {
const entry = t.template.searchResult.cloneNode(true);
const {
i: id,
i: rid,
n: name,
r: rating,
u: updateTime,
@ -342,7 +348,8 @@
sn: shot,
f: fmt,
} = entry._result = result;
entry.id = RESULT_ID_PREFIX + id;
const id = rid2id(rid);
entry.id = RESULT_ID_PREFIX + rid;
// title
Object.assign($('.search-result-title', entry), {
onclick: Events.openURLandHide,
@ -421,22 +428,19 @@
}
}
function renderActionButtons(entry, installedId) {
if (Number(entry)) {
function renderActionButtons(entry) {
if (typeof entry !== 'object') {
entry = $('#' + RESULT_ID_PREFIX + entry);
}
if (!entry) return;
const result = entry._result;
if (typeof installedId === 'number') {
result._installed = installedId > 0;
result._installedStyleId = installedId;
}
const isInstalled = result._installed;
const installedId = result._styleId;
const isInstalled = installedId > 0; // must be boolean for comparisons below
const status = $('.search-result-status', entry).textContent =
isInstalled ? t('clickToUninstall') :
entry.dataset.noImage != null ? t('installButton') :
'';
const notMatching = installedId > 0 && !$entry(installedId);
const notMatching = isInstalled && !$entry(installedId);
if (notMatching !== entry.classList.contains('not-matching')) {
entry.classList.toggle('not-matching');
if (notMatching) {
@ -456,6 +460,7 @@
disabled: notMatching,
});
toggleDataset(entry, 'installed', isInstalled);
toggleDataset(entry, 'customizable', result._styleVars);
}
function renderFullInfo(entry, style) {
@ -469,17 +474,20 @@
textContent: description,
title: description,
});
vars = !isEmptyObj(vars);
entry._result._styleVars = vars;
toggleDataset(entry, 'customizable', vars);
}
function configure() {
const styleEntry = $entry($resultEntry(this).result._installedStyleId);
const styleEntry = $entry($resultEntry(this).result._styleId);
Events.configure.call(this, {target: styleEntry});
}
async function install() {
const {entry, result} = $resultEntry(this);
const {i: id, f: fmt} = result;
const {f: fmt} = result;
const id = rid2id(result.i);
const installButton = $('.search-result-install', entry);
showSpinner(entry);
@ -507,7 +515,7 @@
function uninstall() {
const {entry, result} = $resultEntry(this);
saveScrollPosition(entry);
API.styles.delete(result._installedStyleId);
API.styles.delete(result._styleId);
}
function saveScrollPosition(entry) {
@ -553,10 +561,11 @@
async function fetchIndex() {
const timer = setTimeout(showSpinner, BUSY_DELAY, dom.list);
const jobs = [
[INDEX_URL, json => json.filter(entry => entry.f === 'uso')],
[USW_INDEX_URL, json => json.data],
].map(async ([url, transform]) => {
[INDEX_URL, 'uso', json => json.filter(v => v.f === 'uso')],
[USW_INDEX_URL, 'usw', json => json.data],
].map(async ([url, prefix, transform]) => {
const res = transform(await download(url, {responseType: 'json'}));
for (const v of res) v.i = `${prefix}-${v.i}`;
index = index ? index.concat(res) : res;
if (index !== res) ready = ready.then(start);
});
@ -607,17 +616,4 @@
: b[order] - a[order]
) || b.t - a.t;
}
function calcUsoId({md5Url: m, updateUrl}) {
return Number(m && m.match(/\d+|$/)[0]) ||
URLS.extractUsoArchiveId(updateUrl);
}
function calcUswId({updateUrl}) {
return URLS.extractUSwId(updateUrl) || 0;
}
function calcId(style) {
return calcUsoId(style) || calcUswId(style);
}
})();