diff --git a/src/packages/core/sorter/sorter.controller.ts b/src/packages/core/sorter/sorter.controller.ts index dd5201daee..37f501f27d 100644 --- a/src/packages/core/sorter/sorter.controller.ts +++ b/src/packages/core/sorter/sorter.controller.ts @@ -72,16 +72,21 @@ export type resolvePlacementArgs = { pointerY: number; }; +type UniqueType = string | symbol | number; + +/** + * Internal type, which is adjusted to become the public one. + * @internal */ type INTERNAL_UmbSorterConfig = { /** * Define how to retrive the unique identifier of an element. If this method returns undefined, the move will be cancelled. */ - getUniqueOfElement: (element: ElementType) => string | null | symbol | number | undefined; - getUniqueOfModel: (modeEntry: T) => string | null | symbol | number | undefined; + getUniqueOfElement: (element: ElementType) => UniqueType | null | undefined; + getUniqueOfModel: (modeEntry: T) => UniqueType | null | undefined; /** * Optionally define a unique identifier for each sorter experience, all Sorters that uses the same identifier to connect with other sorters. */ - identifier: string | symbol; + identifier: UniqueType; /** * A query selector for the item element. */ @@ -107,6 +112,7 @@ type INTERNAL_UmbSorterConfig = { * The selector to find the draggable element within the item. */ draggableSelector?: string; + //boundarySelector?: string; dataTransferResolver?: (dataTransfer: DataTransfer | null, currentItem: T) => void; onStart?: (argument: { item: T; element: ElementType }) => void; @@ -166,7 +172,7 @@ type INTERNAL_UmbSorterConfig = { performItemRemove?: (argument: { item: T }) => Promise | boolean; }; -// External type with some properties optional, as they have defaults: +// External type with some properties optional, as they have fallback values: export type UmbSorterConfig = Omit< INTERNAL_UmbSorterConfig, 'ignorerSelector' | 'containerSelector' | 'identifier' @@ -178,6 +184,19 @@ export type UmbSorterConfig = * @class UmbSorterController * @implements {UmbControllerInterface} * @description This controller can make user able to sort items. + * @example + * + * This example shows how to setup a sorter controller with no special needs. + * Assuming your declaring this on a Umbraco Element(UmbControllerHostElement): + * + * ```ts + * const sorter = new UmbSorterController(this, { + * itemSelector: '.item', + * containerSelector: '.container', + * getUniqueOfElement: (element) => element.dataset.id, + * getUniqueOfModel: (model) => model.id + * }); + * ``` */ export class UmbSorterController extends UmbControllerBase { // @@ -274,16 +293,13 @@ export class UmbSorterController this.#config.getUniqueOfModel(x) === unique) !== undefined; } - /* - getItem(unique: string) { - if (!unique) return undefined; + getItem(unique: UniqueType) { return this.#model.find((x) => this.#config.getUniqueOfModel(x) === unique); } - */ hostConnected() { this.#isConnected = true; @@ -453,7 +469,7 @@ export class UmbSorterController; + // Notice, it is acceptable here to get index via object reference, but only cause there has been no change at this stage, otherwise we cannot trust the object instance is represented in the model — it could have mutated or been cloned [NL] UmbSorterController.originalIndex = this.#model.indexOf(UmbSorterController.activeItem); if (!UmbSorterController.activeItem) { @@ -478,7 +495,7 @@ export class UmbSorterController) { - const item = UmbSorterController.activeItem; + public async moveItemInModel(newIndex: number, fromCtrl: UmbSorterController) { + if (!UmbSorterController.activeItem) { + console.error('There is no active item to move'); + return false; + } + const itemUnique = this.#config.getUniqueOfModel(UmbSorterController.activeItem); + if (!itemUnique) { + console.error('Failed to retrieve active item unique'); + return false; + } + // We use the getItem method to find the current item/object of this entry, as we cannot trust the object instance(activeItem) to be the same as in the model. [NL] + // So notice, item in this method is the real modal entry reference, where in many other cases we use the activeItem which might not be up to date with the real entry of the model. [NL] + const item = fromCtrl.getItem(itemUnique); if (!item) { - console.error('Could not find item of sync item'); + console.error('Could not find item of model to move', itemUnique, this.#model); return false; } if (this.notifyRequestDrop({ item }) === false) { @@ -819,10 +847,9 @@ export class UmbSorterController, }); this.#config.onChange?.({ model: newModel, item }); - } - // If everything went well, we can set new activeSorter to this: - UmbSorterController.activeSorter = this as unknown as UmbSorterController; - UmbSorterController.activeIndex = newIndex; + // If everything went well, we can set the new activeSorter (and dropSorter) to this, as we are switching container. [NL] + UmbSorterController.activeSorter = this as unknown as UmbSorterController; + UmbSorterController.dropSorter = this as unknown as UmbSorterController; + UmbSorterController.activeIndex = newIndex; + } } return true;