SpinaCMS/Spina

View on GitHub
app/assets/javascripts/spina/controllers/repeater_controller.js

Summary

Maintainability
A
0 mins
Test Coverage
import { Controller } from "@hotwired/stimulus"
import Sortable from "libraries/sortablejs"

export default class extends Controller {
  static get targets() {
    return [ "list", "listItem", "content" ]
  }

  connect() {
    this.sortable = Sortable.create(this.listTarget, {
      handle: 'button svg',
      dataIdAttr: "data-pane-id",
      onEnd: this.sort.bind(this),
      animation: 150
    })
  }

  sort(event) {
    let ids = this.sortable.toArray()

    // Sort the DOM elements containing the repeater fields
    this.panes
      .sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id))
      .map((node, index) => {
        this.contentTarget.appendChild(node)
        const positionField = node.querySelector('[data-position]')
        if (positionField) positionField.value = index
      })

  }

  addFields(event) {
    let button = event.currentTarget
    let childIndex = button.dataset.childIndex

    // Get timestamp
    let time = new Date().getTime()
    let regex = new RegExp(childIndex, 'g')
    let html = button.dataset.fields.replace(regex, time)

    // Insert button
    this.listTarget.insertAdjacentHTML('beforeend', this.buttonHTML(time))
    // Insert fields
    const parser = new DOMParser();
    const docFields = parser.parseFromString(html, 'text/html');
    this.contentTarget.appendChild(docFields.body.firstChild);

  }

  removeFields(event) {
    let id = event.currentTarget.dataset.id
    let listItem = this.listItemTargets.find(listItem => listItem.dataset.paneId == id)
    let sibling = listItem.previousElementSibling || listItem.nextElementSibling
    let pane = document.getElementById(id)
    this.listTarget.removeChild(listItem)
    this.contentTarget.removeChild(pane)
    
    // Activate previous/next tab
    if(sibling) sibling.click()
  }

  buttonHTML(pane_id) {
    return `<button type="button" class="text-gray-600 rounded-md px-3 truncate text-sm font-medium flex items-center w-full h-10" data-controller="exists" data-action="tabs#show" data-tabs-target="button" data-repeater-target="listItem" data-pane-id="pane_${pane_id}">
      <svg class="w-4 h-4 mr-2" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M432 288H16c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h416c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16zm0-112H16c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h416c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16z"/></svg>
      ...
    </button>`
  }

  get panes() {
    return [...this.contentTarget.children]
  }

}