File size: 4,406 Bytes
4dd77e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Text Selection</title>
  <style>
    #settings {
      margin-bottom: 15px;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 6px;
      background: #fafafa;
      width: 90%;
    }
    #inputBox {
      width: 90%;
      min-height: 150px;
      border: 1px solid #ccc;
      padding: 10px;
      white-space: pre-wrap;
      overflow-wrap: break-word;
    }
    #results {
      margin-top: 15px;
      font-family: monospace;
      background: #f4f4f4;
      padding: 10px;
      border-radius: 6px;
      border: 1px solid #ddd;
      white-space: pre-wrap;
      user-select: text;
    }
    label {
      margin-right: 10px;
    }
  </style>
</head>
<body>
  <h3>Highlight text to get indices (accurate whitespace & line break)</h3>

  <!-- Settings Panel -->
  <div id="settings">
    <strong>Settings (rename keys):</strong><br><br>
    <label>Span Text Key: <input id="keySpan" type="text" value="span_text"></label>
    <label>Start Key: <input id="keyStart" type="text" value="start"></label>
    <label>End Key: <input id="keyEnd" type="text" value="end"></label>
  </div>

  <!-- Editable div -->
  <div id="inputBox" contenteditable="true"></div>

  <button onclick="getSelectionIndices()">Get Span JSON</button>

  <pre id="results"></pre>

  <script>
    let spans = [];
    let lastText = "";

    // Convert HTML content to normalized text where line breaks are \n
    function getNormalizedText(container) {
      let html = container.innerHTML;

      // Replace empty divs with \n
      html = html.replace(/<div><br><\/div>/gi, '\n');

      // Replace remaining divs with \n at start, remove closing divs
      html = html.replace(/<div>/gi, '\n').replace(/<\/div>/gi, '');

      // Replace <br> with \n
      html = html.replace(/<br\s*\/?>/gi, '\n');

      // Replace &nbsp; with space
      html = html.replace(/&nbsp;/g, ' ');

      // Strip other tags just in case
      html = html.replace(/<[^>]+>/g, '');

      return html;
    }

    function getSelectionIndices() {
      const container = document.getElementById("inputBox");
      const selection = window.getSelection();
      if (!selection || !selection.rangeCount) return;

      const range = selection.getRangeAt(0);
      if (!container.contains(range.startContainer) || !container.contains(range.endContainer)) return; 

      const selectedText = selection.toString();
      if (!selectedText) return;

      // Normalize the container text
      const normalizedText = getNormalizedText(container);

      // Get text before selection
      const preRange = range.cloneRange();
      preRange.selectNodeContents(container);
      preRange.setEnd(range.startContainer, range.startOffset);

      const tempDiv = document.createElement("div");
      tempDiv.appendChild(preRange.cloneContents());
      let preText = getNormalizedText(tempDiv);

      const start = preText.length;
      const end = start + selectedText.length;

      const spanInfo = { span_text: selectedText, start, end };

      // Prepend and keep last 5 spans
      spans.unshift(spanInfo);
      spans = spans.slice(0, 5);

      renderSpans();
    }

    function renderSpans() {
      const keySpan = document.getElementById("keySpan").value || "span_text";
      const keyStart = document.getElementById("keyStart").value || "start";
      const keyEnd = document.getElementById("keyEnd").value || "end";

      const renamedSpans = spans.map(s => ({
        [keySpan]: s.span_text,
        [keyStart]: s.start,
        [keyEnd]: s.end
      }));

      document.getElementById("results").innerText = renamedSpans.length
        ? JSON.stringify(renamedSpans, null, 2)
        : "";
    }

    // Reset spans if input text changes
    document.getElementById("inputBox").addEventListener("input", function() {
      const currentText = getNormalizedText(this);
      if (currentText !== lastText) {
        spans = [];
        document.getElementById("results").innerText = "";
        lastText = currentText;
      }
    });

    // Re-render spans if key names change
    document.getElementById("keySpan").addEventListener("input", renderSpans);
    document.getElementById("keyStart").addEventListener("input", renderSpans);
    document.getElementById("keyEnd").addEventListener("input", renderSpans);
  </script>
</body>
</html>