PageSourceSearch

https://draw.city/assets/controllers/clipboard_controller-3943eb63.js

js draw.city collected 2026-09-28 10:21:03 UTC 2,984 bytes, 98 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2import ClipboardJS from "clipboard"
3import { autoPlacement, computePosition, flip, offset, arrow } from "@floating-ui/dom"
4
5export default class extends Controller {
6  static values = {
7    hideTooltipAfter: 1500,
8    tooltipPlacement: "top",
9    tooltipOffset: 6,
10    errorMessage: { type: String, default: "Failed!" },
11    successMessage: { type: String, default: "Copied!" }
12  }
13
14  connect() {
15    // ClipboardJS copies through a hidden textarea appended to `container`.
16    // Inside an open modal <dialog> the rest of the document is inert, so the
17    // default body mount can't take the selection and the copy silently fails —
18    // mount the fake element inside the dialog instead.
19    this.clipboard = new ClipboardJS(this.element, {
20      container: this.element.closest("dialog") || document.body
21    })
22    this.clipboard.on("success", (e) => this.handleEvent(this.successMessageValue))
23    this.clipboard.on("error",   (e) => this.handleEvent(this.errorMessageValue))
24  }
25
26  disconnect() {
27    this.clearTooltip()
28  }
29
30  handleEvent(message) {
31    this.clearTooltip()
32    this.createTooltipElements(message)
33    this.updatePosition()
34
35    this.timeout = setTimeout(() => {
36      this.clearTooltip()
37    }, this.hideTooltipAfterValue)
38  }
39
40  clearTooltip() {
41    this.tooltip?.remove()
42    clearTimeout(this.timeout)
43  }
44
45  createTooltipElements(message) {
46    this.tooltip = document.createElement("div")
47    this.tooltip.dataset.tooltipTarget = "content"
48    this.tooltip.classList.add("tooltip", "open")
49    this.tooltip.textContent = message
50
51    this.arrow = document.createElement("div")
52    this.arrow.classList.add("arrow")
53
54    this.tooltip.appendChild(this.arrow)
55    // A body-mounted tooltip paints beneath an open modal <dialog>'s top
56    // layer, so from inside one it must mount there to be visible.
57    const host = this.element.closest("dialog[open]") || document.body
58    host.appendChild(this.tooltip)
59  }
60
61  updatePosition() {
62    computePosition(this.element, this.tooltip, {
63      placement: this.tooltipPlacementValue,
64      middleware: [
65        flip(),
66        offset(this.tooltipOffsetValue),
67        arrow({element: this.arrow}),
68      ]
69    }).then(({x, y, placement, middlewareData}) => {
70      Object.assign(this.tooltip.style, {
71        left: `${x}px`,
72        top: `${y}px`
73      });
74
75      const side = placement.split("-")[0];
76
77      const staticSide = {
78        top: "bottom",
79        right: "left",
80        bottom: "top",
81        left: "right"
82      }[side];
83
84      if (middlewareData.arrow) {
85        const { x, y } = middlewareData.arrow;
86        Object.assign(this.arrow.style, {
87          left: x != null ? `${x}px` : "",
88          top: y != null ? `${y}px` : "",
89          // Ensure the static side gets unset when
90          // flipping to other placements' axes.
91          right: "",
92          bottom: "",
93          [staticSide]: `${-8 / 2}px`,
94        });
95      }
96    })
97  }
98}

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.