diff --git a/frontend/src/app/shared/helpers/dom-helpers.ts b/frontend/src/app/shared/helpers/dom-helpers.ts index 635c2da2e9e..03991e1fcb0 100644 --- a/frontend/src/app/shared/helpers/dom-helpers.ts +++ b/frontend/src/app/shared/helpers/dom-helpers.ts @@ -243,3 +243,35 @@ export function attributeTokenList(element:HTMLElement, attribute:string):DOMTok return list as DOMTokenList; } /* eslint-enable */ + +/** + * Toggles the enabled/disabled state of form elements. + * For fieldsets, recursively applies to all child elements. + * + * @param element the element to toggle + * @param value force state (optional): `true` to enable/`false` to disable + */ +export function toggleEnabled(element:HTMLElement, value?:boolean) { + if ( + element instanceof HTMLInputElement || + element instanceof HTMLSelectElement || + element instanceof HTMLTextAreaElement || + element instanceof HTMLButtonElement || + element instanceof HTMLFieldSetElement + ) { + if (typeof value === 'undefined') { + element.disabled = !element.disabled; + } else { + element.disabled = !value; + } + } + + if (element instanceof HTMLFieldSetElement) { + Array.from(element.elements).forEach((child) => { + toggleEnabled(child as HTMLElement, !element.disabled); + }); + } +} + +export const enableElement = (element:HTMLElement) => toggleEnabled(element, true); +export const disableElement = (element:HTMLElement) => toggleEnabled(element, false); diff --git a/frontend/src/stimulus/controllers/disable-when-value-selected.controller.ts b/frontend/src/stimulus/controllers/disable-when-value-selected.controller.ts new file mode 100644 index 00000000000..61582c71715 --- /dev/null +++ b/frontend/src/stimulus/controllers/disable-when-value-selected.controller.ts @@ -0,0 +1,69 @@ +/* + * -- copyright + * OpenProject is an open source project management software. + * Copyright (C) the OpenProject GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 3. + * + * OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: + * Copyright (C) 2006-2013 Jean-Philippe Lang + * Copyright (C) 2010-2013 the ChiliProject Team + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * See COPYRIGHT and LICENSE files for more details. + * ++ + */ + +import { toggleEnabled } from 'core-app/shared/helpers/dom-helpers'; +import { ApplicationController } from 'stimulus-use'; + +export default class OpDisableWhenValueSelectedController extends ApplicationController { + static targets = ['cause', 'effect']; + + declare readonly effectTargets:(HTMLInputElement|HTMLFieldSetElement)[]; + + private boundListener = this.toggleDisabled.bind(this); + + causeTargetConnected(target:HTMLElement) { + target.addEventListener('change', this.boundListener); + } + + causeTargetDisconnected(target:HTMLElement) { + target.removeEventListener('change', this.boundListener); + } + + private toggleDisabled(evt:Event):void { + const input = evt.target as HTMLInputElement; + const targetName = input.dataset.targetName; + + this + .effectTargets + .filter((el) => targetName === el.dataset.targetName) + .forEach((el) => { + const disabled = this.willDisable(el, input.value); + toggleEnabled(el, !disabled); + }); + } + + private willDisable(el:HTMLElement, value:string):boolean { + if (el.dataset.notValue) { + return el.dataset.notValue === value; + } + + return !(el.dataset.value === value); + } +} diff --git a/frontend/src/stimulus/setup.ts b/frontend/src/stimulus/setup.ts index 2fa3ac2c098..da140656c9a 100644 --- a/frontend/src/stimulus/setup.ts +++ b/frontend/src/stimulus/setup.ts @@ -2,6 +2,7 @@ import { environment } from '../environments/environment'; import { OpApplicationController } from './controllers/op-application.controller'; import MainMenuController from './controllers/dynamic/menus/main.controller'; import OpDisableWhenCheckedController from './controllers/disable-when-checked.controller'; +import OpDisableWhenValueSelectedController from './controllers/disable-when-value-selected.controller'; import PrintController from './controllers/print.controller'; import RefreshOnFormChangesController from './controllers/refresh-on-form-changes.controller'; import FormPreviewController from './controllers/form-preview.controller'; @@ -57,6 +58,7 @@ OpenProjectStimulusApplication.preregister('application', OpApplicationControlle OpenProjectStimulusApplication.preregister('async-dialog', AsyncDialogController); OpenProjectStimulusApplication.preregister('disable-when-checked', OpDisableWhenCheckedController); OpenProjectStimulusApplication.preregister('disable-when-clicked', DisableWhenClickedController); +OpenProjectStimulusApplication.preregister('disable-when-value-selected', OpDisableWhenValueSelectedController); OpenProjectStimulusApplication.preregister('flash', FlashController); OpenProjectStimulusApplication.preregister('menus--main', MainMenuController); OpenProjectStimulusApplication.preregister('require-password-confirmation', RequirePasswordConfirmationController); diff --git a/modules/webhooks/app/views/webhooks/outgoing/admin/_form.html.erb b/modules/webhooks/app/views/webhooks/outgoing/admin/_form.html.erb index 0cd3804082f..5967756c12d 100644 --- a/modules/webhooks/app/views/webhooks/outgoing/admin/_form.html.erb +++ b/modules/webhooks/app/views/webhooks/outgoing/admin/_form.html.erb @@ -70,7 +70,7 @@ <% end %> -