Skip to content

Commit

Permalink
fix(admin-ui): Fix broken image re-ordering drag-drop
Browse files Browse the repository at this point in the history
Fixes #982
  • Loading branch information
michaelbromley committed Jul 12, 2021
1 parent 2445e48 commit e052b25
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,17 @@
</ng-template>

<ng-template #assetList>
<div class="all-assets" [class.compact]="compact" cdkDropListGroup #dlg>
<div class="all-assets" [class.compact]="compact" cdkDropListGroup>
<div
*ngFor="let asset of assets; let index = index"
class="drop-list"
cdkDropList
#dl
cdkDropListOrientation="horizontal"
[cdkDropListData]="index"
[cdkDropListDisabled]="!(updatePermissions | hasPermission)"
[cdkDropListEnterPredicate]="dropListEnterPredicate"
(cdkDropListDropped)="dropListDropped()"
></div>
<div
*ngFor="let asset of assets"
cdkDropList
[cdkDropListDisabled]="!(updatePermissions | hasPermission)"
[cdkDropListEnterPredicate]="dropListEnterPredicate"
(cdkDropListDropped)="dropListDropped()"
(cdkDropListDropped)="dropListDropped($event)"
>
<vdr-dropdown cdkDrag (cdkDragMoved)="dragMoved($event)">
<vdr-dropdown cdkDrag>
<div
class="asset-thumb"
vdrDropdownTrigger
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
display: flex;
flex-wrap: wrap;

.drop-list {
min-width: 60px;
}

.asset-thumb {
margin: 3px;
padding: 0;
Expand All @@ -54,38 +58,16 @@
}

&.compact {
.drop-list {
min-width: 54px;
}
.asset-thumb {
margin: 1px;
border-width: 1px;
}
}
}

