diff --git a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts index 687d43b378..31c27ccd55 100644 --- a/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts +++ b/src/Umbraco.Web.UI.Client/libs/sorter/sorter.controller.ts @@ -122,7 +122,7 @@ export class UmbSorterController implements UmbControllerInterface { #model: Array = []; #rqaId?: number; - #containerElement!: Element; + #containerElement!: HTMLElement; #currentContainerVM = this; #currentContainerElement: Element | null = null; @@ -146,7 +146,7 @@ export class UmbSorterController implements UmbControllerInterface { // Set defaults: config.ignorerSelector ??= 'a, img, iframe'; - config.placeholderClass ??= 'umb-drag-placeholder'; + config.placeholderClass ??= '--umb-sorter-placeholder'; this.#config = config as INTERNAL_UmbSorterConfig; host.addController(this); @@ -167,8 +167,6 @@ export class UmbSorterController implements UmbControllerInterface { }); }); }); - - host.addEventListener('dragover', preventDragOver); } setModel(model: Array) { @@ -179,29 +177,46 @@ export class UmbSorterController implements UmbControllerInterface { } hostConnected() { + requestAnimationFrame(this._onFirstRender); + } + private _onFirstRender = () => { const containerEl = - (this.#config.containerSelector ? this.#host.querySelector(this.#config.containerSelector) : this.#host) ?? - this.#host; - - (containerEl as any)['__umbBlockGridSorterController'] = () => { - return this; - }; + (this.#config.containerSelector + ? this.#host.shadowRoot!.querySelector(this.#config.containerSelector) + : this.#host) ?? this.#host; if (this.#currentContainerElement === this.#containerElement) { this.#currentContainerElement = containerEl; } - this.#containerElement = containerEl; + this.#containerElement = containerEl as HTMLElement; + this.#containerElement.addEventListener('dragover', preventDragOver); + + (this.#containerElement as any)['__umbBlockGridSorterController'] = () => { + return this; + }; + + console.log('containerEl', this.#containerElement.shadowRoot ?? this.#containerElement); // TODO: Clean up?? this.#observer.disconnect(); - this.#observer.observe(this.#containerElement.shadowRoot ?? this.#containerElement, { + + const containerElement = this.#containerElement.shadowRoot ?? this.#containerElement; + containerElement.querySelectorAll(this.#config.itemSelector).forEach((child) => { + if (child.matches && child.matches(this.#config.itemSelector)) { + this.setupItem(child as HTMLElement); + } + }); + this.#observer.observe(containerElement, { childList: true, subtree: false, }); - } + }; hostDisconnected() { // TODO: Clean up?? this.#observer.disconnect(); + (this.#containerElement as any)['__umbBlockGridSorterController'] = undefined; + this.#containerElement.removeEventListener('dragover', preventDragOver); + (this.#containerElement as any) = undefined; } setupItem(element: HTMLElement) { @@ -316,14 +331,14 @@ export class UmbSorterController implements UmbControllerInterface { const movingItemIndex = this.#model.indexOf(this.#currentItem); if (movingItemIndex < this.#model.length - 1) { const afterItem = this.#model[movingItemIndex + 1]; - const afterEl = this.#config.querySelectModelToElement(this.#host, afterItem); + const afterEl = this.#config.querySelectModelToElement(this.#containerElement, afterItem); if (afterEl) { - this.#host.insertBefore(this.#currentElement, afterEl); + this.#containerElement.insertBefore(this.#currentElement, afterEl); } else { - this.#host.appendChild(this.#currentElement); + this.#containerElement.appendChild(this.#currentElement); } } else { - this.#host.appendChild(this.#currentElement); + this.#containerElement.appendChild(this.#currentElement); } } @@ -406,6 +421,7 @@ export class UmbSorterController implements UmbControllerInterface { // we are outside the current container boundary, so lets see if there is a parent we can move. const parentNode = this.#currentContainerElement.parentNode; if (parentNode) { + // TODO: support multiple parent shadowDOMs? const parentContainer = this.#config.containerSelector ? (parentNode as HTMLElement).closest(this.#config.containerSelector) : null; @@ -429,8 +445,8 @@ export class UmbSorterController implements UmbControllerInterface { // We want to retrieve the children of the container, every time to ensure we got the right order and index const orderedContainerElements = Array.from( this.#currentContainerElement.shadowRoot - ? this.#currentContainerElement.shadowRoot.children - : this.#currentContainerElement.children + ? this.#currentContainerElement.shadowRoot.querySelectorAll(this.#config.itemSelector) + : this.#currentContainerElement.querySelectorAll(this.#config.itemSelector) ); const currentContainerRect = this.#currentContainerElement.getBoundingClientRect(); @@ -478,6 +494,7 @@ export class UmbSorterController implements UmbControllerInterface { // If we are inside the found element, lets look for sub containers. // use the itemHasNestedContainersResolver, if not configured fallback to looking for the existence of a container via DOM. + // TODO: Ability to look into shadowDOMs for sub containers? if ( isInsideFound && this.#config.itemHasNestedContainersResolver ? this.#config.itemHasNestedContainersResolver(foundEl) @@ -669,6 +686,13 @@ export class UmbSorterController implements UmbControllerInterface { let newIndex = this.#model.length; + const movingItemIndex = this.#model.indexOf(movingItem); + + console.log('this.#model', this.#model, movingItemIndex); + + if (movingItemIndex !== -1 && movingItemIndex <= movingItemIndex) { + newIndex--; + } if (nextEl) { // We had a reference element, we want to get the index of it. // This is might a problem if a item is being moved forward? (was also like this in the AngularJS version...) @@ -806,9 +830,6 @@ export class UmbSorterController implements UmbControllerInterface { this._lastIndicationContainerVM = null; - (this.#host as any)['__umbBlockGridSorterController'] = null; - this.#host.removeEventListener('dragover', preventDragOver); - // TODO: Clean up items?? this.#observer.disconnect(); diff --git a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 185044e267..f000b6917b 100644 --- a/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/backoffice/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -21,6 +21,7 @@ const SORTER_CONFIG: UmbSorterConfig = { identifier: 'content-type-property-sorter', itemSelector: '[data-umb-property-id]', disabledItemSelector: ':not([data-property-of-owner-document])', + containerSelector: '#property-list', }; @customElement('umb-document-type-workspace-view-edit-properties') export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitElement { @@ -31,7 +32,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle if (this._propertyStructure.length > 0) { console.log('args.newIndex', args.newIndex); if (args.newIndex === 0) { - // TODO: Remove as any when sortOrder is added to the model: + // TODO: Remove 'as any' when sortOrder is added to the model: sortOrder = ((this._propertyStructure[0] as any).sortOrder ?? 0) - 1; } else { sortOrder = @@ -39,11 +40,9 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle 0) + 1; } } - console.log('insert', args.item.id, sortOrder); return this._propertyStructureHelper.insertProperty(args.item, sortOrder); }, performItemRemove: (args) => { - console.log('remove', args.item.id); return this._propertyStructureHelper.removeProperty(args.item.id!); }, }); @@ -109,36 +108,29 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle } render() { - return html`${repeat( - this._propertyStructure, - (property) => property.alias ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', - (property) => - html` { - this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); - }}>` - )} Add property `; + return html`
+ ${repeat( + this._propertyStructure, + (property) => property.alias ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', + (property) => + html` { + this._propertyStructureHelper.partialUpdateProperty(property.id, event.detail); + }}>` + )} +
+ Add property `; } static styles = [ UUITextStyles, css` - .property:first-of-type { - padding-top: 0; - } - .property { - border-bottom: 1px solid var(--uui-color-divider); - } - .property:last-child { - border-bottom: 0; - } - #add { width: 100%; } 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 9e08199e49..2739bc0508 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 @@ -81,9 +81,27 @@ export class UmbDocumentTypeWorkspacePropertyElement extends LitElement { border-bottom: none; } - :host-context(umb-variantable-property:first-of-type) { + :host(:first-of-type) { padding-top: 0; } + :host([data-property-of-owner-document]) { + cursor: grab; + } + + // PLaceholder style, used when property is being dragged. + :host(.--umb-sorter-placeholder) { + height: 2px; + } + :host(.--umb-sorter-placeholder) > div { + display: none; + } + :host(.--umb-sorter-placeholder)::after { + content: ''; + display:block: + grid-column: span 2; + width: 100%; + border-top: 2px solid blue; + } p { margin-bottom: 0;