diff --git a/ext/css/permissions.css b/ext/css/permissions.css new file mode 100644 index 00000000..9a846841 --- /dev/null +++ b/ext/css/permissions.css @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#permissions-origin-list { + display: grid; + grid-template-columns: auto 1fr auto; + grid-template-rows: auto; + align-items: center; + justify-content: center; +} +.permissions-origin-index { + margin: 0 0.5em; +} +input[type=text].permissions-origin-input { + width: auto; + justify-self: stretch; +} +.permissions-origin-button { + justify-self: center; + margin-left: 0.5em; +} diff --git a/ext/js/pages/permissions-main.js b/ext/js/pages/permissions-main.js index 3cf531a6..d36859ec 100644 --- a/ext/js/pages/permissions-main.js +++ b/ext/js/pages/permissions-main.js @@ -17,6 +17,8 @@ /* global * DocumentFocusController + * ModalController + * PermissionsOriginController * PermissionsToggleController * PersistentStorageController * SettingsController @@ -95,12 +97,18 @@ function setupPermissionsToggles() { permissionsCheckboxes[i].checked = permissions[i]; } + const modalController = new ModalController(); + modalController.prepare(); + const settingsController = new SettingsController(0); settingsController.prepare(); const permissionsToggleController = new PermissionsToggleController(settingsController); permissionsToggleController.prepare(); + const permissionsOriginController = new PermissionsOriginController(settingsController); + permissionsOriginController.prepare(); + const persistentStorageController = new PersistentStorageController(); persistentStorageController.prepare(); @@ -108,7 +116,7 @@ function setupPermissionsToggles() { document.documentElement.dataset.loaded = 'true'; - const settingsDisplayController = new SettingsDisplayController(settingsController, null); + const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); settingsDisplayController.prepare(); } catch (e) { log.error(e); diff --git a/ext/js/pages/settings/permissions-origin-controller.js b/ext/js/pages/settings/permissions-origin-controller.js new file mode 100644 index 00000000..adb4c1d9 --- /dev/null +++ b/ext/js/pages/settings/permissions-origin-controller.js @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2021 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +class PermissionsOriginController { + constructor(settingsController) { + this._settingsController = settingsController; + this._originContainer = null; + this._originEmpty = null; + this._originToggleNodes = null; + this._addOriginInput = null; + this._errorContainer = null; + this._originContainerChildren = []; + this._eventListeners = new EventListenerCollection(); + } + + async prepare() { + this._originContainer = document.querySelector('#permissions-origin-list'); + this._originEmpty = document.querySelector('#permissions-origin-list-empty'); + this._originToggleNodes = document.querySelectorAll('.permissions-origin-toggle'); + this._addOriginInput = document.querySelector('#permissions-origin-new-input'); + this._errorContainer = document.querySelector('#permissions-origin-list-error'); + const addButton = document.querySelector('#permissions-origin-add'); + + for (const node of this._originToggleNodes) { + node.addEventListener('change', this._onOriginToggleChange.bind(this), false); + } + addButton.addEventListener('click', this._onAddButtonClick.bind(this), false); + + this._settingsController.on('permissionsChanged', this._onPermissionsChanged.bind(this)); + await this._updatePermissions(); + } + + // Private + + _onPermissionsChanged({permissions}) { + this._eventListeners.removeAllEventListeners(); + for (const node of this._originContainerChildren) { + if (node.parentNode === null) { continue; } + node.parentNode.removeChild(node); + } + this._originContainerChildren = []; + + const originsSet = new Set(permissions.origins); + for (const node of this._originToggleNodes) { + node.checked = originsSet.has(node.dataset.origin); + } + + let any = false; + const excludeOrigins = new Set([ + '' + ]); + const fragment = document.createDocumentFragment(); + for (const origin of permissions.origins) { + if (excludeOrigins.has(origin)) { continue; } + const node = this._settingsController.instantiateTemplateFragment('permissions-origin'); + const input = node.querySelector('.permissions-origin-input'); + const menuButton = node.querySelector('.permissions-origin-button'); + input.value = origin; + this._eventListeners.addEventListener(menuButton, 'menuClose', this._onOriginMenuClose.bind(this, origin), false); + this._originContainerChildren.push(...node.children); + fragment.appendChild(node); + any = true; + } + this._originContainer.insertBefore(fragment, this._originContainer.firstChild); + this._originEmpty.hidden = any; + + this._errorContainer.hidden = true; + } + + _onOriginToggleChange(e) { + const node = e.currentTarget; + const value = node.checked; + node.checked = !value; + + const {origin} = node.dataset; + this._setOriginPermissionEnabled(origin, value); + } + + _onOriginMenuClose(origin) { + this._setOriginPermissionEnabled(origin, false); + } + + _onAddButtonClick() { + this._addOrigin(); + } + + async _addOrigin() { + const origin = this._addOriginInput.value; + const added = await this._setOriginPermissionEnabled(origin, true); + if (added) { + this._addOriginInput.value = ''; + } + } + + async _updatePermissions() { + const permissions = await this._settingsController.permissionsUtil.getAllPermissions(); + this._onPermissionsChanged({permissions}); + } + + async _setOriginPermissionEnabled(origin, enabled) { + let added = false; + try { + added = await this._settingsController.permissionsUtil.setPermissionsGranted({origins: [origin]}, enabled); + } catch (e) { + this._errorContainer.hidden = false; + this._errorContainer.textContent = e.message; + } + if (!added) { return false; } + await this._updatePermissions(); + return true; + } +} diff --git a/ext/permissions.html b/ext/permissions.html index 4aa0fd1f..e5be7219 100644 --- a/ext/permissions.html +++ b/ext/permissions.html @@ -13,6 +13,7 @@ + @@ -175,6 +176,14 @@ +
+
+
Configure allowed origins…
+
+
+ +
+
@@ -182,6 +191,66 @@ + + + + + + + + + + + + + @@ -193,7 +262,12 @@ + + + + +