1import {html, LitElement} from 'lit'; 2import {customElement, property} from 'lit/decorators.js'; 3 4import {DeviceDragZone} from './device-dragzone.js'; 5import {simulationState} from './device-observer.js'; 6 7@customElement('ns-device-dropzone') 8export class DeviceDropZone extends LitElement { 9 @property({type: String, attribute: 'serial'}) serial: string = ''; 10 11 @property({type: String, attribute: 'type'}) type: string = ''; 12 13 constructor() { 14 super(); 15 this.addEventListener('drop', this.handleDrop); 16 this.addEventListener('drag', this.handleDragOver); 17 this.addEventListener('dragenter', DeviceDropZone.handleDragEnter); 18 this.addEventListener('dragleave', DeviceDropZone.handleDragLeave); 19 this.addEventListener('dragover', this.handleDragOver); 20 } 21 22 static handleDragEnter(ev: DragEvent) { 23 ev.preventDefault(); 24 } 25 26 static handleDragLeave(ev: DragEvent) { 27 ev.preventDefault(); 28 } 29 30 slottedDropZone() { 31 // Returns the #dropzone div inside the slotted children, where devices are 32 // stored. note: needs better checking when not the first element. 33 const slot = this.shadowRoot?.querySelector('slot'); 34 return slot?.assignedElements({flatten: true})[0]; 35 } 36 37 handleDrop(ev: DragEvent) { 38 ev.preventDefault(); 39 const dropzone = this.slottedDropZone(); 40 if (dropzone) { 41 const draggedElement = DeviceDragZone.dragged as HTMLElement; 42 if (ev.dataTransfer?.effectAllowed === 'move') { 43 draggedElement.parentNode?.removeChild(draggedElement); 44 draggedElement.style.opacity = ''; 45 dropzone.appendChild(draggedElement); 46 } else { 47 // copy 48 dropzone.appendChild(draggedElement.cloneNode(true)); 49 } 50 const dropped = dropzone.lastChild as HTMLElement; 51 if (dropped) { 52 const rect = (dropzone as HTMLElement).getBoundingClientRect(); 53 dropped.setAttribute('action', 'move'); 54 dropped.style.position = 'absolute'; 55 dropped.style.left = `${ev.clientX - rect.left}px`; 56 dropped.style.top = `${ev.clientY - rect.top}px`; 57 dropped.style.opacity = `1.0`; 58 // Patch the position of a dropped element 59 let id = dropped.getElementsByTagName('ns-cube-sprite') 60 .item(0) 61 ?.getAttribute('id'); 62 if (id === undefined) { 63 id = dropped.getElementsByTagName('ns-pyramid-sprite') 64 .item(0) 65 ?.getAttribute('id'); 66 } 67 if (id === undefined || id === null) { 68 id = ''; 69 } 70 simulationState.handleDrop( 71 id, (ev.clientX - rect.left) / 100, (ev.clientY - rect.top) / 100); 72 } 73 } 74 } 75 76 handleDragOver(ev: DragEvent) { 77 ev.preventDefault(); 78 this.slottedDropZone(); 79 } 80 81 render() { 82 return html`<slot></slot>`; 83 } 84} 85