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