gsarti commited on
Commit
063d3f1
·
verified ·
1 Parent(s): 05d52b1

Update src/frontend/HighlightedTextbox.svelte

Browse files
src/frontend/HighlightedTextbox.svelte CHANGED
@@ -56,25 +56,33 @@
56
  _color_map = correct_color_map(current_color_map, browser, ctx);
57
  }
58
 
59
- function set_text_from_value(as_output: boolean): void {
60
- if (value.length > 0 && as_output) {
61
- el_text = value.map(([text, _]) => text).join("");
62
- marked_el_text = value.map(([text, category]) => {
63
- if (category !== null) {
64
- return `<mark class="hl ${category}" style="background-color:${_color_map[category].secondary}">${text}</mark>`;
65
- } else {
66
- return text;
67
- }
68
- }).join("");
69
- tagged_text = value.map(([text, category]) => {
70
- if (category !== null) {
71
- return `<${category}>${text}</${category}>`;
72
- } else {
73
- return text;
74
- }
75
- }).join("");
76
- }
77
- }
 
 
 
 
 
 
 
 
78
 
79
  $: set_color_map();
80
  $: set_text_from_value(true);
@@ -108,42 +116,66 @@
108
  });
109
 
110
  function set_value_from_marked_span(): void {
111
- let new_value: [string, string | null][] = [];
112
- let text = "";
113
- let category = null;
114
- let in_tag = false;
115
- let tag = "";
116
- // Replace &nbsp;, &amp;, &lt;, &gt; with their corresponding characters
117
- let clean_marked_text = marked_el_text.replace(/&nbsp;|&amp;|&lt;|&gt;/g, function(m) {
118
- return {"&nbsp;":" ", "&amp;":"&", "&lt;":"<", "&gt;":">"}[m];
119
- });
120
- for (let i = 0; i < clean_marked_text.length; i++) {
121
- let char = clean_marked_text[i];
122
- if (char === "<" && (i+5) <= clean_marked_text.length && clean_marked_text.slice(i+1,i+5) === "mark") {
123
- in_tag = true;
124
- if (text) {
125
- new_value.push([text, category]);
126
- }
127
- text = "";
128
- category = null;
129
- } else if (char === ">" && in_tag) {
130
- in_tag = false;
131
- if (tag.slice(0, 4) === "mark") {
132
- let match = /class="hl ([^"]+)"/.exec(tag);
133
- category = match ? match[1] : null;
134
- }
135
- tag = "";
136
- } else if (in_tag) {
137
- tag += char;
138
- } else {
139
- text += char;
140
- }
141
- }
142
- if (text) {
143
- new_value.push([text, category]);
144
- }
145
- value = new_value;
146
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  function handle_remove_tags(): void {
149
  marked_el_text = el_text;
 
56
  _color_map = correct_color_map(current_color_map, browser, ctx);
57
  }
58
 
59
+ function escapeHtml(text: string): string {
60
+ const div = document.createElement('div');
61
+ div.textContent = text;
62
+ return div.innerHTML;
63
+ }
64
+
65
+ function set_text_from_value(as_output: boolean): void {
66
+ if (value.length > 0 && as_output) {
67
+ el_text = value.map(([text, _]) => text).join("");
68
+ marked_el_text = value.map(([text, category]) => {
69
+ // Escape HTML entities in the text
70
+ const escapedText = escapeHtml(text);
71
+ if (category !== null) {
72
+ return `<mark class="hl ${category}" style="background-color:${_color_map[category].secondary}">${escapedText}</mark>`;
73
+ } else {
74
+ return escapedText;
75
+ }
76
+ }).join("");
77
+ tagged_text = value.map(([text, category]) => {
78
+ if (category !== null) {
79
+ return `<${category}>${text}</${category}>`;
80
+ } else {
81
+ return text;
82
+ }
83
+ }).join("");
84
+ }
85
+ }
86
 
87
  $: set_color_map();
88
  $: set_text_from_value(true);
 
116
  });
117
 
118
  function set_value_from_marked_span(): void {
119
+ let new_value: [string, string | null][] = [];
120
+ let text = "";
121
+ let category = null;
122
+
123
+ // Create a temporary container to parse the HTML properly
124
+ const tempDiv = document.createElement('div');
125
+ tempDiv.innerHTML = marked_el_text;
126
+
127
+ // Function to recursively process nodes
128
+ function processNode(node: Node) {
129
+ if (node.nodeType === Node.TEXT_NODE) {
130
+ // Text node - add to current text
131
+ text += node.textContent || '';
132
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
133
+ const element = node as HTMLElement;
134
+
135
+ if (element.tagName.toLowerCase() === 'mark') {
136
+ // Save any accumulated text before the mark
137
+ if (text) {
138
+ new_value.push([text, category]);
139
+ text = "";
140
+ }
141
+
142
+ // Extract category from mark class
143
+ const classList = element.className.split(' ');
144
+ const hlIndex = classList.indexOf('hl');
145
+ category = hlIndex >= 0 && hlIndex + 1 < classList.length ? classList[hlIndex + 1] : null;
146
+
147
+ // Process mark content
148
+ for (let child of element.childNodes) {
149
+ processNode(child);
150
+ }
151
+
152
+ // Save marked text
153
+ if (text) {
154
+ new_value.push([text, category]);
155
+ text = "";
156
+ category = null;
157
+ }
158
+ } else {
159
+ // Other elements - process children
160
+ for (let child of element.childNodes) {
161
+ processNode(child);
162
+ }
163
+ }
164
+ }
165
+ }
166
+
167
+ // Process all nodes
168
+ for (let node of tempDiv.childNodes) {
169
+ processNode(node);
170
+ }
171
+
172
+ // Add any remaining text
173
+ if (text) {
174
+ new_value.push([text, category]);
175
+ }
176
+
177
+ value = new_value;
178
+ }
179
 
180
  function handle_remove_tags(): void {
181
  marked_el_text = el_text;