photo Draggable Modals

javascript class DraggableModal


class DraggableModal {
  constructor(modalId, recipientAttribute) {
    this.modal = document.getElementById(modalId);
    this.modalContent = this.modal.querySelector('.modal-content');
    this.modalHeader = this.modal.querySelector('.modal-header');
    this.isDragging = false;
    this.startX = 0;
    this.startY = 0;
    this.offsetX = 0;
    this.offsetY = 0;
    this.recipientAttribute = recipientAttribute;

    this.startDrag = this.startDrag.bind(this);
    this.drag = this.drag.bind(this);
    this.endDrag = this.endDrag.bind(this);

    this.modalHeader.addEventListener('mousedown', this.startDrag);
    this.modalHeader.addEventListener('touchstart', this.startDrag);
    document.addEventListener('mousemove', this.drag);
    document.addEventListener('touchmove', this.drag);
    document.addEventListener('mouseup', this.endDrag);
    document.addEventListener('touchend', this.endDrag);

    this.modal.addEventListener('show.bs.modal', (event) => {
      const button = event.relatedTarget;
      const recipient = button.getAttribute(this.recipientAttribute);
      const modalTitle = this.modal.querySelector('.modal-title');
      const modalBodyInput = this.modal.querySelector('.modal-body input');
      if (recipient) {
        modalTitle.textContent = `New Message to ${recipient}`;
        if (modalBodyInput) modalBodyInput.value = recipient;
      }
    });
    this.modal.addEventListener('hidden.bs.modal', (event) => {
      const remember = this.modal.querySelector('.form-check-input');
      if (!remember.checked) {
        this.modalContent.removeAttribute('style');
        const content = this.modalContent.querySelector('.modal-body p');
        if (content) content.textContent = 'The content of your modal.';
      } else {
        const content = this.modalContent.querySelector('.modal-body p');
        if (content) content.textContent = 'I remembered the position';
      }
    });
  }

  startDrag(e) {
    this.isDragging = true;
    this.startX = e.clientX || e.touches[0].clientX;
    this.startY = e.clientY || e.touches[0].clientY;
    this.offsetX = this.modalContent.offsetLeft;
    this.offsetY = this.modalContent.offsetTop;
  }

  drag(e) {
    if (this.isDragging) {
      const x =
        this.offsetX + (e.clientX || e.touches[0].clientX) - this.startX;
      const y =
        this.offsetY + (e.clientY || e.touches[0].clientY) - this.startY;
      this.modalContent.style.left = x + 'px';
      this.modalContent.style.top = y + 'px';
    }
  }

  endDrag() {
    this.isDragging = false;
  }
}

document.addEventListener('DOMContentLoaded', function () {
  new DraggableModal('modal-1');
  new DraggableModal('modal-2', 'data-recipient');
});

css

.modal-header {
  cursor: move;
}

.modal-title::before {
  content: "⠿";
  color: #aaa;
  margin-right: 1rem;
  font-size: 1.5rem;
}

Go back