From 467e7707895a29882b407d6df804596f691488da Mon Sep 17 00:00:00 2001 From: Lone Iversen <108085781+loivsen@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:10:19 +0100 Subject: [PATCH] Feature: Sorter for block grid and list config editor --- ...i-block-grid-type-configuration.element.ts | 37 +++++++++++++++++-- ...i-block-list-type-configuration.element.ts | 16 ++++++-- .../input-block-type.element.ts | 36 +++++++++++++++--- 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-type-configuration/property-editor-ui-block-grid-type-configuration.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-type-configuration/property-editor-ui-block-grid-type-configuration.element.ts index edc11c5282..f8dff44840 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-type-configuration/property-editor-ui-block-grid-type-configuration.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-grid/property-editors/block-grid-type-configuration/property-editor-ui-block-grid-type-configuration.element.ts @@ -35,6 +35,7 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement extends UmbLitElement implements UmbPropertyEditorUiElement { + #moveData?: Array; #sorter = new UmbSorterController(this, { getUniqueOfElement: (element) => element.getAttribute('data-umb-group-key'), getUniqueOfModel: (modelEntry) => modelEntry.key!, @@ -128,13 +129,40 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement this.#sorter.setModel(this._groupsWithBlockTypes); } - #onChange(e: CustomEvent, groupKey?: string) { + #onDelete(e: CustomEvent, groupKey?: string) { const updatedValues = (e.target as UmbInputBlockTypeElement).value.map((value) => ({ ...value, groupKey })); const filteredValues = this.value.filter((value) => value.groupKey !== groupKey); this.value = [...filteredValues, ...updatedValues]; this.dispatchEvent(new UmbPropertyValueChangeEvent()); } + async #onChange(e: CustomEvent) { + e.stopPropagation(); + const element = e.target as UmbInputBlockTypeElement; + const value = element.value; + + if (!e.detail?.moveComplete) { + // Container change, store data of the new group... + const newGroupKey = element.getAttribute('data-umb-group-key'); + const movedItem = e.detail?.item as UmbBlockTypeWithGroupKey; + // Check if item moved back to original group... + movedItem.groupKey === newGroupKey + ? (this.#moveData = undefined) + : (this.#moveData = value.map((block) => ({ ...block, groupKey: newGroupKey }))); + } else if (e.detail?.moveComplete) { + // Move complete, get the blocks that were in an untouched group + const blocks = this.value + .filter((block) => !value.find((value) => value.contentElementTypeKey === block.contentElementTypeKey)) + .filter( + (block) => !this.#moveData?.find((value) => value.contentElementTypeKey === block.contentElementTypeKey), + ); + + this.value = this.#moveData ? [...blocks, ...value, ...this.#moveData] : [...blocks, ...value]; + this.dispatchEvent(new UmbPropertyValueChangeEvent()); + this.#moveData = undefined; + } + } + #onCreate(e: CustomEvent, groupKey?: string) { const selectedElementType = e.detail.contentElementTypeKey; if (selectedElementType) { @@ -170,8 +198,9 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement ? html` this.#onCreate(e, undefined)} - @change=${(e: CustomEvent) => this.#onChange(e, undefined)}>` + @delete=${(e: CustomEvent) => this.#onDelete(e, undefined)}>` : ''} ${repeat( this._groupsWithBlockTypes, @@ -180,10 +209,12 @@ export class UmbPropertyEditorUIBlockGridTypeConfigurationElement html`
${group.key ? this.#renderGroupInput(group.key, group.name) : nothing} this.#onCreate(e, group.key)} - @change=${(e: CustomEvent) => this.#onChange(e, group.key)}> + @delete=${(e: CustomEvent) => this.#onDelete(e, group.key)}>
`, )} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-type-configuration/property-editor-ui-block-list-type-configuration.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-type-configuration/property-editor-ui-block-list-type-configuration.element.ts index 39525dbc90..b49deaecdb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-type-configuration/property-editor-ui-block-list-type-configuration.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/property-editors/block-list-type-configuration/property-editor-ui-block-list-type-configuration.element.ts @@ -3,7 +3,10 @@ import '../../../block-type/components/input-block-type/index.js'; import { UMB_BLOCK_LIST_TYPE } from '../../types.js'; import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry'; import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; +import { + UmbPropertyValueChangeEvent, + type UmbPropertyEditorConfigCollection, +} from '@umbraco-cms/backoffice/property-editor'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal'; @@ -51,14 +54,19 @@ export class UmbPropertyEditorUIBlockListBlockConfigurationElement } } + #onChange(e: CustomEvent) { + e.stopPropagation(); + this.value = (e.target as UmbInputBlockTypeElement).value; + this.dispatchEvent(new UmbPropertyValueChangeEvent()); + } + render() { return html` { - this.value = (e.target as UmbInputBlockTypeElement).value; - }}>`; + @delete=${this.#onChange} + @change=${this.#onChange}>`; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts index 5643b99105..ad408e2314 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-type/components/input-block-type/input-block-type.element.ts @@ -1,20 +1,41 @@ -import type { UmbBlockTypeBaseModel } from '../../types.js'; +import type { UmbBlockTypeCardElement } from '../block-type-card/index.js'; +import type { UmbBlockTypeBaseModel, UmbBlockTypeWithGroupKey } from '../../types.js'; import { UMB_MODAL_MANAGER_CONTEXT, umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import '../block-type-card/index.js'; import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property'; import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; -import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { UmbDeleteEvent } from '@umbraco-cms/backoffice/event'; import { UMB_DOCUMENT_TYPE_PICKER_MODAL } from '@umbraco-cms/backoffice/document-type'; +import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @customElement('umb-input-block-type') export class UmbInputBlockTypeElement< - BlockType extends UmbBlockTypeBaseModel = UmbBlockTypeBaseModel, + BlockType extends UmbBlockTypeWithGroupKey = UmbBlockTypeWithGroupKey, > extends UmbLitElement { + #sorter = new UmbSorterController(this, { + getUniqueOfElement: (element) => element.contentElementTypeKey, + getUniqueOfModel: (modelEntry) => modelEntry.contentElementTypeKey!, + itemSelector: 'umb-block-type-card', + identifier: 'umb-block-type-sorter', + containerSelector: '#blocks', + onChange: ({ model }) => { + this._items = model; + }, + onContainerChange: ({ model, item }) => { + this._items = model; + this.dispatchEvent(new CustomEvent('change', { detail: { item } })); + }, + onEnd: () => { + this.dispatchEvent(new CustomEvent('change', { detail: { moveComplete: true } })); + }, + }); + @property({ type: Array, attribute: false }) public set value(items) { this._items = items ?? []; + this.#sorter.setModel(this._items); } public get value() { return this._items; @@ -67,7 +88,7 @@ export class UmbInputBlockTypeElement< deleteItem(contentElementTypeKey: string) { this.value = this.value.filter((x) => x.contentElementTypeKey !== contentElementTypeKey); - this.dispatchEvent(new UmbChangeEvent()); + this.dispatchEvent(new UmbDeleteEvent()); } protected getFormElement() { @@ -85,7 +106,7 @@ export class UmbInputBlockTypeElement< } render() { - return html`
+ return html`
${repeat(this.value, (block) => block.contentElementTypeKey, this.#renderItem)} ${this.#renderButton()}
`; } @@ -93,6 +114,7 @@ export class UmbInputBlockTypeElement< #renderItem = (block: BlockType) => { return html`