| import {html, LitElement} from 'lit'; |
| import {customElement, property} from 'lit/decorators.js'; |
| |
| import {DeviceDragZone} from './device-dragzone.js'; |
| import {simulationState} from './device-observer.js'; |
| |
| @customElement('ns-device-dropzone') |
| export class DeviceDropZone extends LitElement { |
| @property({type: String, attribute: 'serial'}) serial: string = ''; |
| |
| @property({type: String, attribute: 'type'}) type: string = ''; |
| |
| constructor() { |
| super(); |
| this.addEventListener('drop', this.handleDrop); |
| this.addEventListener('drag', this.handleDragOver); |
| this.addEventListener('dragenter', DeviceDropZone.handleDragEnter); |
| this.addEventListener('dragleave', DeviceDropZone.handleDragLeave); |
| this.addEventListener('dragover', this.handleDragOver); |
| } |
| |
| static handleDragEnter(ev: DragEvent) { |
| ev.preventDefault(); |
| } |
| |
| static handleDragLeave(ev: DragEvent) { |
| ev.preventDefault(); |
| } |
| |
| slottedDropZone() { |
| // Returns the #dropzone div inside the slotted children, where devices are |
| // stored. note: needs better checking when not the first element. |
| const slot = this.shadowRoot?.querySelector('slot'); |
| return slot?.assignedElements({flatten: true})[0]; |
| } |
| |
| handleDrop(ev: DragEvent) { |
| ev.preventDefault(); |
| const dropzone = this.slottedDropZone(); |
| if (dropzone) { |
| const draggedElement = DeviceDragZone.dragged as HTMLElement; |
| if (ev.dataTransfer?.effectAllowed === 'move') { |
| draggedElement.parentNode?.removeChild(draggedElement); |
| draggedElement.style.opacity = ''; |
| dropzone.appendChild(draggedElement); |
| } else { |
| // copy |
| dropzone.appendChild(draggedElement.cloneNode(true)); |
| } |
| const dropped = dropzone.lastChild as HTMLElement; |
| if (dropped) { |
| const rect = (dropzone as HTMLElement).getBoundingClientRect(); |
| dropped.setAttribute('action', 'move'); |
| dropped.style.position = 'absolute'; |
| dropped.style.left = `${ev.clientX - rect.left}px`; |
| dropped.style.top = `${ev.clientY - rect.top}px`; |
| dropped.style.opacity = `1.0`; |
| // Patch the position of a dropped element |
| let id = dropped.getElementsByTagName('ns-cube-sprite') |
| .item(0) |
| ?.getAttribute('id'); |
| if (id === undefined) { |
| id = dropped.getElementsByTagName('ns-pyramid-sprite') |
| .item(0) |
| ?.getAttribute('id'); |
| } |
| if (id === undefined || id === null) { |
| id = ''; |
| } |
| simulationState.handleDrop( |
| id, (ev.clientX - rect.left) / 100, (ev.clientY - rect.top) / 100); |
| } |
| } |
| } |
| |
| handleDragOver(ev: DragEvent) { |
| ev.preventDefault(); |
| this.slottedDropZone(); |
| } |
| |
| render() { |
| return html`<slot></slot>`; |
| } |
| } |