lk-text-select-highlight 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ git提交的描述都用中文
2
+ 代码备注使用中文
package/README-cn.md CHANGED
@@ -125,6 +125,20 @@ if (highlights.length > 0) {
125
125
 
126
126
  支持所有现代浏览器 (Chrome, Firefox, Safari, Edge)。
127
127
 
128
+ ## 测试
129
+
130
+ 运行测试:
131
+
132
+ ```bash
133
+ npm test
134
+ ```
135
+
136
+ 该库包含全面的单元测试,覆盖所有主要功能,包括初始化、自定义选项、严格模式处理和高亮管理。
137
+
138
+ ## 浏览器兼容性
139
+
140
+ 支持所有现代浏览器 (Chrome, Firefox, Safari, Edge)。
141
+
128
142
  ## 许可证
129
143
 
130
144
  MIT
package/README.md CHANGED
@@ -75,6 +75,16 @@ Removes a specific highlight object. The highlight object can be obtained from t
75
75
 
76
76
  Removes all existing highlights.
77
77
 
78
+ ## Testing
79
+
80
+ To run the tests:
81
+
82
+ ```bash
83
+ npm test
84
+ ```
85
+
86
+ The library includes comprehensive unit tests covering all major functionality including initialization, custom options, strict mode handling, and highlight management.
87
+
78
88
  ## License
79
89
 
80
90
  MIT
package/demo-full.html ADDED
@@ -0,0 +1,246 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>lk-text-select-highlight 完整功能演示</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ max-width: 800px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ line-height: 1.6;
14
+ }
15
+
16
+ .container {
17
+ border: 2px solid #ddd;
18
+ padding: 20px;
19
+ margin: 20px 0;
20
+ background-color: #f9f9f9;
21
+ border-radius: 5px;
22
+ }
23
+
24
+ .controls {
25
+ margin: 20px 0;
26
+ padding: 15px;
27
+ background-color: #eef;
28
+ border-radius: 5px;
29
+ }
30
+
31
+ button {
32
+ margin: 5px;
33
+ padding: 8px 15px;
34
+ cursor: pointer;
35
+ background-color: #007bff;
36
+ color: white;
37
+ border: none;
38
+ border-radius: 3px;
39
+ }
40
+
41
+ button:hover {
42
+ background-color: #0056b3;
43
+ }
44
+
45
+ .highlighted-text {
46
+ background-color: yellow;
47
+ padding: 0;
48
+ margin: 0;
49
+ }
50
+
51
+ .status {
52
+ margin: 10px 0;
53
+ padding: 10px;
54
+ background-color: #eee;
55
+ border-left: 4px solid #007bff;
56
+ }
57
+
58
+ #output {
59
+ background-color: #f0f0f0;
60
+ padding: 10px;
61
+ border-radius: 3px;
62
+ font-family: monospace;
63
+ white-space: pre-wrap;
64
+ }
65
+ </style>
66
+ </head>
67
+ <body>
68
+ <h1>lk-text-select-highlight 完整功能演示</h1>
69
+
70
+ <div class="controls">
71
+ <button onclick="highlightText()">高亮选中文本</button>
72
+ <button onclick="removeAllHighlights()">清除所有高亮</button>
73
+ <button onclick="getHighlights()">获取高亮数据</button>
74
+ <button onclick="setHighlightsData()">设置预设高亮数据</button>
75
+ <button onclick="removeSpecificHighlight()">移除特定高亮</button>
76
+ <br /><br />
77
+ <label>
78
+ <input
79
+ type="checkbox"
80
+ id="strictMode"
81
+ onchange="toggleStrictMode()"
82
+ />
83
+ 严格模式
84
+ </label>
85
+ <label>
86
+ <input
87
+ type="checkbox"
88
+ id="limitedContainer"
89
+ onchange="toggleContainer()"
90
+ />
91
+ 限制容器内高亮
92
+ </label>
93
+ </div>
94
+
95
+ <div class="status">
96
+ <strong>状态信息:</strong>
97
+ <div id="output">点击按钮开始测试功能...</div>
98
+ </div>
99
+
100
+ <div class="container" id="container1">
101
+ <h2>容器1 - 可高亮区域</h2>
102
+ <p>
103
+ 这里是第一个容器的内容。您可以选择这段文字进行高亮。这是用于测试容器限制功能的文本。
104
+ </p>
105
+ <p>
106
+ 尝试选择这部分文字:<strong>这段文字可以被高亮</strong>,因为它在容器内。
107
+ </p>
108
+ <p>还可以选择其他内容,比如:<em>斜体文字也可以被高亮</em>。</p>
109
+ </div>
110
+
111
+ <div class="container" id="container2">
112
+ <h2>容器2 - 另一个可高亮区域</h2>
113
+ <p>这里是第二个容器的内容。这里也有一些可以高亮的文本。</p>
114
+ <p>
115
+ 您可以试试选择
116
+ <span class="highlighted-text" data-uuid="demo-123"
117
+ >这个预先高亮的文本</span
118
+ >,看看在严格模式下的表现。
119
+ </p>
120
+ <p>这段文字也是可以被高亮的普通文本。</p>
121
+ </div>
122
+
123
+ <div>
124
+ <h2>非容器区域 - 默认也可高亮</h2>
125
+ <p>
126
+ 这部分内容默认在整个页面都可以选择高亮,但如果启用了容器限制,则只能在指定容器内高亮。
127
+ </p>
128
+ <p>这是一个额外的测试段落,用来验证容器限制功能。</p>
129
+ </div>
130
+
131
+ <script src="./dist/lk-text-select-highlight.umd.js?v=1.0.5"></script>
132
+ <script>
133
+ // 初始化TextHighlighter实例
134
+ let highlighter;
135
+ let limitedHighlighter;
136
+
137
+ // 页面加载完成后初始化
138
+ document.addEventListener("DOMContentLoaded", function () {
139
+ // 创建普通高亮器(整个页面)
140
+ highlighter = new TextHighlighter({
141
+ className: "highlighted-text",
142
+ color: "#ffff00",
143
+ });
144
+
145
+ // 创建限制在容器内的高亮器
146
+ const container = document.getElementById("container1");
147
+ limitedHighlighter = new TextHighlighter({
148
+ className: "highlighted-text",
149
+ color: "#aaffaa",
150
+ container: container,
151
+ strictMode: false,
152
+ });
153
+
154
+ updateOutput("TextHighlighter 已初始化完成");
155
+ });
156
+
157
+ function updateOutput(message) {
158
+ const output = document.getElementById("output");
159
+ output.textContent = message;
160
+ }
161
+
162
+ function highlightText() {
163
+ const useLimited =
164
+ document.getElementById("limitedContainer").checked;
165
+ const currentHighlighter = useLimited
166
+ ? limitedHighlighter
167
+ : highlighter;
168
+
169
+ const success = currentHighlighter.highlightSelection();
170
+ if (success) {
171
+ updateOutput("文本高亮成功!");
172
+ } else {
173
+ updateOutput(
174
+ "高亮失败:可能是没有选中文本,或超出容器范围,或处于严格模式下选择了已高亮的文本",
175
+ );
176
+ }
177
+ }
178
+
179
+ function removeAllHighlights() {
180
+ highlighter.removeAllHighlights();
181
+ limitedHighlighter.removeAllHighlights(); // 同时清理两个高亮器
182
+ updateOutput("所有高亮已清除");
183
+ }
184
+
185
+ function getHighlights() {
186
+ const highlights = highlighter.getHighlights();
187
+ const limitedHighlights = limitedHighlighter.getHighlights();
188
+ updateOutput(
189
+ `主高亮器数据:${JSON.stringify(highlights, null, 2)}\n\n限制容器高亮器数据:${JSON.stringify(limitedHighlights, null, 2)}`,
190
+ );
191
+ }
192
+
193
+ function setHighlightsData() {
194
+ try {
195
+ // 设置一些预设的高亮数据
196
+ const presetHighlights = [
197
+ { uuid: "preset-1", text: "这段文字可以被高亮" },
198
+ { uuid: "preset-2", text: "斜体文字也可以被高亮" },
199
+ ];
200
+
201
+ highlighter.setHighlights(presetHighlights);
202
+ updateOutput(
203
+ `已设置预设高亮数据:${JSON.stringify(presetHighlights, null, 2)}`,
204
+ );
205
+ } catch (error) {
206
+ updateOutput(`设置高亮数据失败:${error.message}`);
207
+ }
208
+ }
209
+
210
+ function removeSpecificHighlight() {
211
+ const highlights = highlighter.getHighlights();
212
+ if (highlights.length > 0) {
213
+ const highlightToRemove = highlights[0]; // 移除第一个高亮
214
+ const success =
215
+ highlighter.removeHighlight(highlightToRemove);
216
+ if (success) {
217
+ updateOutput(
218
+ `已移除特定高亮:${JSON.stringify(highlightToRemove)}`,
219
+ );
220
+ } else {
221
+ updateOutput(`移除高亮失败`);
222
+ }
223
+ } else {
224
+ updateOutput("没有可移除的高亮");
225
+ }
226
+ }
227
+
228
+ function toggleStrictMode() {
229
+ const strictMode =
230
+ document.getElementById("strictMode").checked;
231
+ // 更新两个高亮器的严格模式
232
+ highlighter.options.strictMode = strictMode;
233
+ limitedHighlighter.options.strictMode = strictMode;
234
+ updateOutput(`严格模式已${strictMode ? "启用" : "禁用"}`);
235
+ }
236
+
237
+ function toggleContainer() {
238
+ const useLimited =
239
+ document.getElementById("limitedContainer").checked;
240
+ updateOutput(
241
+ `容器限制模式${useLimited ? "已启用(请在容器1内选择文本)" : "已禁用(可在整个页面选择文本)"}`,
242
+ );
243
+ }
244
+ </script>
245
+ </body>
246
+ </html>
@@ -22,6 +22,18 @@ class TextHighlighter {
22
22
  this.highlights = [];
23
23
  }
