Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2022-09-14 17:39:00 +0300
committerJoas Schilling <coding@schilljs.com>2022-09-15 11:52:55 +0300
commit7672152579447d1cc465a41d1b90004045236c29 (patch)
tree22d4820a12befb8d17357714ad82d424e3ecff06 /apps/theming
parent4c1f06170e1f7256bdc0791c40359c5ab6ad5eda (diff)
Add a global setting to disable keyboard shortcuts
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'apps/theming')
-rw-r--r--apps/theming/lib/AppInfo/Application.php5
-rw-r--r--apps/theming/lib/Listener/BeforePreferenceListener.php56
-rw-r--r--apps/theming/lib/Listener/BeforeTemplateRenderedListener.php13
-rw-r--r--apps/theming/src/UserThemes.vue51
4 files changed, 124 insertions, 1 deletions
diff --git a/apps/theming/lib/AppInfo/Application.php b/apps/theming/lib/AppInfo/Application.php
index 0f567b4d0e4..48bf42252c7 100644
--- a/apps/theming/lib/AppInfo/Application.php
+++ b/apps/theming/lib/AppInfo/Application.php
@@ -25,12 +25,15 @@
namespace OCA\Theming\AppInfo;
use OCA\Theming\Capabilities;
+use OCA\Theming\Listener\BeforePreferenceListener;
use OCA\Theming\Listener\BeforeTemplateRenderedListener;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
+use OCP\Config\BeforePreferenceDeletedEvent;
+use OCP\Config\BeforePreferenceSetEvent;
class Application extends App implements IBootstrap {
public const APP_ID = 'theming';
@@ -42,6 +45,8 @@ class Application extends App implements IBootstrap {
public function register(IRegistrationContext $context): void {
$context->registerCapability(Capabilities::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
+ $context->registerEventListener(BeforePreferenceSetEvent::class, BeforePreferenceListener::class);
+ $context->registerEventListener(BeforePreferenceDeletedEvent::class, BeforePreferenceListener::class);
}
public function boot(IBootContext $context): void {
diff --git a/apps/theming/lib/Listener/BeforePreferenceListener.php b/apps/theming/lib/Listener/BeforePreferenceListener.php
new file mode 100644
index 00000000000..a1add86e600
--- /dev/null
+++ b/apps/theming/lib/Listener/BeforePreferenceListener.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Theming\Listener;
+
+use OCA\Theming\AppInfo\Application;
+use OCP\Config\BeforePreferenceDeletedEvent;
+use OCP\Config\BeforePreferenceSetEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+class BeforePreferenceListener implements IEventListener {
+ public function handle(Event $event): void {
+ if (!$event instanceof BeforePreferenceSetEvent
+ && !$event instanceof BeforePreferenceDeletedEvent) {
+ return;
+ }
+
+ if ($event->getAppId() !== Application::APP_ID) {
+ return;
+ }
+
+ if ($event->getConfigKey() !== 'shortcuts_disabled') {
+ return;
+ }
+
+ if ($event instanceof BeforePreferenceSetEvent) {
+ $event->setValid($event->getConfigValue() === 'yes');
+ return;
+ }
+
+ $event->setValid(true);
+ }
+}
diff --git a/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php b/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php
index d6e00b927ae..1d28a1d4399 100644
--- a/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php
+++ b/apps/theming/lib/Listener/BeforeTemplateRenderedListener.php
@@ -29,6 +29,8 @@ use OCA\Theming\AppInfo\Application;
use OCA\Theming\Service\BackgroundService;
use OCA\Theming\Service\JSDataService;
use OCA\Theming\Service\ThemeInjectionService;
+use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
+use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
@@ -64,6 +66,17 @@ class BeforeTemplateRenderedListener implements IEventListener {
fn () => $this->container->get(JSDataService::class),
);
+ /** @var BeforeTemplateRenderedEvent $event */
+ if ($event->getResponse()->getRenderAs() === TemplateResponse::RENDER_AS_USER) {
+ $this->initialState->provideLazyInitialState('shortcutsDisabled', function () {
+ if ($this->userSession->getUser()) {
+ $uid = $this->userSession->getUser()->getUID();
+ return $this->config->getUserValue($uid, Application::APP_ID, 'shortcuts_disabled', 'no') === 'yes';
+ }
+ return false;
+ });
+ }
+
$this->themeInjectionService->injectHeaders();
$user = $this->userSession->getUser();
diff --git a/apps/theming/src/UserThemes.vue b/apps/theming/src/UserThemes.vue
index c886394136a..da4495158f3 100644
--- a/apps/theming/src/UserThemes.vue
+++ b/apps/theming/src/UserThemes.vue
@@ -23,7 +23,9 @@
<template>
<section>
- <NcSettingsSection class="theming" :title="t('theming', 'Appearance and accessibility')">
+ <NcSettingsSection :title="t('theming', 'Appearance and accessibility')"
+ :limit-width="false"
+ class="theming">
<p v-html="description" />
<p v-html="descriptionDetail" />
@@ -48,6 +50,18 @@
@change="changeFont" />
</div>
</NcSettingsSection>
+
+ <NcSettingsSection :title="t('theming', 'Keyboard shortcuts')">
+ <p>{{ t('theming', 'In some cases keyboard shortcuts can interfer with accessibility tools. In order to allow focusing on your tool correctly you can disable all keyboard shortcuts here. This will also disable all available shortcuts in apps.') }}</p>
+ <NcCheckboxRadioSwitch class="theming__preview-toggle"
+ :checked.sync="shortcutsDisabled"
+ name="shortcuts_disabled"
+ type="switch"
+ @change="changeShortcutsDisabled">
+ {{ t('theming', 'Disable all keyboard shortcuts') }}
+ </NcCheckboxRadioSwitch>
+ </NcSettingsSection>
+
<NcSettingsSection :title="t('theming', 'Background')"
class="background">
<p>{{ t('theming', 'Set a custom background') }}</p>
@@ -63,6 +77,7 @@
import { generateOcsUrl, imagePath } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
import axios from '@nextcloud/axios'
+import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch'
import NcSettingsSection from '@nextcloud/vue/dist/Components/NcSettingsSection'
import BackgroundSettings from './components/BackgroundSettings.vue'
@@ -72,6 +87,7 @@ import { getBackgroundUrl } from '../src/helpers/getBackgroundUrl.js'
const availableThemes = loadState('theming', 'themes', [])
const enforceTheme = loadState('theming', 'enforceTheme', '')
+const shortcutsDisabled = loadState('theming', 'shortcutsDisabled', false)
const background = loadState('theming', 'background')
const backgroundVersion = loadState('theming', 'backgroundVersion')
@@ -84,6 +100,7 @@ export default {
name: 'UserThemes',
components: {
ItemPreview,
+ NcCheckboxRadioSwitch,
NcSettingsSection,
BackgroundSettings,
},
@@ -92,6 +109,7 @@ export default {
return {
availableThemes,
enforceTheme,
+ shortcutsDisabled,
background,
themingDefaultBackground,
}
@@ -151,9 +169,17 @@ export default {
return '<a target="_blank" href="https://nextcloud.com/design" rel="noreferrer nofollow">'
},
},
+
mounted() {
this.updateGlobalStyles()
},
+
+ watch: {
+ shortcutsDisabled(newState) {
+ this.changeShortcutsDisabled(newState)
+ },
+ },
+
methods: {
updateBackground(data) {
this.background = (data.type === 'custom' || data.type === 'default') ? data.type : data.value
@@ -212,6 +238,29 @@ export default {
this.selectItem(enabled, id)
},
+ async changeShortcutsDisabled(newState) {
+ if (newState) {
+ await axios({
+ url: generateOcsUrl('apps/provisioning_api/api/v1/config/users/{appId}/{configKey}', {
+ appId: 'theming',
+ configKey: 'shortcuts_disabled',
+ }),
+ data: {
+ configValue: 'yes',
+ },
+ method: 'POST',
+ })
+ } else {
+ await axios({
+ url: generateOcsUrl('apps/provisioning_api/api/v1/config/users/{appId}/{configKey}', {
+ appId: 'theming',
+ configKey: 'shortcuts_disabled',
+ }),
+ method: 'DELETE',
+ })
+ }
+ },
+
updateBodyAttributes() {
const enabledThemesIDs = this.themes.filter(theme => theme.enabled === true).map(theme => theme.id)
const enabledFontsIDs = this.fonts.filter(font => font.enabled === true).map(font => font.id)