PageSourceSearch

https://hush.sg/assets/controllers/faq_sortable_controller-77ae875b.js

js hush.sg collected 2026-09-26 07:29:48 UTC 3,484 bytes, 107 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3export default class extends Controller {
4  static values = { url: String }
5  static targets = ["categoryList", "category"]
6
7  connect() {
8    this.dragType = null
9    this.draggedEl = null
10
11    // Category drag via handles
12    this.element.querySelectorAll("[data-drag-handle='category']").forEach(handle => {
13      handle.addEventListener("mousedown", (e) => {
14        const cat = handle.closest("[data-faq-sortable-target='category']")
15        cat.setAttribute("draggable", "true")
16        this.pendingDragType = "category"
17      })
18    })
19
20    // Item drag via handles
21    this.element.querySelectorAll("[data-drag-handle='item']").forEach(handle => {
22      handle.addEventListener("mousedown", (e) => {
23        const item = handle.closest("[data-faq-id]")
24        item.setAttribute("draggable", "true")
25        this.pendingDragType = "item"
26      })
27    })
28
29    // Use event delegation for drag events
30    this.element.addEventListener("dragstart", this.onDragStart.bind(this))
31    this.element.addEventListener("dragover", this.onDragOver.bind(this))
32    this.element.addEventListener("drop", this.onDrop.bind(this))
33    this.element.addEventListener("dragend", this.onDragEnd.bind(this))
34  }
35
36  onDragStart(e) {
37    this.dragType = this.pendingDragType
38    this.draggedEl = this.dragType === "category"
39      ? e.target.closest("[data-faq-sortable-target='category']")
40      : e.target.closest("[data-faq-id]")
41
42    if (!this.draggedEl) return
43
44    this.draggedEl.classList.add("opacity-40")
45    e.dataTransfer.effectAllowed = "move"
46    // Firefox requires setData
47    e.dataTransfer.setData("text/plain", "")
48  }
49
50  onDragOver(e) {
51    if (!this.draggedEl) return
52    e.preventDefault()
53    e.dataTransfer.dropEffect = "move"
54
55    if (this.dragType === "category") {
56      const target = e.target.closest("[data-faq-sortable-target='category']")
57      if (!target || target === this.draggedEl) return
58
59      const rect = target.getBoundingClientRect()
60      const after = e.clientY > rect.top + rect.height / 2
61      this.categoryListTarget.insertBefore(this.draggedEl, after ? target.nextElementSibling : target)
62    } else {
63      const targetItem = e.target.closest("[data-faq-id]")
64      const targetList = e.target.closest("[data-item-list]")
65      if (!targetList) return
66
67      if (targetItem && targetItem !== this.draggedEl) {
68        const rect = targetItem.getBoundingClientRect()
69        const after = e.clientY > rect.top + rect.height / 2
70        targetList.insertBefore(this.draggedEl, after ? targetItem.nextElementSibling : targetItem)
71      } else if (!targetItem && targetList.children.length === 0) {
72        targetList.appendChild(this.draggedEl)
73      }
74    }
75  }
76
77  onDrop(e) {
78    e.preventDefault()
79  }
80
81  onDragEnd(e) {
82    if (this.draggedEl) {
83      this.draggedEl.classList.remove("opacity-40")
84      this.draggedEl.removeAttribute("draggable")
85    }
86    this.dragType = null
87    this.draggedEl = null
88    this.pendingDragType = null
89    this.save()
90  }
91
92  save() {
93    const ids = []
94    this.categoryTargets.forEach(cat => {
95      cat.querySelectorAll("[data-faq-id]").forEach(item => {
96        ids.push(item.dataset.faqId)
97      })
98    })
99
100    const token = document.querySelector('meta[name="csrf-token"]')?.content
101    fetch(this.urlValue, {
102      method: "PATCH",
103      headers: { "Content-Type": "application/json", "X-CSRF-Token": token },
104      body: JSON.stringify({ ids })
105    })
106  }
107}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.