From 68086e542c8b92df30df34f735a2aeb28d4798df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 12 May 2023 13:16:35 +0200 Subject: [PATCH] simplifying property creator inputs --- .../utils/generate-umbraco-alias.function.ts | 8 + src/Umbraco.Web.UI.Client/libs/utils/index.ts | 1 + .../property-settings-modal.element.ts | 188 ++++++++++-------- ...pe-workspace-view-edit-property.element.ts | 2 + 4 files changed, 121 insertions(+), 78 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/libs/utils/generate-umbraco-alias.function.ts diff --git a/src/Umbraco.Web.UI.Client/libs/utils/generate-umbraco-alias.function.ts b/src/Umbraco.Web.UI.Client/libs/utils/generate-umbraco-alias.function.ts new file mode 100644 index 0000000000..597f562c24 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/libs/utils/generate-umbraco-alias.function.ts @@ -0,0 +1,8 @@ +export function generateAlias(text: string) { + //replace all spaces characters with a dash and remove all non-alphanumeric characters, except underscore. Allow a maximum of 1 dashes or underscores in a row. + return text + .replace(/\s+/g, '-') + .replace(/[^a-zA-Z0-9_-]+/g, '') + .replace(/[-_]{2,}/g, (match) => match[0]) + .toLowerCase(); +} diff --git a/src/Umbraco.Web.UI.Client/libs/utils/index.ts b/src/Umbraco.Web.UI.Client/libs/utils/index.ts index ec8b2470c9..2da5e19e0e 100644 --- a/src/Umbraco.Web.UI.Client/libs/utils/index.ts +++ b/src/Umbraco.Web.UI.Client/libs/utils/index.ts @@ -1,3 +1,4 @@ +export * from './generate-umbraco-alias.function'; export * from './umbraco-path'; export * from './udi-service'; export * from './selection-manager'; diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/core/modals/property-settings/property-settings-modal.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/core/modals/property-settings/property-settings-modal.element.ts index 6c79fa2559..932a7a6e54 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/core/modals/property-settings/property-settings-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/core/modals/property-settings/property-settings-modal.element.ts @@ -1,6 +1,6 @@ import { UUIBooleanInputEvent, UUIInputEvent, UUISelectEvent } from '@umbraco-ui/uui'; import { UUITextStyles } from '@umbraco-ui/uui-css'; -import { css, html, nothing } from 'lit'; +import { PropertyValueMap, css, html, nothing } from 'lit'; import { customElement, state } from 'lit/decorators.js'; import { UmbModalContext, @@ -12,6 +12,7 @@ import { import { ManifestPropertyEditorUI } from '@umbraco-cms/backoffice/extensions-registry'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extensions-api'; import { UmbModalBaseElement } from '@umbraco-cms/internal/modal'; +import { generateAlias } from '@umbraco-cms/backoffice/utils'; @customElement('umb-property-settings-modal') // TODO: Could base take a token to get its types?. @@ -20,46 +21,40 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< UmbPropertySettingsModalResult > { @state() private _selectedPropertyEditorUI?: ManifestPropertyEditorUI; - @state() private _selectedPropertyEditorUIAlias = ''; - - @state() private _appearanceIsTop = false; - @state() private _mandatory = false; + @state() private _selectedPropertyEditorId = ''; //TODO: Should these options come from the server? @state() private _customValidationOptions = [ { name: 'No validation', - value: 'no-validation', + value: '', selected: true, }, { name: 'Validate as an email address', - value: 'email', - validation: '[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+', + value: '[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+', }, { name: 'Validate as a number', - value: 'number', - validation: '^[0-9]*$', + value: '^[0-9]*$', }, { name: 'Validate as an URL', - value: 'url', - validation: 'https?://[a-zA-Z0-9-.]+\\.[a-zA-Z]{2,}', + value: 'https?://[a-zA-Z0-9-.]+\\.[a-zA-Z]{2,}', }, { name: '...or enter a custom validation', - value: 'custom', + value: '', }, ]; - @state() private _customValidation = this._customValidationOptions[0]; @state() private _aliasLocked = true; - @state() private _name = ''; - @state() private _alias = ''; #modalContext?: UmbModalContext; + @state() + protected _returnData!: UmbPropertySettingsModalResult; + constructor() { super(); @@ -70,11 +65,34 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< this.#observePropertyEditorUI(); } + connectedCallback(): void { + super.connectedCallback(); + this._returnData = JSON.parse(JSON.stringify(this.data)); + + const regEx = this._returnData.validation?.regEx ?? ''; + const newlySelected = this._customValidationOptions.find((option) => { + option.selected = option.value === regEx; + return option.selected; + }); + if (newlySelected === undefined) { + this._customValidationOptions[4].selected = true; + } + } + + protected firstUpdated(_changedProperties: PropertyValueMap | Map): void { + super.firstUpdated(_changedProperties); + + // TODO: Make a general way to put focus on a input in a modal. (also make sure it only happens if its the top-most-modal.) + requestAnimationFrame(() => { + (this.shadowRoot!.querySelector('#nameInput') as HTMLElement).focus(); + }); + } + #observePropertyEditorUI() { - if (!this._selectedPropertyEditorUIAlias) return; + if (!this._selectedPropertyEditorId) return; this.observe( - umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this._selectedPropertyEditorUIAlias), + umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUI', this._selectedPropertyEditorId), (propertyEditorUI) => { if (!propertyEditorUI) return; @@ -84,15 +102,16 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< } #onCustomValidationChange(event: UUISelectEvent) { - const value = event.target.value; - - this._customValidation = - this._customValidationOptions.find((option) => option.value === value) ?? this._customValidationOptions[0]; + console.log('event.target.value', event.target.value); + const regEx = event.target.value.toString(); + this._returnData.validation!.regEx = regEx; + this.requestUpdate('_returnData'); } #onMandatoryChange(event: UUIBooleanInputEvent) { const value = event.target.checked; - this._mandatory = value; + this._returnData.validation!.mandatory = value; + this.requestUpdate('_returnData'); } #onClose() { @@ -110,65 +129,50 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< const formData = new FormData(form); - const label = this._name || ''; - const alias = this._alias || ''; - const description = formData.get('description')?.toString() || ''; - const propertyEditorUI = this._selectedPropertyEditorUIAlias || undefined; - const labelOnTop = this._appearanceIsTop; - const mandatory = this._mandatory; - const mandatoryMessage = formData.get('mandatory-message')?.toString() || ''; - const pattern = formData.get('pattern')?.toString() || ''; - const patternMessage = formData.get('pattern-message')?.toString() || ''; + this._returnData.dataTypeId = this._selectedPropertyEditorId || undefined; + this._returnData.validation!.mandatoryMessage = formData.get('mandatory-message')?.toString() || ''; - this.modalHandler?.submit({ - label, - alias, - description, - propertyEditorUI, - labelOnTop, - validation: { - mandatory, - mandatoryMessage, - pattern, - patternMessage, - }, - }); + this.modalHandler?.submit(this._returnData); } #onNameChange(event: UUIInputEvent) { //TODO: Generate alias - this._name = event.target.value.toString(); + const oldName = this._returnData.name; + const oldAlias = this._returnData.alias; + this._returnData.name = event.target.value.toString(); if (this._aliasLocked) { - this._alias = this.#generateAlias(this._name); + const expectedOldAlias = generateAlias(oldName ?? ''); + // Only update the alias if the alias matches a generated alias of the old name (otherwise the alias is considered one written by the user.) + if (expectedOldAlias === oldAlias) { + this._returnData.alias = generateAlias(this._returnData.name); + this.requestUpdate('_returnData'); + } } } - // TODO: move this to a helper so we can reuse it across the app - #generateAlias(text: string) { - //replace all spaces characters with a dash and remove all non-alphanumeric characters, except underscore. Allow a maximum of 1 dashes or underscores in a row. - return text - .replace(/\s+/g, '-') - .replace(/[^a-zA-Z0-9_-]+/g, '') - .replace(/[-_]{2,}/g, (match) => match[0]) - .toLowerCase(); - } - #onAliasChange(event: UUIInputEvent) { - const alias = this.#generateAlias(event.target.value.toString()); + const alias = generateAlias(event.target.value.toString()); if (!this._aliasLocked) { - this._alias = alias; + this._returnData.alias = alias; } else { - event.target.value = this._alias; + this._returnData.alias = this.data?.alias; } + this.requestUpdate('_returnData'); } - #onAppearanceChange(event: MouseEvent) { - const target = event.target as HTMLElement; - const alreadySelected = target.classList.contains(this._appearanceIsTop ? 'top' : 'left'); + #setAppearanceNormal() { + const currentValue = this._returnData.appearance?.labelOnTop; + if (currentValue !== true) return; - if (alreadySelected) return; + this._returnData.appearance!.labelOnTop = false; + this.requestUpdate('_returnData'); + } + #setAppearanceTop() { + const currentValue = this._returnData.appearance?.labelOnTop; + if (currentValue === true) return; - this._appearanceIsTop = !this._appearanceIsTop; + this._returnData.appearance!.labelOnTop = true; + this.requestUpdate('_returnData'); } #onOpenPropertyEditorUIPicker() { @@ -181,7 +185,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< modalHandler?.onSubmit().then(({ selection }) => { if (selection.length === 0) return; // TODO: we might should set the alias to null or empty string, if no selection. - this._selectedPropertyEditorUIAlias = selection[0]; + this._selectedPropertyEditorId = selection[0]; this.#observePropertyEditorUI(); }); } @@ -195,10 +199,28 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< this._aliasLocked = !this._aliasLocked; if (this._aliasLocked) { - this._alias = this.#generateAlias(this._name); + this._returnData.alias = generateAlias(this._returnData.alias ?? ''); + this.requestUpdate('_returnData'); } } + #onValidationRegExChange(event: UUIInputEvent) { + const regEx = event.target.value.toString(); + const newlySelected = this._customValidationOptions.find((option) => { + option.selected = option.value === regEx; + return option.selected; + }); + if (newlySelected === undefined) { + this._customValidationOptions[4].selected = true; + } + this._returnData.validation!.regEx = regEx; + this.requestUpdate('_returnData'); + } + #onValidationMessageChange(event: UUIInputEvent) { + this._returnData.validation!.regExMessage = event.target.value.toString(); + this.requestUpdate('_returnData'); + } + render() { return html` @@ -208,22 +230,28 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement<
+ +
''} id="alias-lock" slot="prepend">
- +
${this.#renderPropertyUIPicker()}
@@ -252,9 +280,9 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< #renderAlignLeftIcon() { return html`
''} - class="appearance left ${this._appearanceIsTop ? '' : 'selected'}"> + class="appearance left ${this._returnData.appearance?.labelOnTop ? '' : 'selected'}"> @@ -268,9 +296,9 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< #renderAlignTopIcon() { return html`
''} - class="appearance top ${this._appearanceIsTop ? 'selected' : ''}"> + class="appearance top ${this._returnData.appearance?.labelOnTop ? 'selected' : ''}"> @@ -287,7 +315,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement<
- ${this._mandatory + ${this._returnData.validation?.mandatory ? html` - ${this._customValidation.value !== 'no-validation' + ${this._returnData.validation?.regEx !== '' ? html` - + @change=${this.#onValidationRegExChange} + .value=${this._returnData.validation?.regEx ?? ''}> + ` : nothing} `; } diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts index 57bd0eadde..69c018ec80 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-property.element.ts @@ -51,9 +51,11 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement { this.#modalRegistration = new UmbModalRouteRegistrationController(this, UMB_PROPERTY_SETTINGS_MODAL) .addUniquePaths(['propertyId']) .onSetup(() => { + console.log(this.property); return this.property ?? false; }) .onSubmit((result) => { + console.log(result); this._partialUpdate(result); }) .observeRouteBuilder((routeBuilder) => {