stylus/options/options.js

109 lines
3.0 KiB
JavaScript
Raw Permalink Normal View History

/* global API */// msg.js
/* global prefs */
/* global t */// localization.js
2022-09-05 20:08:03 +00:00
/* global $ $$ $create getEventKeyName messageBoxProxy setInputValue setupLivePrefs */// dom.js
/* global
CHROME_POPUP_BORDER_BUG
FIREFOX
URLS
clamp
ignoreChromeError
openURL
*/// toolbox.js
2017-02-14 15:35:53 +00:00
'use strict';
setupLivePrefs();
$$('input[min], input[max]').forEach(enforceInputRange);
if (CHROME_POPUP_BORDER_BUG) {
$('.chrome-no-popup-border').classList.remove('chrome-no-popup-border');
}
2018-04-12 18:02:34 +00:00
if (FIREFOX && 'update' in (chrome.commands || {})) {
$('#shortcuts').classList.remove('chromium-only');
}
2017-02-14 15:35:53 +00:00
// actions
$('#options-close-icon').onclick = () => {
top.dispatchEvent(new CustomEvent('closeOptions'));
};
$('#manage').onclick = () => {
API.openManage();
};
$('#shortcuts').onclick = () => {
if (FIREFOX) {
customizeHotkeys();
} else {
openURL({url: URLS.configureCommands});
}
};
$('#reset').onclick = async () => {
if (await messageBoxProxy.confirm(t('confirmDiscardChanges'))) {
for (const el of $$('input')) {
const id = el.id || el.name;
if (prefs.knownKeys.includes(id)) {
prefs.reset(id);
}
}
Add: sync database to a cloud drive (#787) * Add key * Add: a second index uuid, push changes to sync controller * Add: sync.js * Add: tokenManager * Change: log entire body for http error * Add: token flow * Fix: minor * Fix: move cleanup to stop function * Add: syncNow * Update dependencies * Fix: handle 401 error * Add: handle 401 error * Fix: then -> catch * Add: sync options to options page * Update db-to-cloud * Change: make prefs.set return a promise * Add: disble selector if connected * Add: update selector state * Fix: return promise in prefs.set * Fix: manage complex state * Fix: handle prefs change * Change: manage sync status in background * Add: show current status in the UI * Add: schedule a faster sync when db changed * Update dependencies * Add: include progress in sync status * Add: more detail status * Show status text only * Bump dependencies * Change: show loaded and total * Fix: syncTarget is undefined * Add: google and onedrive * Fix: token is not reused * Bump dependencies * Don't use minified version since it is hard to debug * Fix: expire time is incorrect * Change: switch google to code flow * Bump dependencies * Change: only modify pref if the initialization success? * Don't stop the sync if the first sync is not triggered by the user * Add: implement refresh token * Change: switch microsoft to code flow * Add: subtract expire with a latency * Add: microsoft client secret * Add: display error message * Fix: fromPref is not used * Change: try to revoke the token when log out * Add: revoke dropbox token * Fix: Google only generates one refresh token for one user by default * Bump dependencies, fix onedrive list issue * Fix: arguments sent to sync.put is wrong * Fix: don't schedule a sync on db changed if not connected * Bump dependencies. Fix issue of switching drives * Bump db-to-cloud, fix switching drive issue * Fix: only auth user on 401 error, don't display login window without user interaction * Fix: don't call revoke() if token is undefined * Add: login button to generate the access token interactively * Fix: make addMissingProperties a local * Fix: store missing props in an object * Fix: sync.getStatus should be sync * LATENCY -> NETWORK_LATENCY * Fix: cache the token forever if there is no expire time e.g. dropbox * Add some comments * Fix: i18n * Fix: i18n sync status * fixup! Fix: i18n sync status * Fix: 'sync to cloud' is displayed twice
2019-11-05 19:30:45 +00:00
}
};
2022-09-05 20:08:03 +00:00
$$('[data-clickable]').forEach(el => {
const input = $('input', el.closest('label'));
const value = el.dataset.clickable;
const rx = new RegExp(`\\b(${value})\\b`, 'g');
const onclick = () => setInputValue(input, value);
const parts = elementize(el.textContent, rx, s => $create('span.clickable', {onclick}, s));
el.firstChild.replaceWith(...parts);
});
2017-06-28 10:49:04 +00:00
2018-04-12 18:02:34 +00:00
function customizeHotkeys() {
messageBoxProxy.show({
2018-04-12 18:02:34 +00:00
title: t('shortcutsNote'),
contents: t.template.shortcutsFF.cloneNode(true),
className: 'center-dialog pre-line',
2018-04-12 18:02:34 +00:00
buttons: [t('confirmClose')],
onshow(box) {
box.oninput = onInput;
setupLivePrefs($$('input', box).map(el => el.id));
2018-04-12 18:02:34 +00:00
},
});
async function onInput({target: el}) {
const name = el.id.split('.')[1];
const shortcut = el.value.trim();
if (!shortcut) {
browser.commands.reset(name).catch(ignoreChromeError);
el.setCustomValidity('');
2018-04-12 18:02:34 +00:00
return;
}
try {
await browser.commands.update({name, shortcut});
el.setCustomValidity('');
2018-04-12 18:02:34 +00:00
} catch (err) {
el.setCustomValidity(err);
2018-04-12 18:02:34 +00:00
}
}
}
2022-09-05 20:08:03 +00:00
function elementize(str, rx, cb) {
return str.split(rx).map((s, i) => i % 2 ? cb(s) : s).filter(Boolean);
}
function enforceInputRange(element) {
const min = Number(element.min);
const max = Number(element.max);
const doNotify = () => element.dispatchEvent(new Event('change', {bubbles: true}));
const onChange = ({type}) => {
if (type === 'input' && element.checkValidity()) {
doNotify();
} else if (type === 'change' && !element.checkValidity()) {
element.value = clamp(Number(element.value), min, max);
doNotify();
}
};
element.on('change', onChange);
element.on('input', onChange);
}
window.onkeydown = event => {
if (getEventKeyName(event) === 'Escape') {
top.dispatchEvent(new CustomEvent('closeOptions'));
}
};