Allow features to require optional permissions
Design doc:
https://docs.google.com/document/d/1OhL0Yh7SmWffXyjW_XVQOK95Fqh7gLltk1eEtnKN8Ds/edit
Fixed: twpowertools:86
Change-Id: Iccb22aac2b285307854b7a4c002e9702c24d57f2
diff --git a/src/options/optionsCommon.js b/src/options/optionsCommon.js
index c76cd6c..b4bb42a 100644
--- a/src/options/optionsCommon.js
+++ b/src/options/optionsCommon.js
@@ -1,10 +1,13 @@
import {getExtVersion, isFirefox, isReleaseVersion} from '../common/extUtils.js';
+import {ensureOptPermissions, grantedOptPermissions, missingPermissions} from '../common/optionsPermissions.js';
import {cleanUpOptions, optionsPrototype, specialOptions} from '../common/optionsUtils.js';
+
import optionsPage from './optionsPage.json5';
var savedSuccessfullyTimeout = null;
const exclusiveOptions = [['thread', 'threadall']];
+const kClickShouldEnableFeat = 'data-click-should-enable-feature';
// Get a URL to a document which is part of the extension documentation (using
// |ref| as the Git ref).
@@ -142,14 +145,25 @@
optionsContainer.append(optionEl);
}
- // Add kill switch component after each option.
+ // Add optional permissions warning label and kill switch component
+ // after each option.
+ let optionalPermissionsWarningLabel = document.createElement('div');
+ optionalPermissionsWarningLabel.classList.add(
+ 'optional-permissions-warning-label');
+ optionalPermissionsWarningLabel.setAttribute('hidden', '');
+ optionalPermissionsWarningLabel.setAttribute(
+ 'data-feature', option.codename);
+ optionalPermissionsWarningLabel.setAttribute(
+ 'data-i18n', 'optionalpermissionswarning_label');
+
let killSwitchComponent = document.createElement('div');
killSwitchComponent.classList.add('kill-switch-label');
killSwitchComponent.setAttribute('hidden', '');
killSwitchComponent.setAttribute('data-feature', option.codename);
killSwitchComponent.setAttribute('data-i18n', 'killswitchenabled');
- optionsContainer.append(killSwitchComponent);
+ optionsContainer.append(
+ optionalPermissionsWarningLabel, killSwitchComponent);
}
}
@@ -178,9 +192,6 @@
document.getElementById('kill-switch-warning')
.removeAttribute('hidden');
}
-
- // TODO(avm99963): show a message above each option that has been force
- // disabled
}
for (var entry of Object.entries(optionsPrototype)) {
@@ -262,6 +273,84 @@
}
}));
});
+
+ // Handle options which need optional permissions.
+ grantedOptPermissions()
+ .then(grantedPerms => {
+ for (const [opt, optMeta] of Object.entries(optionsPrototype)) {
+ if (!optMeta.requiredOptPermissions?.length || !isOptionShown(opt))
+ continue;
+
+ let warningLabel = document.querySelector(
+ '.optional-permissions-warning-label[data-feature="' + opt +
+ '"]');
+
+ // Ensure we have the appropriate permissions when the checkbox
+ // switches from disabled to enabled.
+ //
+ // Also, if the checkbox was indeterminate because the feature was
+ // enabled but not all permissions had been granted, enable the
+ // feature in order to trigger the permission request again.
+ let checkbox = document.getElementById(opt);
+ if (!checkbox) {
+ console.error('Expected checkbox for feature "' + opt + '".');
+ continue;
+ }
+ checkbox.addEventListener('change', () => {
+ if (checkbox.hasAttribute(kClickShouldEnableFeat)) {
+ checkbox.removeAttribute(kClickShouldEnableFeat);
+ checkbox.checked = true;
+ }
+
+ if (checkbox.checked)
+ ensureOptPermissions(opt)
+ .then(granted => {
+ if (granted) {
+ warningLabel.setAttribute('hidden', '');
+ if (!document.querySelector(
+ '.optional-permissions-warning-label:not([hidden])'))
+ document
+ .getElementById('optional-permissions-warning')
+ .setAttribute('hidden', '');
+ } else
+ document.getElementById('blockdrafts').checked = false;
+ })
+ .catch(err => {
+ console.error(
+ 'An error ocurred while ensuring that the optional ' +
+ 'permissions were granted after the checkbox ' +
+ 'was clicked for feature "' + opt + '":',
+ err);
+ document.getElementById('blockdrafts').checked = false;
+ });
+ });
+
+ // Add warning message if some permissions are missing and the
+ // feature is enabled.
+ if (items[opt] === true) {
+ let shownHeaderMessage = false;
+ missingPermissions(opt, grantedPerms)
+ .then(missingPerms => {
+ console.log(missingPerms);
+ if (missingPerms.length > 0) {
+ checkbox.indeterminate = true;
+ checkbox.setAttribute(kClickShouldEnableFeat, '');
+
+ warningLabel.removeAttribute('hidden');
+
+ if (!shownHeaderMessage) {
+ shownHeaderMessage = true;
+ document.getElementById('optional-permissions-warning')
+ .removeAttribute('hidden');
+ }
+ }
+ })
+ .catch(err => console.error(err));
+ }
+ }
+ })
+ .catch(err => console.error(err));
+
document.querySelector('#save').addEventListener('click', save);
});
});