Bin
2025-12-17 262fecaa75b2909ad244f12c3b079ed3ff4ae329
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import { useEffect } from "react";
 
export const useRegionsCopyPaste = (entity: any) => {
  useEffect(() => {
    const isFocusable = (el: Node | Window | HTMLElement | null) => {
      if (!el) return false;
      if ((el as Node).nodeType !== Node.ELEMENT_NODE) return false;
 
      const element = el as HTMLElement;
      const tabIndex = Number.parseInt(element.getAttribute("tabindex") ?? "", 10);
      const isFocusable = element.matches("a, button, input, textarea, select, details, [tabindex], [contenteditable]");
 
      return isFocusable || tabIndex > -1;
    };
 
    const allowCopyPaste = () => {
      const selection = window.getSelection();
      const focusNode = selection?.focusNode;
      const nodeIsFocusable = isFocusable(focusNode as HTMLElement);
      const activeElementIsFocusable = isFocusable(document.activeElement);
      const selectionIsCollapsed = selection?.isCollapsed ?? true;
 
      return selectionIsCollapsed && !nodeIsFocusable && !activeElementIsFocusable;
    };
 
    const copyToClipboard = (ev: ClipboardEvent) => {
      const { clipboardData } = ev;
      const results = entity.serializedSelection;
 
      clipboardData?.setData("application/json", JSON.stringify(results));
      ev.preventDefault();
    };
 
    const pasteFromClipboard = (ev: ClipboardEvent) => {
      const { clipboardData } = ev;
      const data = clipboardData?.getData("application/json");
 
      try {
        const results = (data ? JSON.parse(data) : []).map((res: any) => {
          return { ...res, readonly: false };
        });
 
        entity.appendResults(results);
        ev.preventDefault();
      } catch (e) {
        console.error(e);
        return;
      }
    };
 
    const copyHandler = (ev: Event) => {
      if (!allowCopyPaste()) return;
 
      copyToClipboard(ev as ClipboardEvent);
    };
 
    const pasteHandler = (ev: Event) => {
      if (!allowCopyPaste()) return;
 
      pasteFromClipboard(ev as ClipboardEvent);
    };
 
    const cutHandler = (ev: Event) => {
      if (!allowCopyPaste()) return;
 
      copyToClipboard(ev as ClipboardEvent);
      entity.deleteSelectedRegions();
    };
 
    window.addEventListener("copy", copyHandler);
    window.addEventListener("paste", pasteHandler);
    window.addEventListener("cut", cutHandler);
    return () => {
      window.removeEventListener("copy", copyHandler);
      window.removeEventListener("paste", pasteHandler);
      window.removeEventListener("cut", cutHandler);
    };
  }, [entity.pk ?? entity.id]);
};