PageSourceSearch

https://sifrcrm.up.railway.app/assets/controllers/chat/input_contr…1f44c0860ff07bca4538a84176ef95c0ae8a4d5d.js

js sifrcrm.up.railway.app collected 2026-10-03 12:14:46 UTC 2,301 bytes, 85 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2
3// chat--input: handles the composer textarea behavior — auto-grow,
4// Enter-submits, disabled-when-empty, in-flight spinner, and
5// optimistic clear-on-submit.
6export default class extends Controller {
7  static targets = ["input", "submit", "sendIcon", "spinner"]
8
9  connect() {
10    this.onSubmitStart = this.onSubmitStart.bind(this)
11    this.onSubmitEnd = this.onSubmitEnd.bind(this)
12    this.element.addEventListener("turbo:submit-start", this.onSubmitStart)
13    this.element.addEventListener("turbo:submit-end", this.onSubmitEnd)
14    this.updateDisabled()
15  }
16
17  disconnect() {
18    this.element.removeEventListener("turbo:submit-start", this.onSubmitStart)
19    this.element.removeEventListener("turbo:submit-end", this.onSubmitEnd)
20  }
21
22  isEmpty() {
23    return !this.hasInputTarget || this.inputTarget.value.trim() === ""
24  }
25
26  // Stays disabled while a message is in flight, even as the user types the next one.
27  updateDisabled() {
28    if (this.hasSubmitTarget) {
29      this.submitTarget.disabled = this.busy || this.isEmpty()
30    }
31  }
32
33  setBusy(busy) {
34    this.busy = busy
35    this.updateDisabled()
36    if (this.hasSubmitTarget) {
37      busy ? this.submitTarget.setAttribute("aria-busy", "true") : this.submitTarget.removeAttribute("aria-busy")
38    }
39    if (this.hasSendIconTarget) {
40      this.sendIconTarget.classList.toggle("hidden", busy)
41    }
42    if (this.hasSpinnerTarget) {
43      this.spinnerTarget.classList.toggle("hidden", !busy)
44    }
45  }
46
47  onSubmitStart() {
48    this.setBusy(true)
49  }
50
51  onSubmitEnd() {
52    this.setBusy(false)
53  }
54
55  autoGrow() {
56    if (!this.hasInputTarget) return
57    const el = this.inputTarget
58    el.style.height = "auto"
59    el.style.height = `${el.scrollHeight}px`
60    this.updateDisabled()
61  }
62
63  handleKey(event) {
64    if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
65      event.preventDefault()
66      if (!this.isEmpty()) {
67        this.element.requestSubmit()
68      }
69    }
70  }
71
72  submit(event) {
73    if (this.isEmpty()) {
74      event.preventDefault()
75      return
76    }
77    requestAnimationFrame(() => {
78      if (this.hasInputTarget) {
79        this.inputTarget.value = ""
80        this.inputTarget.style.height = "auto"
81      }
82      this.updateDisabled()
83    })
84  }
85};

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.