24
24
 
25
+ /**
26
+ * Generate a simple UUID
27
+ */
28
+ generateUUID() {
29
+ return (
30
+ "highlight-" +
31
+ Date.now() +
32
+ "-" +
33
+ Math.random().toString(36).substring(2, 11)
34
+ );
35
+ }
36
+
25
37
  /**
26
38
  * Highlight selected text
27
39
  */
@@ -56,10 +68,11 @@ class TextHighlighter {
56
68
  }
57
69
 
58
70
  try {
59
- const highlightedElement = this.wrapRange(range);
71
+ const uuid = this.generateUUID();
72
+ const highlightedElement = this.wrapRange(range, uuid);
60
73
 
61
74
  this.highlights.push({
62
- element: highlightedElement,
75
+ uuid: uuid,
63
76
  text: selection.toString(),
64
77
  });
65
78
 
@@ -116,14 +129,18 @@ class TextHighlighter {
116
129
  /**
117
130
  * Wrap a range with highlight element
118
131
  * @param {Range} range - The range to wrap
132
+ * @param {string} uuid - Unique identifier for the highlight
119
133
  */
120
- wrapRange(range) {
134
+ wrapRange(range, uuid) {
121
135
  const highlightEl = document.createElement("span");
122
136
  highlightEl.className = this.options.className;
123
137
  highlightEl.style.backgroundColor = this.options.color;
124
138
  highlightEl.style.padding = "0";
125
139
  highlightEl.style.margin = "0";
126
140
 
141
+ // Add UUID as data attribute
142
+ highlightEl.setAttribute("data-uuid", uuid);
143
+
127
144
  // Clone the range and insert the highlight element
128
145
  range.surroundContents(highlightEl);
129
146
 
@@ -135,12 +152,12 @@ class TextHighlighter {
135
152
  */
136
153
  removeAllHighlights() {
137
154
  this.highlights.forEach((highlight) => {
138
- if (highlight.element.parentNode) {
155
+ const element = document.querySelector(
156
+ `[data-uuid="${highlight.uuid}"]`,
157
+ );
158
+ if (element && element.parentNode) {
139
159
  const textNode = document.createTextNode(highlight.text);
140
- highlight.element.parentNode.replaceChild(
141
- textNode,
142
- highlight.element,
143
- );
160
+ element.parentNode.replaceChild(textNode, element);
144
161
  }
145
162
  });
146
163
 
@@ -151,23 +168,26 @@ class TextHighlighter {
151
168
  * Get all highlighted elements
152
169
  */
153
170
  getHighlights() {
171
+ // Return highlights with uuid and text
154
172
  return [...this.highlights];
155
173
  }
156
174
 
157
175
  /**
158
176
  * Remove a specific highlight
159
- * @param {Object} highlight - The highlight object to remove
177
+ * @param {Object} highlight - The highlight object to remove (containing uuid)
160
178
  */
161
179
  removeHighlight(highlight) {
162
- const index = this.highlights.indexOf(highlight);
180
+ const index = this.highlights.findIndex(
181
+ (h) => h.uuid === highlight.uuid,
182
+ );
163
183
  if (index !== -1) {
164
184
  // Restore the original text
165
- if (highlight.element.parentNode) {
185
+ const element = document.querySelector(
186
+ `[data-uuid="${highlight.uuid}"]`,
187
+ );
188
+ if (element && element.parentNode) {
166
189
  const textNode = document.createTextNode(highlight.text);
167
- highlight.element.parentNode.replaceChild(
168
- textNode,
169
- highlight.element,
170
- );
190
+ element.parentNode.replaceChild(textNode, element);
171
191
  }
172
192
 
173
193
  // Remove from the highlights array
@@ -176,6 +196,36 @@ class TextHighlighter {
176
196
  }
177
197
  return false;
178
198
  }
199
+
200
+ /**
201
+ * Set highlights data
202
+ * @param {Array} highlights - Array of highlight objects with uuid and text properties
203
+ */
204
+ setHighlights(highlights) {
205
+ // Validate the input to ensure it's an array of objects with required properties
206
+ if (!Array.isArray(highlights)) {
207
+ throw new Error("Highlights must be an array");
208
+ }
209
+
210
+ // Validate each highlight object
211
+ for (const highlight of highlights) {
212
+ if (
213
+ typeof highlight !== "object" ||
214
+ !highlight.hasOwnProperty("uuid") ||
215
+ !highlight.hasOwnProperty("text")
216
+ ) {
217
+ throw new Error(
218
+ "Each highlight must be an object with uuid and text properties",
219
+ );
220
+ }
221
+ }
222
+
223
+ // Clear existing highlights
224
+ this.removeAllHighlights();
225
+
226
+ // Set the new highlights data
227
+ this.highlights = [...highlights];
228
+ }
179
229
  }
180
230
 
181
231
  module.exports = TextHighlighter;
@@ -1 +1 @@
1
- {"version":3,"file":"lk-text-select-highlight.cjs.js","sources":["../src/index.js"],"sourcesContent":["/**\r\n * lk-text-select-highlight - A lightweight text selection highlight library\r\n * @module lk-text-select-highlight\r\n */\r\n\r\nclass TextHighlighter {\r\n\tconstructor(options = {}) {\r\n\t\tthis.options = {\r\n\t\t\tclassName: options.className || \"highlighted-text\",\r\n\t\t\tcolor: options.color || \"#ffff00\",\r\n\t\t\tcontainer: options.container || document.body, // DOM容器,默认为整个body\r\n\t\t\tstrictMode: options.strictMode || false, // 严格模式,默认为false\r\n\t\t\tcaseSensitive:\r\n\t\t\t\toptions.caseSensitive !== undefined\r\n\t\t\t\t\t? options.caseSensitive\r\n\t\t\t\t\t: true,\r\n\t\t\t...options,\r\n\t\t};\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Highlight selected text\r\n\t */\r\n\thighlightSelection() {\r\n\t\tconst selection = window.getSelection();\r\n\t\tif (!selection.toString().trim()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst range = selection.getRangeAt(0);\r\n\r\n\t\t// 检查选择的范围是否在指定的容器内\r\n\t\tconst container = this.options.container;\r\n\t\tif (\r\n\t\t\t!container.contains(range.startContainer) ||\r\n\t\t\t!container.contains(range.endContainer)\r\n\t\t) {\r\n\t\t\treturn false; // 选择超出了指定容器范围\r\n\t\t}\r\n\r\n\t\t// 更全面地检查整个范围是否在容器内\r\n\t\tconst commonAncestor = range.commonAncestorContainer;\r\n\t\tif (!container.contains(commonAncestor)) {\r\n\t\t\treturn false; // 整个范围不在容器内\r\n\t\t}\r\n\r\n\t\t// 严格模式检查:如果启用严格模式,检查选择范围内是否包含目标className的元素\r\n\t\tif (this.options.strictMode) {\r\n\t\t\tif (this.hasTargetClassInSelection(range)) {\r\n\t\t\t\treturn false; // 选择范围内包含目标className的元素,不允许高亮\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst highlightedElement = this.wrapRange(range);\r\n\r\n\t\t\tthis.highlights.push({\r\n\t\t\t\telement: highlightedElement,\r\n\t\t\t\ttext: selection.toString(),\r\n\t\t\t});\r\n\r\n\t\t\treturn true;\r\n\t\t} catch (error) {\r\n\t\t\tconsole.warn(\"Could not highlight selection:\", error);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the selection range contains elements with the target class\r\n\t * @param {Range} range - The range to check\r\n\t */\r\n\thasTargetClassInSelection(range) {\r\n\t\t// Check if startContainer or endContainer themselves have the target class\r\n\t\tconst startElement =\r\n\t\t\trange.startContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.startContainer\r\n\t\t\t\t: range.startContainer.parentElement;\r\n\r\n\t\tconst endElement =\r\n\t\t\trange.endContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.endContainer\r\n\t\t\t\t: range.endContainer.parentElement;\r\n\r\n\t\tif (\r\n\t\t\tstartElement &&\r\n\t\t\tstartElement.classList &&\r\n\t\t\tstartElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (\r\n\t\t\tendElement &&\r\n\t\t\tendElement.classList &&\r\n\t\t\tendElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Create a temporary div to work with the range content\r\n\t\tconst tempDiv = document.createElement(\"div\");\r\n\t\ttempDiv.appendChild(range.cloneContents());\r\n\r\n\t\t// Check if any child elements have the target class\r\n\t\tconst elementsWithTargetClass = tempDiv.querySelectorAll(\r\n\t\t\t`.${this.options.className}`,\r\n\t\t);\r\n\t\treturn elementsWithTargetClass.length > 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Wrap a range with highlight element\r\n\t * @param {Range} range - The range to wrap\r\n\t */\r\n\twrapRange(range) {\r\n\t\tconst highlightEl = document.createElement(\"span\");\r\n\t\thighlightEl.className = this.options.className;\r\n\t\thighlightEl.style.backgroundColor = this.options.color;\r\n\t\thighlightEl.style.padding = \"0\";\r\n\t\thighlightEl.style.margin = \"0\";\r\n\r\n\t\t// Clone the range and insert the highlight element\r\n\t\trange.surroundContents(highlightEl);\r\n\r\n\t\treturn highlightEl;\r\n\t}\r\n\r\n\t/**\r\n\t * Remove all highlights\r\n\t */\r\n\tremoveAllHighlights() {\r\n\t\tthis.highlights.forEach((highlight) => {\r\n\t\t\tif (highlight.element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\thighlight.element.parentNode.replaceChild(\r\n\t\t\t\t\ttextNode,\r\n\t\t\t\t\thighlight.element,\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Get all highlighted elements\r\n\t */\r\n\tgetHighlights() {\r\n\t\treturn [...this.highlights];\r\n\t}\r\n\r\n\t/**\r\n\t * Remove a specific highlight\r\n\t * @param {Object} highlight - The highlight object to remove\r\n\t */\r\n\tremoveHighlight(highlight) {\r\n\t\tconst index = this.highlights.indexOf(highlight);\r\n\t\tif (index !== -1) {\r\n\t\t\t// Restore the original text\r\n\t\t\tif (highlight.element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\thighlight.element.parentNode.replaceChild(\r\n\t\t\t\t\ttextNode,\r\n\t\t\t\t\thighlight.element,\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\t// Remove from the highlights array\r\n\t\t\tthis.highlights.splice(index, 1);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport default TextHighlighter;\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lk-text-select-highlight.cjs.js","sources":["../src/index.js"],"sourcesContent":["/**\r\n * lk-text-select-highlight - A lightweight text selection highlight library\r\n * @module lk-text-select-highlight\r\n */\r\n\r\nclass TextHighlighter {\r\n\tconstructor(options = {}) {\r\n\t\tthis.options = {\r\n\t\t\tclassName: options.className || \"highlighted-text\",\r\n\t\t\tcolor: options.color || \"#ffff00\",\r\n\t\t\tcontainer: options.container || document.body, // DOM容器,默认为整个body\r\n\t\t\tstrictMode: options.strictMode || false, // 严格模式,默认为false\r\n\t\t\tcaseSensitive:\r\n\t\t\t\toptions.caseSensitive !== undefined\r\n\t\t\t\t\t? options.caseSensitive\r\n\t\t\t\t\t: true,\r\n\t\t\t...options,\r\n\t\t};\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Generate a simple UUID\r\n\t */\r\n\tgenerateUUID() {\r\n\t\treturn (\r\n\t\t\t\"highlight-\" +\r\n\t\t\tDate.now() +\r\n\t\t\t\"-\" +\r\n\t\t\tMath.random().toString(36).substring(2, 11)\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Highlight selected text\r\n\t */\r\n\thighlightSelection() {\r\n\t\tconst selection = window.getSelection();\r\n\t\tif (!selection.toString().trim()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst range = selection.getRangeAt(0);\r\n\r\n\t\t// 检查选择的范围是否在指定的容器内\r\n\t\tconst container = this.options.container;\r\n\t\tif (\r\n\t\t\t!container.contains(range.startContainer) ||\r\n\t\t\t!container.contains(range.endContainer)\r\n\t\t) {\r\n\t\t\treturn false; // 选择超出了指定容器范围\r\n\t\t}\r\n\r\n\t\t// 更全面地检查整个范围是否在容器内\r\n\t\tconst commonAncestor = range.commonAncestorContainer;\r\n\t\tif (!container.contains(commonAncestor)) {\r\n\t\t\treturn false; // 整个范围不在容器内\r\n\t\t}\r\n\r\n\t\t// 严格模式检查:如果启用严格模式,检查选择范围内是否包含目标className的元素\r\n\t\tif (this.options.strictMode) {\r\n\t\t\tif (this.hasTargetClassInSelection(range)) {\r\n\t\t\t\treturn false; // 选择范围内包含目标className的元素,不允许高亮\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst uuid = this.generateUUID();\r\n\t\t\tconst highlightedElement = this.wrapRange(range, uuid);\r\n\r\n\t\t\tthis.highlights.push({\r\n\t\t\t\tuuid: uuid,\r\n\t\t\t\ttext: selection.toString(),\r\n\t\t\t});\r\n\r\n\t\t\treturn true;\r\n\t\t} catch (error) {\r\n\t\t\tconsole.warn(\"Could not highlight selection:\", error);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the selection range contains elements with the target class\r\n\t * @param {Range} range - The range to check\r\n\t */\r\n\thasTargetClassInSelection(range) {\r\n\t\t// Check if startContainer or endContainer themselves have the target class\r\n\t\tconst startElement =\r\n\t\t\trange.startContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.startContainer\r\n\t\t\t\t: range.startContainer.parentElement;\r\n\r\n\t\tconst endElement =\r\n\t\t\trange.endContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.endContainer\r\n\t\t\t\t: range.endContainer.parentElement;\r\n\r\n\t\tif (\r\n\t\t\tstartElement &&\r\n\t\t\tstartElement.classList &&\r\n\t\t\tstartElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (\r\n\t\t\tendElement &&\r\n\t\t\tendElement.classList &&\r\n\t\t\tendElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Create a temporary div to work with the range content\r\n\t\tconst tempDiv = document.createElement(\"div\");\r\n\t\ttempDiv.appendChild(range.cloneContents());\r\n\r\n\t\t// Check if any child elements have the target class\r\n\t\tconst elementsWithTargetClass = tempDiv.querySelectorAll(\r\n\t\t\t`.${this.options.className}`,\r\n\t\t);\r\n\t\treturn elementsWithTargetClass.length > 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Wrap a range with highlight element\r\n\t * @param {Range} range - The range to wrap\r\n\t * @param {string} uuid - Unique identifier for the highlight\r\n\t */\r\n\twrapRange(range, uuid) {\r\n\t\tconst highlightEl = document.createElement(\"span\");\r\n\t\thighlightEl.className = this.options.className;\r\n\t\thighlightEl.style.backgroundColor = this.options.color;\r\n\t\thighlightEl.style.padding = \"0\";\r\n\t\thighlightEl.style.margin = \"0\";\r\n\r\n\t\t// Add UUID as data attribute\r\n\t\thighlightEl.setAttribute(\"data-uuid\", uuid);\r\n\r\n\t\t// Clone the range and insert the highlight element\r\n\t\trange.surroundContents(highlightEl);\r\n\r\n\t\treturn highlightEl;\r\n\t}\r\n\r\n\t/**\r\n\t * Remove all highlights\r\n\t */\r\n\tremoveAllHighlights() {\r\n\t\tthis.highlights.forEach((highlight) => {\r\n\t\t\tconst element = document.querySelector(\r\n\t\t\t\t`[data-uuid=\"${highlight.uuid}\"]`,\r\n\t\t\t);\r\n\t\t\tif (element && element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\telement.parentNode.replaceChild(textNode, element);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Get all highlighted elements\r\n\t */\r\n\tgetHighlights() {\r\n\t\t// Return highlights with uuid and text\r\n\t\treturn [...this.highlights];\r\n\t}\r\n\r\n\t/**\r\n\t * Remove a specific highlight\r\n\t * @param {Object} highlight - The highlight object to remove (containing uuid)\r\n\t */\r\n\tremoveHighlight(highlight) {\r\n\t\tconst index = this.highlights.findIndex(\r\n\t\t\t(h) => h.uuid === highlight.uuid,\r\n\t\t);\r\n\t\tif (index !== -1) {\r\n\t\t\t// Restore the original text\r\n\t\t\tconst element = document.querySelector(\r\n\t\t\t\t`[data-uuid=\"${highlight.uuid}\"]`,\r\n\t\t\t);\r\n\t\t\tif (element && element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\telement.parentNode.replaceChild(textNode, element);\r\n\t\t\t}\r\n\r\n\t\t\t// Remove from the highlights array\r\n\t\t\tthis.highlights.splice(index, 1);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\t/**\r\n\t * Set highlights data\r\n\t * @param {Array} highlights - Array of highlight objects with uuid and text properties\r\n\t */\r\n\tsetHighlights(highlights) {\r\n\t\t// Validate the input to ensure it's an array of objects with required properties\r\n\t\tif (!Array.isArray(highlights)) {\r\n\t\t\tthrow new Error(\"Highlights must be an array\");\r\n\t\t}\r\n\r\n\t\t// Validate each highlight object\r\n\t\tfor (const highlight of highlights) {\r\n\t\t\tif (\r\n\t\t\t\ttypeof highlight !== \"object\" ||\r\n\t\t\t\t!highlight.hasOwnProperty(\"uuid\") ||\r\n\t\t\t\t!highlight.hasOwnProperty(\"text\")\r\n\t\t\t) {\r\n\t\t\t\tthrow new Error(\r\n\t\t\t\t\t\"Each highlight must be an object with uuid and text properties\",\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Clear existing highlights\r\n\t\tthis.removeAllHighlights();\r\n\r\n\t\t// Set the new highlights data\r\n\t\tthis.highlights = [...highlights];\r\n\t}\r\n}\r\n\r\nexport default TextHighlighter;\r\n"],"names":[],"mappings":"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"}
@@ -20,6 +20,18 @@ class TextHighlighter {
20
20
  this.highlights = [];
21
21
  }
22
22
 
23
+ /**
24
+ * Generate a simple UUID
25
+ */
26
+ generateUUID() {
27
+ return (
28
+ "highlight-" +
29
+ Date.now() +
30
+ "-" +
31
+ Math.random().toString(36).substring(2, 11)
32
+ );
33
+ }
34
+
23
35
  /**
24
36
  * Highlight selected text
25
37
  */
@@ -54,10 +66,11 @@ class TextHighlighter {
54
66
  }
55
67
 
56
68
  try {
57
- const highlightedElement = this.wrapRange(range);
69
+ const uuid = this.generateUUID();
70
+ const highlightedElement = this.wrapRange(range, uuid);
58
71
 
59
72
  this.highlights.push({
60
- element: highlightedElement,
73
+ uuid: uuid,
61
74
  text: selection.toString(),
62
75
  });
63
76
 
@@ -114,14 +127,18 @@ class TextHighlighter {
114
127
  /**
115
128
  * Wrap a range with highlight element
116
129
  * @param {Range} range - The range to wrap
130
+ * @param {string} uuid - Unique identifier for the highlight
117
131
  */
118
- wrapRange(range) {
132
+ wrapRange(range, uuid) {
119
133
  const highlightEl = document.createElement("span");
120
134
  highlightEl.className = this.options.className;
121
135
  highlightEl.style.backgroundColor = this.options.color;
122
136
  highlightEl.style.padding = "0";
123
137
  highlightEl.style.margin = "0";
124
138
 
139
+ // Add UUID as data attribute
140
+ highlightEl.setAttribute("data-uuid", uuid);
141
+
125
142
  // Clone the range and insert the highlight element
126
143
  range.surroundContents(highlightEl);
127
144
 
@@ -133,12 +150,12 @@ class TextHighlighter {
133
150
  */
134
151
  removeAllHighlights() {
135
152
  this.highlights.forEach((highlight) => {
136
- if (highlight.element.parentNode) {
153
+ const element = document.querySelector(
154
+ `[data-uuid="${highlight.uuid}"]`,
155
+ );
156
+ if (element && element.parentNode) {
137
157
  const textNode = document.createTextNode(highlight.text);
138
- highlight.element.parentNode.replaceChild(
139
- textNode,
140
- highlight.element,
141
- );
158
+ element.parentNode.replaceChild(textNode, element);
142
159
  }
143
160
  });
144
161
 
@@ -149,23 +166,26 @@ class TextHighlighter {
149
166
  * Get all highlighted elements
150
167
  */
151
168
  getHighlights() {
169
+ // Return highlights with uuid and text
152
170
  return [...this.highlights];
153
171
  }
154
172
 
155
173
  /**
156
174
  * Remove a specific highlight
157
- * @param {Object} highlight - The highlight object to remove
175
+ * @param {Object} highlight - The highlight object to remove (containing uuid)
158
176
  */
159
177
  removeHighlight(highlight) {
160
- const index = this.highlights.indexOf(highlight);
178
+ const index = this.highlights.findIndex(
179
+ (h) => h.uuid === highlight.uuid,
180
+ );
161
181
  if (index !== -1) {
162
182
  // Restore the original text
163
- if (highlight.element.parentNode) {
183
+ const element = document.querySelector(
184
+ `[data-uuid="${highlight.uuid}"]`,
185
+ );
186
+ if (element && element.parentNode) {
164
187
  const textNode = document.createTextNode(highlight.text);
165
- highlight.element.parentNode.replaceChild(
166
- textNode,
167
- highlight.element,
168
- );
188
+ element.parentNode.replaceChild(textNode, element);
169
189
  }
170
190
 
171
191
  // Remove from the highlights array
@@ -174,6 +194,36 @@ class TextHighlighter {
174
194
  }
175
195
  return false;
176
196
  }
197
+
198
+ /**
199
+ * Set highlights data
200
+ * @param {Array} highlights - Array of highlight objects with uuid and text properties
201
+ */
202
+ setHighlights(highlights) {
203
+ // Validate the input to ensure it's an array of objects with required properties
204
+ if (!Array.isArray(highlights)) {
205
+ throw new Error("Highlights must be an array");
206
+ }
207
+
208
+ // Validate each highlight object
209
+ for (const highlight of highlights) {
210
+ if (
211
+ typeof highlight !== "object" ||
212
+ !highlight.hasOwnProperty("uuid") ||
213
+ !highlight.hasOwnProperty("text")
214
+ ) {
215
+ throw new Error(
216
+ "Each highlight must be an object with uuid and text properties",
217
+ );
218
+ }
219
+ }
220
+
221
+ // Clear existing highlights
222
+ this.removeAllHighlights();
223
+
224
+ // Set the new highlights data
225
+ this.highlights = [...highlights];
226
+ }
177
227
  }
178
228
 
179
229
  export { TextHighlighter as default };
@@ -1 +1 @@
1
- {"version":3,"file":"lk-text-select-highlight.esm.js","sources":["../src/index.js"],"sourcesContent":["/**\r\n * lk-text-select-highlight - A lightweight text selection highlight library\r\n * @module lk-text-select-highlight\r\n */\r\n\r\nclass TextHighlighter {\r\n\tconstructor(options = {}) {\r\n\t\tthis.options = {\r\n\t\t\tclassName: options.className || \"highlighted-text\",\r\n\t\t\tcolor: options.color || \"#ffff00\",\r\n\t\t\tcontainer: options.container || document.body, // DOM容器,默认为整个body\r\n\t\t\tstrictMode: options.strictMode || false, // 严格模式,默认为false\r\n\t\t\tcaseSensitive:\r\n\t\t\t\toptions.caseSensitive !== undefined\r\n\t\t\t\t\t? options.caseSensitive\r\n\t\t\t\t\t: true,\r\n\t\t\t...options,\r\n\t\t};\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Highlight selected text\r\n\t */\r\n\thighlightSelection() {\r\n\t\tconst selection = window.getSelection();\r\n\t\tif (!selection.toString().trim()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst range = selection.getRangeAt(0);\r\n\r\n\t\t// 检查选择的范围是否在指定的容器内\r\n\t\tconst container = this.options.container;\r\n\t\tif (\r\n\t\t\t!container.contains(range.startContainer) ||\r\n\t\t\t!container.contains(range.endContainer)\r\n\t\t) {\r\n\t\t\treturn false; // 选择超出了指定容器范围\r\n\t\t}\r\n\r\n\t\t// 更全面地检查整个范围是否在容器内\r\n\t\tconst commonAncestor = range.commonAncestorContainer;\r\n\t\tif (!container.contains(commonAncestor)) {\r\n\t\t\treturn false; // 整个范围不在容器内\r\n\t\t}\r\n\r\n\t\t// 严格模式检查:如果启用严格模式,检查选择范围内是否包含目标className的元素\r\n\t\tif (this.options.strictMode) {\r\n\t\t\tif (this.hasTargetClassInSelection(range)) {\r\n\t\t\t\treturn false; // 选择范围内包含目标className的元素,不允许高亮\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst highlightedElement = this.wrapRange(range);\r\n\r\n\t\t\tthis.highlights.push({\r\n\t\t\t\telement: highlightedElement,\r\n\t\t\t\ttext: selection.toString(),\r\n\t\t\t});\r\n\r\n\t\t\treturn true;\r\n\t\t} catch (error) {\r\n\t\t\tconsole.warn(\"Could not highlight selection:\", error);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the selection range contains elements with the target class\r\n\t * @param {Range} range - The range to check\r\n\t */\r\n\thasTargetClassInSelection(range) {\r\n\t\t// Check if startContainer or endContainer themselves have the target class\r\n\t\tconst startElement =\r\n\t\t\trange.startContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.startContainer\r\n\t\t\t\t: range.startContainer.parentElement;\r\n\r\n\t\tconst endElement =\r\n\t\t\trange.endContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.endContainer\r\n\t\t\t\t: range.endContainer.parentElement;\r\n\r\n\t\tif (\r\n\t\t\tstartElement &&\r\n\t\t\tstartElement.classList &&\r\n\t\t\tstartElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (\r\n\t\t\tendElement &&\r\n\t\t\tendElement.classList &&\r\n\t\t\tendElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Create a temporary div to work with the range content\r\n\t\tconst tempDiv = document.createElement(\"div\");\r\n\t\ttempDiv.appendChild(range.cloneContents());\r\n\r\n\t\t// Check if any child elements have the target class\r\n\t\tconst elementsWithTargetClass = tempDiv.querySelectorAll(\r\n\t\t\t`.${this.options.className}`,\r\n\t\t);\r\n\t\treturn elementsWithTargetClass.length > 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Wrap a range with highlight element\r\n\t * @param {Range} range - The range to wrap\r\n\t */\r\n\twrapRange(range) {\r\n\t\tconst highlightEl = document.createElement(\"span\");\r\n\t\thighlightEl.className = this.options.className;\r\n\t\thighlightEl.style.backgroundColor = this.options.color;\r\n\t\thighlightEl.style.padding = \"0\";\r\n\t\thighlightEl.style.margin = \"0\";\r\n\r\n\t\t// Clone the range and insert the highlight element\r\n\t\trange.surroundContents(highlightEl);\r\n\r\n\t\treturn highlightEl;\r\n\t}\r\n\r\n\t/**\r\n\t * Remove all highlights\r\n\t */\r\n\tremoveAllHighlights() {\r\n\t\tthis.highlights.forEach((highlight) => {\r\n\t\t\tif (highlight.element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\thighlight.element.parentNode.replaceChild(\r\n\t\t\t\t\ttextNode,\r\n\t\t\t\t\thighlight.element,\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Get all highlighted elements\r\n\t */\r\n\tgetHighlights() {\r\n\t\treturn [...this.highlights];\r\n\t}\r\n\r\n\t/**\r\n\t * Remove a specific highlight\r\n\t * @param {Object} highlight - The highlight object to remove\r\n\t */\r\n\tremoveHighlight(highlight) {\r\n\t\tconst index = this.highlights.indexOf(highlight);\r\n\t\tif (index !== -1) {\r\n\t\t\t// Restore the original text\r\n\t\t\tif (highlight.element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\thighlight.element.parentNode.replaceChild(\r\n\t\t\t\t\ttextNode,\r\n\t\t\t\t\thighlight.element,\r\n\t\t\t\t);\r\n\t\t\t}\r\n\r\n\t\t\t// Remove from the highlights array\r\n\t\t\tthis.highlights.splice(index, 1);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nexport default TextHighlighter;\r\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lk-text-select-highlight.esm.js","sources":["../src/index.js"],"sourcesContent":["/**\r\n * lk-text-select-highlight - A lightweight text selection highlight library\r\n * @module lk-text-select-highlight\r\n */\r\n\r\nclass TextHighlighter {\r\n\tconstructor(options = {}) {\r\n\t\tthis.options = {\r\n\t\t\tclassName: options.className || \"highlighted-text\",\r\n\t\t\tcolor: options.color || \"#ffff00\",\r\n\t\t\tcontainer: options.container || document.body, // DOM容器,默认为整个body\r\n\t\t\tstrictMode: options.strictMode || false, // 严格模式,默认为false\r\n\t\t\tcaseSensitive:\r\n\t\t\t\toptions.caseSensitive !== undefined\r\n\t\t\t\t\t? options.caseSensitive\r\n\t\t\t\t\t: true,\r\n\t\t\t...options,\r\n\t\t};\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Generate a simple UUID\r\n\t */\r\n\tgenerateUUID() {\r\n\t\treturn (\r\n\t\t\t\"highlight-\" +\r\n\t\t\tDate.now() +\r\n\t\t\t\"-\" +\r\n\t\t\tMath.random().toString(36).substring(2, 11)\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * Highlight selected text\r\n\t */\r\n\thighlightSelection() {\r\n\t\tconst selection = window.getSelection();\r\n\t\tif (!selection.toString().trim()) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst range = selection.getRangeAt(0);\r\n\r\n\t\t// 检查选择的范围是否在指定的容器内\r\n\t\tconst container = this.options.container;\r\n\t\tif (\r\n\t\t\t!container.contains(range.startContainer) ||\r\n\t\t\t!container.contains(range.endContainer)\r\n\t\t) {\r\n\t\t\treturn false; // 选择超出了指定容器范围\r\n\t\t}\r\n\r\n\t\t// 更全面地检查整个范围是否在容器内\r\n\t\tconst commonAncestor = range.commonAncestorContainer;\r\n\t\tif (!container.contains(commonAncestor)) {\r\n\t\t\treturn false; // 整个范围不在容器内\r\n\t\t}\r\n\r\n\t\t// 严格模式检查:如果启用严格模式,检查选择范围内是否包含目标className的元素\r\n\t\tif (this.options.strictMode) {\r\n\t\t\tif (this.hasTargetClassInSelection(range)) {\r\n\t\t\t\treturn false; // 选择范围内包含目标className的元素,不允许高亮\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst uuid = this.generateUUID();\r\n\t\t\tconst highlightedElement = this.wrapRange(range, uuid);\r\n\r\n\t\t\tthis.highlights.push({\r\n\t\t\t\tuuid: uuid,\r\n\t\t\t\ttext: selection.toString(),\r\n\t\t\t});\r\n\r\n\t\t\treturn true;\r\n\t\t} catch (error) {\r\n\t\t\tconsole.warn(\"Could not highlight selection:\", error);\r\n\t\t\treturn false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Check if the selection range contains elements with the target class\r\n\t * @param {Range} range - The range to check\r\n\t */\r\n\thasTargetClassInSelection(range) {\r\n\t\t// Check if startContainer or endContainer themselves have the target class\r\n\t\tconst startElement =\r\n\t\t\trange.startContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.startContainer\r\n\t\t\t\t: range.startContainer.parentElement;\r\n\r\n\t\tconst endElement =\r\n\t\t\trange.endContainer.nodeType === Node.ELEMENT_NODE\r\n\t\t\t\t? range.endContainer\r\n\t\t\t\t: range.endContainer.parentElement;\r\n\r\n\t\tif (\r\n\t\t\tstartElement &&\r\n\t\t\tstartElement.classList &&\r\n\t\t\tstartElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (\r\n\t\t\tendElement &&\r\n\t\t\tendElement.classList &&\r\n\t\t\tendElement.classList.contains(this.options.className)\r\n\t\t) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\t// Create a temporary div to work with the range content\r\n\t\tconst tempDiv = document.createElement(\"div\");\r\n\t\ttempDiv.appendChild(range.cloneContents());\r\n\r\n\t\t// Check if any child elements have the target class\r\n\t\tconst elementsWithTargetClass = tempDiv.querySelectorAll(\r\n\t\t\t`.${this.options.className}`,\r\n\t\t);\r\n\t\treturn elementsWithTargetClass.length > 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Wrap a range with highlight element\r\n\t * @param {Range} range - The range to wrap\r\n\t * @param {string} uuid - Unique identifier for the highlight\r\n\t */\r\n\twrapRange(range, uuid) {\r\n\t\tconst highlightEl = document.createElement(\"span\");\r\n\t\thighlightEl.className = this.options.className;\r\n\t\thighlightEl.style.backgroundColor = this.options.color;\r\n\t\thighlightEl.style.padding = \"0\";\r\n\t\thighlightEl.style.margin = \"0\";\r\n\r\n\t\t// Add UUID as data attribute\r\n\t\thighlightEl.setAttribute(\"data-uuid\", uuid);\r\n\r\n\t\t// Clone the range and insert the highlight element\r\n\t\trange.surroundContents(highlightEl);\r\n\r\n\t\treturn highlightEl;\r\n\t}\r\n\r\n\t/**\r\n\t * Remove all highlights\r\n\t */\r\n\tremoveAllHighlights() {\r\n\t\tthis.highlights.forEach((highlight) => {\r\n\t\t\tconst element = document.querySelector(\r\n\t\t\t\t`[data-uuid=\"${highlight.uuid}\"]`,\r\n\t\t\t);\r\n\t\t\tif (element && element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\telement.parentNode.replaceChild(textNode, element);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.highlights = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Get all highlighted elements\r\n\t */\r\n\tgetHighlights() {\r\n\t\t// Return highlights with uuid and text\r\n\t\treturn [...this.highlights];\r\n\t}\r\n\r\n\t/**\r\n\t * Remove a specific highlight\r\n\t * @param {Object} highlight - The highlight object to remove (containing uuid)\r\n\t */\r\n\tremoveHighlight(highlight) {\r\n\t\tconst index = this.highlights.findIndex(\r\n\t\t\t(h) => h.uuid === highlight.uuid,\r\n\t\t);\r\n\t\tif (index !== -1) {\r\n\t\t\t// Restore the original text\r\n\t\t\tconst element = document.querySelector(\r\n\t\t\t\t`[data-uuid=\"${highlight.uuid}\"]`,\r\n\t\t\t);\r\n\t\t\tif (element && element.parentNode) {\r\n\t\t\t\tconst textNode = document.createTextNode(highlight.text);\r\n\t\t\t\telement.parentNode.replaceChild(textNode, element);\r\n\t\t\t}\r\n\r\n\t\t\t// Remove from the highlights array\r\n\t\t\tthis.highlights.splice(index, 1);\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\t/**\r\n\t * Set highlights data\r\n\t * @param {Array} highlights - Array of highlight objects with uuid and text properties\r\n\t */\r\n\tsetHighlights(highlights) {\r\n\t\t// Validate the input to ensure it's an array of objects with required properties\r\n\t\tif (!Array.isArray(highlights)) {\r\n\t\t\tthrow new Error(\"Highlights must be an array\");\r\n\t\t}\r\n\r\n\t\t// Validate each highlight object\r\n\t\tfor (const highlight of highlights) {\r\n\t\t\tif (\r\n\t\t\t\ttypeof highlight !== \"object\" ||\r\n\t\t\t\t!highlight.hasOwnProperty(\"uuid\") ||\r\n\t\t\t\t!highlight.hasOwnProperty(\"text\")\r\n\t\t\t) {\r\n\t\t\t\tthrow new Error(\r\n\t\t\t\t\t\"Each highlight must be an object with uuid and text properties\",\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Clear existing highlights\r\n\t\tthis.removeAllHighlights();\r\n\r\n\t\t// Set the new highlights data\r\n\t\tthis.highlights = [...highlights];\r\n\t}\r\n}\r\n\r\nexport default TextHighlighter;\r\n"],"names":[],"mappings":"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"}