class HippieTaskBar { constructor(element, placeholder, options) { this.element = element; this.placeholder = placeholder; this.date = null; this.offsetX = 0; this.offsetY = 0; this.isDragging = false; this.barSize = '64px'; // TODO: Erweitern auf allgemeine Möglichkeiten und dann aus JSON-Datei laden this.options = options || { direction: 0, date: { year: 'numeric', month: '2-digit', day: '2-digit' } }; this.init(); } // TODO: Ereignisse besser delegieren init() { this.element.addEventListener('mousedown', this.onMouseDown.bind(this)); document.addEventListener('mousemove', this.onMouseMove.bind(this)); document.addEventListener('mouseup', this.onMouseUp.bind(this)); const dateElement = document.createElement('span'); dateElement.id = 'date'; this.element.querySelector('.clock').appendChild(dateElement); this.date = new DateDisplay(dateElement, this.options.date); this.setOptions('bottom'); } onMouseDown(event) { if (checkButtonAndTarget(event, this.element, 0)) { console.debug('Drag mode enabled'); this.isDragging = true; // TODO: Platzhalter anpassen je nach Ziel this.showPlaceholder(); this.offsetX = this.placeholder.getBoundingClientRect().width / 2; this.offsetY = this.placeholder.getBoundingClientRect().height / 2; let x = event.clientX - this.offsetX; let y = event.clientY - this.offsetY; this.placeholder.style.left = `${x}px`; this.placeholder.style.top = `${y}px`; } event.preventDefault(); } onMouseMove(event) { if (this.isDragging) { if (!this.isDragging) return; let x = event.clientX - this.offsetX; let y = event.clientY - this.offsetY; console.debug('Position: ', x, y); this.placeholder.style.left = `${x}px`; this.placeholder.style.top = `${y}px`; } } onMouseUp() { if (event.target === this.placeholder) { console.debug('Drag mode disabled'); if (!this.isDragging) return; this.isDragging = false; this.snapToEdges(); this.hidePlaceholder(); } } showPlaceholder() { this.element.style.display = 'none'; this.placeholder.style.display = 'block'; } hidePlaceholder() { this.placeholder.style.display = 'none'; this.element.style.display = ''; } // TODO: Prüfung auf Ziel auslagern und schon bei Mausbewegung verfügbar machen snapToEdges() { const rect = this.placeholder.getBoundingClientRect(); const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const distances = { top: rect.top, right: windowWidth - rect.right, bottom: windowHeight - rect.bottom, left: rect.left }; const closestEdge = Object.keys(distances).reduce((a, b) => distances[a] < distances[b] ? a : b); this.setOptions(closestEdge); this.date.changeFormat(this.options.date, this.options.direction); } setOptions(position) { const attributes = { top: { className: 'top', styles: { top: '0', right: '0', bottom: '', left: '0', width: '', height: this.barSize, flexDirection: 'row' } }, right: { className: 'right', styles: { top: '0', right: '0', bottom: '0', left: '', width: this.barSize, height: '', flexDirection: 'column' } }, bottom: { className: 'bottom', styles: { top: '', right: '0', bottom: '0', left: '0', width: '', height: this.barSize, flexDirection: 'row' } }, left: { className: 'left', styles: { top: '0', right: '', bottom: '0', left: '0', width: this.barSize, height: '', flexDirection: 'column' } } }; this.element.classList.remove(...Object.values(attributes).map(pos => pos.className)); Object.keys(attributes[position].styles).forEach(key => { this.element.style[key] = ''; }); this.element.classList.add(attributes[position].className); Object.entries(attributes[position].styles).forEach(([key, value]) => { this.element.style[key] = value; }); switch (position) { case 'right': case 'left': this.options.date = {year: '2-digit', month: '2-digit', day: '2-digit'}; this.options.direction = 1; break; case 'top': case 'bottom': default: this.options.date = {year: 'numeric', month: '2-digit', day: '2-digit'}; this.options.direction = 0; break; } } }