.cdk-drag-preview {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
background-color: var(--color-component-bg-100);
opacity: 0.9;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
opacity: 0.8;
width: 60px;
height: 50px;
.asset-thumb {
background-color: var(--color-component-bg-300);
height: 100%;
width: 54px;
}
img {
display: none;
}
}
.all-assets.compact .cdk-drag-placeholder {
width: 50px;
.asset-thumb {
Expand All @@ -104,3 +86,7 @@
.all-assets.cdk-drop-list-dragging vdr-dropdown:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.cdk-drop-list-dragging > *:not(.cdk-drag-placeholder) {
display: none;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CdkDrag, CdkDragMove, CdkDropList, CdkDropListGroup, moveItemInArray } from '@angular/cdk/drag-drop';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { ViewportRuler } from '@angular/cdk/overlay';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Expand All @@ -10,7 +9,6 @@ import {
Input,
Optional,
Output,
ViewChild,
} from '@angular/core';
import {
Asset,
Expand Down Expand Up @@ -41,25 +39,18 @@ export interface AssetChange {
styleUrls: ['./product-assets.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProductAssetsComponent implements AfterViewInit {
export class ProductAssetsComponent {
@Input('assets') set assetsSetter(val: Asset[]) {
// create a new non-readonly array of assets
this.assets = val.slice();
}

@Input() featuredAsset: Asset | undefined;
@HostBinding('class.compact')
@Input()
compact = false;
@Output() change = new EventEmitter<AssetChange>();
@ViewChild('dlg', { static: false, read: CdkDropListGroup }) listGroup: CdkDropListGroup<CdkDropList>;
@ViewChild('dl', { static: false, read: CdkDropList }) placeholder: CdkDropList;

public target: CdkDropList | null;
public targetIndex: number;
public source: CdkDropList | null;
public sourceIndex: number;
public dragIndex: number;
public activeContainer;
public assets: Asset[] = [];

private readonly updateCollectionPermissions = [Permission.UpdateCatalog, Permission.UpdateCollection];
Expand All @@ -80,15 +71,6 @@ export class ProductAssetsComponent implements AfterViewInit {
@Optional() private collectionDetailComponent?: CollectionDetailComponent,
) {}

ngAfterViewInit() {
const phElement = this.placeholder.element.nativeElement;

phElement.style.display = 'none';
if (phElement.parentElement) {
phElement.parentElement.removeChild(phElement);
}
}

selectAssets() {
this.modalService
.fromComponent(AssetPickerDialogComponent, {
Expand Down Expand Up @@ -140,114 +122,8 @@ export class ProductAssetsComponent implements AfterViewInit {
});
}

dragMoved(e: CdkDragMove) {
const point = this.getPointerPositionOnPage(e.event);

this.listGroup._items.forEach(dropList => {
if (__isInsideDropListClientRect(dropList, point.x, point.y)) {
this.activeContainer = dropList;
return;
}
});
}

dropListDropped() {
if (!this.target || !this.source) {
return;
}

const phElement = this.placeholder.element.nativeElement;
// tslint:disable-next-line:no-non-null-assertion
const parent = phElement.parentElement!;

phElement.style.display = 'none';

parent.removeChild(phElement);
parent.appendChild(phElement);
parent.insertBefore(this.source.element.nativeElement, parent.children[this.sourceIndex]);

this.target = null;
this.source = null;

if (this.sourceIndex !== this.targetIndex) {
moveItemInArray(this.assets, this.sourceIndex, this.targetIndex);
this.emitChangeEvent(this.assets, this.featuredAsset);
}
}

dropListEnterPredicate = (drag: CdkDrag, drop: CdkDropList) => {
if (drop === this.placeholder) {
return true;
}
if (drop !== this.activeContainer) {
return false;
}

const phElement = this.placeholder.element.nativeElement;
const sourceElement = drag.dropContainer.element.nativeElement;
const dropElement = drop.element.nativeElement;
const children = dropElement.parentElement && dropElement.parentElement.children;

const dragIndex = __indexOf(children, this.source ? phElement : sourceElement);
const dropIndex = __indexOf(children, dropElement);

if (!this.source) {
this.sourceIndex = dragIndex;
this.source = drag.dropContainer;

phElement.style.width = sourceElement.clientWidth + 'px';
phElement.style.height = sourceElement.clientHeight + 'px';

if (sourceElement.parentElement) {
sourceElement.parentElement.removeChild(sourceElement);
}
}

this.targetIndex = dropIndex;
this.target = drop;

phElement.style.display = '';
if (dropElement.parentElement) {
dropElement.parentElement.insertBefore(
phElement,
dropIndex > dragIndex ? dropElement.nextSibling : dropElement,
);
}

this.placeholder._dropListRef.enter(
drag._dragRef,
drag.element.nativeElement.offsetLeft,
drag.element.nativeElement.offsetTop,
);
return false;
};

/** Determines the point of the page that was touched by the user. */
getPointerPositionOnPage(event: MouseEvent | TouchEvent) {
// `touches` will be empty for start/end events so we have to fall back to `changedTouches`.
const point = __isTouchEvent(event) ? event.touches[0] || event.changedTouches[0] : event;
const scrollPosition = this.viewportRuler.getViewportScrollPosition();

return {
x: point.pageX - scrollPosition.left,
y: point.pageY - scrollPosition.top,
};
}
}

function __indexOf(collection: HTMLCollection | null, node: HTMLElement) {
if (!collection) {
return -1;
dropListDropped(event: CdkDragDrop<number>) {
moveItemInArray(this.assets, event.previousContainer.data, event.container.data);
this.emitChangeEvent(this.assets, this.featuredAsset);
}
return Array.prototype.indexOf.call(collection, node);
}

/** Determines whether an event is a touch event. */
function __isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
return event.type.startsWith('touch');
}

function __isInsideDropListClientRect(dropList: CdkDropList, x: number, y: number) {
const { top, bottom, left, right } = dropList.element.nativeElement.getBoundingClientRect();
return y >= top && y <= bottom && x >= left && x <= right;
}

0 comments on commit e052b25

Please sign in to comment.