@editora/core 1.0.2 → 1.0.3

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,2022 @@
1
+ class P {
2
+ constructor(e = "") {
3
+ this._lines = [], this._version = 0, this.setText(e);
4
+ }
5
+ // Get line at index
6
+ getLine(e) {
7
+ return this._lines[e] || "";
8
+ }
9
+ // Get all lines
10
+ getLines() {
11
+ return [...this._lines];
12
+ }
13
+ // Get total number of lines
14
+ getLineCount() {
15
+ return this._lines.length;
16
+ }
17
+ // Get total text content
18
+ getText() {
19
+ return this._lines.join(`
20
+ `);
21
+ }
22
+ // Set entire text content
23
+ setText(e) {
24
+ this._lines = e.split(`
25
+ `), this._version++;
26
+ }
27
+ // Get text in a range
28
+ getTextInRange(e) {
29
+ if (e.start.line === e.end.line)
30
+ return this.getLine(e.start.line).substring(e.start.column, e.end.column);
31
+ const t = [];
32
+ t.push(this.getLine(e.start.line).substring(e.start.column));
33
+ for (let s = e.start.line + 1; s < e.end.line; s++)
34
+ t.push(this.getLine(s));
35
+ return e.end.line < this.getLineCount() && t.push(this.getLine(e.end.line).substring(0, e.end.column)), t.join(`
36
+ `);
37
+ }
38
+ // Replace text in range
39
+ replaceRange(e, t) {
40
+ const s = this.getTextInRange(e);
41
+ if (e.start.line === e.end.line) {
42
+ const i = this.getLine(e.start.line), r = i.substring(0, e.start.column) + t + i.substring(e.end.column);
43
+ this._lines[e.start.line] = r;
44
+ } else {
45
+ const i = this.getLine(e.start.line), r = this.getLine(e.end.line), n = i.substring(0, e.start.column) + t, o = r.substring(e.end.column), a = t.split(`
46
+ `);
47
+ a[0] = n + a[0], a[a.length - 1] = a[a.length - 1] + o, this._lines.splice(e.start.line, e.end.line - e.start.line + 1, ...a);
48
+ }
49
+ return this._version++, { range: e, text: t, oldText: s };
50
+ }
51
+ // Insert text at position
52
+ insertText(e, t) {
53
+ const s = { start: e, end: e };
54
+ return this.replaceRange(s, t);
55
+ }
56
+ // Delete text in range
57
+ deleteRange(e) {
58
+ return this.replaceRange(e, "");
59
+ }
60
+ // Convert position to offset
61
+ positionToOffset(e) {
62
+ let t = 0;
63
+ for (let s = 0; s < e.line; s++)
64
+ t += this.getLine(s).length + 1;
65
+ return t += e.column, t;
66
+ }
67
+ // Convert offset to position
68
+ offsetToPosition(e) {
69
+ let t = e;
70
+ for (let s = 0; s < this.getLineCount(); s++) {
71
+ const i = this.getLine(s).length;
72
+ if (t <= i)
73
+ return { line: s, column: t };
74
+ t -= i + 1;
75
+ }
76
+ return {
77
+ line: this.getLineCount() - 1,
78
+ column: this.getLine(this.getLineCount() - 1).length
79
+ };
80
+ }
81
+ // Validate position
82
+ isValidPosition(e) {
83
+ return !(e.line < 0 || e.line >= this.getLineCount() || e.column < 0 || e.column > this.getLine(e.line).length);
84
+ }
85
+ // Validate range
86
+ isValidRange(e) {
87
+ return this.isValidPosition(e.start) && this.isValidPosition(e.end);
88
+ }
89
+ // Get version for change tracking
90
+ getVersion() {
91
+ return this._version;
92
+ }
93
+ // Clone the model
94
+ clone() {
95
+ const e = new P();
96
+ return e._lines = [...this._lines], e._version = this._version, e;
97
+ }
98
+ }
99
+ class B {
100
+ constructor(e) {
101
+ this.gutterWidth = 50, this.lineHeight = 21, this.container = e, this.createDOM();
102
+ }
103
+ createDOM() {
104
+ this.container.innerHTML = "";
105
+ const e = document.createElement("div");
106
+ this.editorContainer = e, e.style.cssText = `
107
+ position: relative;
108
+ display: flex;
109
+ width: 100%;
110
+ height: 100%;
111
+ background: var(--editor-background, #1e1e1e);
112
+ color: var(--editor-foreground, #f8f9fa);
113
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
114
+ font-size: 14px;
115
+ line-height: ${this.lineHeight}px;
116
+ /* make the outer container the single scrollable element so gutter and content scroll together */
117
+ overflow: auto;
118
+ `, this.lineNumbersElement = document.createElement("div"), this.lineNumbersElement.setAttribute("data-editor-gutter", "true"), this.lineNumbersElement.style.cssText = `
119
+ display: table-cell;
120
+ vertical-align: top;
121
+ width: ${this.gutterWidth}px;
122
+ background: var(--editor-gutter-background, #252526);
123
+ color: var(--editor-gutter-foreground, #858585);
124
+ padding: 0 8px 0 0;
125
+ text-align: right;
126
+ border-right: 1px solid var(--editor-gutter-border, #3e3e42);
127
+ user-select: none;
128
+ z-index: 1;
129
+ `, this.contentElement = document.createElement("div"), this.contentElement.style.cssText = `
130
+ display: table-cell;
131
+ vertical-align: top;
132
+ padding: 0 12px;
133
+ background: transparent;
134
+ border: none;
135
+ outline: none;
136
+ white-space: pre;
137
+ overflow-x: auto;
138
+ overflow-y: visible;
139
+ min-height: 400px;
140
+ font-family: inherit;
141
+ font-size: inherit;
142
+ line-height: inherit;
143
+ color: inherit;
144
+ tab-size: 2;
145
+ -moz-tab-size: 2;
146
+ `, this.contentElement.contentEditable = "true", this.contentElement.spellcheck = !1;
147
+ const t = document.createElement("div");
148
+ t.setAttribute("data-editora-editor", "true"), t.style.cssText = "display: table; table-layout: fixed; width: 100%; height: 100%;", t.appendChild(this.lineNumbersElement), t.appendChild(this.contentElement), e.appendChild(t), this.container.appendChild(e), this.updateLineNumbers(1);
149
+ }
150
+ // Update line numbers
151
+ updateLineNumbers(e) {
152
+ const t = Math.max(e, 20), s = Array.from({ length: t }, (i, r) => r + 1);
153
+ this.lineNumbersElement.innerHTML = s.map((i) => `<div style="height: ${this.lineHeight}px; line-height: ${this.lineHeight}px; padding-right: 12px;">${i}</div>`).join("");
154
+ }
155
+ // Get content element
156
+ getContentElement() {
157
+ return this.contentElement;
158
+ }
159
+ // Get line numbers element
160
+ getLineNumbersElement() {
161
+ return this.lineNumbersElement;
162
+ }
163
+ // Get text content
164
+ getText() {
165
+ return this.contentElement.textContent || "";
166
+ }
167
+ // Set text content
168
+ setText(e) {
169
+ this.contentElement.textContent = e;
170
+ const t = e.split(`
171
+ `).length;
172
+ this.updateLineNumbers(t);
173
+ }
174
+ // Set inner HTML (used for syntax highlighted content)
175
+ setHTML(e) {
176
+ const t = /&lt;|&gt;/.test(e), s = /<span\b/i.test(e), i = /<[^>]+>/.test(e);
177
+ t && s ? this.contentElement.innerHTML = e : i && !t ? this.contentElement.textContent = e : this.contentElement.innerHTML = e;
178
+ const r = (this.contentElement.textContent || "").split(`
179
+ `).length;
180
+ this.updateLineNumbers(r);
181
+ }
182
+ // Get cursor position from DOM selection
183
+ getCursorPosition() {
184
+ const e = window.getSelection();
185
+ if (!e || e.rangeCount === 0)
186
+ return { line: 0, column: 0 };
187
+ const t = e.getRangeAt(0), s = t.cloneRange();
188
+ s.selectNodeContents(this.contentElement), s.setEnd(t.endContainer, t.endOffset);
189
+ const i = s.toString().split(`
190
+ `);
191
+ return {
192
+ line: i.length - 1,
193
+ column: i[i.length - 1].length
194
+ };
195
+ }
196
+ // Set cursor position
197
+ setCursorPosition(e) {
198
+ var g, d;
199
+ const t = this.getText().split(`
200
+ `), s = Math.min(e.line, t.length - 1), i = Math.min(e.column, ((g = t[s]) == null ? void 0 : g.length) || 0);
201
+ let r = 0;
202
+ for (let f = 0; f < s; f++)
203
+ r += t[f].length + 1;
204
+ r += i;
205
+ const n = document.createRange(), o = window.getSelection();
206
+ let a = 0, c = null, l = 0;
207
+ const h = document.createTreeWalker(
208
+ this.contentElement,
209
+ NodeFilter.SHOW_TEXT,
210
+ null
211
+ );
212
+ let u;
213
+ for (; u = h.nextNode(); ) {
214
+ const f = ((d = u.textContent) == null ? void 0 : d.length) || 0;
215
+ if (a + f >= r) {
216
+ c = u, l = r - a;
217
+ break;
218
+ }
219
+ a += f;
220
+ }
221
+ if (c)
222
+ try {
223
+ n.setStart(c, l), n.setEnd(c, l), o == null || o.removeAllRanges(), o == null || o.addRange(n);
224
+ } catch (f) {
225
+ console.warn("Could not set cursor position:", f);
226
+ }
227
+ }
228
+ // Get selection range
229
+ getSelectionRange() {
230
+ const e = window.getSelection();
231
+ if (!e || e.rangeCount === 0 || e.isCollapsed)
232
+ return;
233
+ const t = e.getRangeAt(0), s = t.cloneRange();
234
+ s.selectNodeContents(this.contentElement), s.setEnd(t.startContainer, t.startOffset);
235
+ const i = s.toString().split(`
236
+ `), r = t.cloneRange();
237
+ r.selectNodeContents(this.contentElement), r.setEnd(t.endContainer, t.endOffset);
238
+ const n = r.toString().split(`
239
+ `);
240
+ return {
241
+ start: {
242
+ line: i.length - 1,
243
+ column: i[i.length - 1].length
244
+ },
245
+ end: {
246
+ line: n.length - 1,
247
+ column: n[n.length - 1].length
248
+ }
249
+ };
250
+ }
251
+ // Set selection range
252
+ setSelectionRange(e) {
253
+ this.setCursorPosition(e.start);
254
+ }
255
+ // Focus the editor
256
+ focus() {
257
+ this.contentElement.focus();
258
+ }
259
+ // Blur the editor
260
+ blur() {
261
+ this.contentElement.blur();
262
+ }
263
+ // Set read-only mode
264
+ setReadOnly(e) {
265
+ this.contentElement.contentEditable = e ? "false" : "true";
266
+ }
267
+ // Apply theme
268
+ applyTheme(e) {
269
+ Object.entries(e).forEach(([t, s]) => {
270
+ this.container.style.setProperty(`--${t}`, s);
271
+ });
272
+ }
273
+ // Scroll to position
274
+ scrollToPosition(e) {
275
+ const t = this.lineNumbersElement.children[e.line];
276
+ t && t.scrollIntoView({ block: "center", behavior: "smooth" });
277
+ }
278
+ // Get scroll position
279
+ getScrollTop() {
280
+ return this.editorContainer.scrollTop;
281
+ }
282
+ // Set scroll position
283
+ setScrollTop(e) {
284
+ this.editorContainer.scrollTop = e;
285
+ }
286
+ // Destroy the view
287
+ destroy() {
288
+ this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this._rafId && (cancelAnimationFrame(this._rafId), this._rafId = void 0);
289
+ }
290
+ }
291
+ class K {
292
+ constructor(e, t = {}) {
293
+ this.extensions = /* @__PURE__ */ new Map(), this.commands = /* @__PURE__ */ new Map(), this.eventListeners = /* @__PURE__ */ new Map(), this.folds = [], this.currentTheme = "default", this.isDestroyed = !1, this.undoStack = [], this.redoStack = [], this.suppressHistory = !1, this.expectingProgrammaticCursor = !1, this.config = {
294
+ value: "",
295
+ theme: "default",
296
+ readOnly: !1,
297
+ tabSize: 2,
298
+ lineWrapping: !1,
299
+ lineNumbers: !0,
300
+ ...t
301
+ }, this.textModel = new P(this.config.value), this.view = new B(e), this.setupEventHandlers(), this.config.extensions && this.config.extensions.forEach((s) => this.addExtension(s)), this.setTheme(this.config.theme), this.view.setReadOnly(this.config.readOnly || !1), this.renderTextWithHighlight(this.textModel.getText()), this.registerBuiltInCommands();
302
+ }
303
+ // Public accessors for extensions
304
+ getTextModel() {
305
+ return this.textModel;
306
+ }
307
+ getView() {
308
+ return this.view;
309
+ }
310
+ getConfig() {
311
+ return { ...this.config };
312
+ }
313
+ // Register built-in editor commands like undo/redo/insertTab
314
+ registerBuiltInCommands() {
315
+ this.registerCommand("undo", () => this.undo()), this.registerCommand("redo", () => this.redo()), this.registerCommand("insertTab", () => this.insertTab()), this.registerCommand("save", () => {
316
+ this.emit("save");
317
+ });
318
+ }
319
+ // Get keymap extension if available
320
+ getKeymapExtension() {
321
+ return this.extensions.get("keymap");
322
+ }
323
+ // Setup DOM event handlers
324
+ setupEventHandlers() {
325
+ const e = this.view.getContentElement();
326
+ e.addEventListener("input", () => {
327
+ const t = this.view.getText(), s = this.textModel.getText();
328
+ if (t !== s) {
329
+ if (!this.suppressHistory) {
330
+ const i = this.getCursor().position, r = this.textModel.positionToOffset(i), n = this.getSelection();
331
+ let o, a;
332
+ n && (o = this.textModel.positionToOffset(n.start), a = this.textModel.positionToOffset(n.end)), this.undoStack.push({ text: s, cursorOffset: r, anchorOffset: o, focusOffset: a }), this.undoStack.length > 100 && this.undoStack.shift(), this.redoStack.length = 0;
333
+ }
334
+ this.textModel.setText(t), this.highlightTimeout && clearTimeout(this.highlightTimeout), this.highlightTimeout = setTimeout(() => {
335
+ this.renderTextWithHighlight(this.textModel.getText(), !1), this.highlightTimeout = null;
336
+ }, 300), this.updateLineNumbers(), this.emit("change", [{ range: this.getFullRange(), text: t, oldText: s }]);
337
+ }
338
+ }), e.addEventListener("selectionchange", () => {
339
+ const t = this.getCursor(), s = this.getSelection();
340
+ this.emit("cursor", t), s && this.emit("selection", s);
341
+ }), e.addEventListener("keydown", (t) => {
342
+ if (this.emit("keydown", t), t.key === "Tab") {
343
+ this.config.readOnly || this.insertTab(), t.preventDefault(), t.stopPropagation();
344
+ return;
345
+ }
346
+ if (t.key === "Enter") {
347
+ if (!this.config.readOnly) {
348
+ const s = window.getSelection();
349
+ if (s && s.rangeCount > 0) {
350
+ const i = this.getCursor().position, r = this.textModel.positionToOffset(i), n = this.getSelection();
351
+ let o, a;
352
+ n && (o = this.textModel.positionToOffset(n.start), a = this.textModel.positionToOffset(n.end)), this.suppressHistory || (this.undoStack.push({ text: this.textModel.getText(), cursorOffset: r, anchorOffset: o, focusOffset: a }), this.undoStack.length > 100 && this.undoStack.shift(), this.redoStack.length = 0);
353
+ const c = s.getRangeAt(0);
354
+ c.deleteContents();
355
+ const l = document.createTextNode(`
356
+ `);
357
+ c.insertNode(l), c.setStartAfter(l), c.collapse(!0), s.removeAllRanges(), s.addRange(c);
358
+ const h = this.getCursor().position, u = this.textModel.positionToOffset(h), g = this.getSelection();
359
+ let d, f;
360
+ g && (d = this.textModel.positionToOffset(g.start), f = this.textModel.positionToOffset(g.end));
361
+ const p = this.view.getText();
362
+ this.textModel.setText(p), this.highlightTimeout && clearTimeout(this.highlightTimeout), this.highlightTimeout = setTimeout(() => {
363
+ this.renderTextWithHighlight(this.textModel.getText(), !1), requestAnimationFrame(() => {
364
+ try {
365
+ if (g && (d !== void 0 || f !== void 0)) {
366
+ const x = d !== void 0 ? d : u, y = f !== void 0 ? f : u, v = Math.min(x, y), C = Math.max(x, y), L = this.textModel.offsetToPosition(v), T = this.textModel.offsetToPosition(C);
367
+ this.setSelection({ start: L, end: T });
368
+ } else {
369
+ const x = this.textModel.offsetToPosition(u);
370
+ this.setCursor(x);
371
+ }
372
+ } catch (x) {
373
+ }
374
+ }), this.highlightTimeout = null;
375
+ }, 300), this.updateLineNumbers(), this.emit("change", [{ range: this.getFullRange(), text: this.getValue(), oldText: "" }]);
376
+ }
377
+ }
378
+ t.preventDefault(), t.stopPropagation();
379
+ return;
380
+ }
381
+ for (const s of this.extensions.values())
382
+ if (s.onKeyDown && s.onKeyDown(t) === !1) {
383
+ t.preventDefault(), t.stopPropagation();
384
+ return;
385
+ }
386
+ }), e.addEventListener("mousedown", (t) => {
387
+ this.emit("mousedown", t);
388
+ for (const s of this.extensions.values())
389
+ if (s.onMouseDown && s.onMouseDown(t) === !1) {
390
+ t.preventDefault(), t.stopPropagation();
391
+ return;
392
+ }
393
+ }), e.addEventListener("focus", () => {
394
+ this.emit("focus");
395
+ }), e.addEventListener("blur", () => {
396
+ this.emit("blur");
397
+ });
398
+ }
399
+ // Update line numbers display
400
+ updateLineNumbers() {
401
+ const e = this.textModel.getLineCount();
402
+ this.view.updateLineNumbers(e);
403
+ }
404
+ // Get full range of document
405
+ getFullRange() {
406
+ return {
407
+ start: { line: 0, column: 0 },
408
+ end: {
409
+ line: this.textModel.getLineCount() - 1,
410
+ column: this.textModel.getLine(this.textModel.getLineCount() - 1).length
411
+ }
412
+ };
413
+ }
414
+ // Emit events to listeners
415
+ emit(e, ...t) {
416
+ const s = this.eventListeners.get(e);
417
+ s && s.forEach((i) => i(...t));
418
+ }
419
+ // State management
420
+ getValue() {
421
+ return this.textModel.getText();
422
+ }
423
+ setValue(e) {
424
+ const t = this.textModel.getText();
425
+ this.textModel.setText(e), this.renderTextWithHighlight(e, !1), this.updateLineNumbers(), this.emit("change", [{ range: this.getFullRange(), text: e, oldText: t }]);
426
+ }
427
+ getState() {
428
+ return {
429
+ text: this.getValue(),
430
+ cursor: this.getCursor(),
431
+ selection: this.getSelection(),
432
+ readOnly: this.config.readOnly || !1,
433
+ theme: this.currentTheme
434
+ };
435
+ }
436
+ // Cursor & Selection
437
+ getCursor() {
438
+ const e = this.view.getCursorPosition();
439
+ return {
440
+ position: e,
441
+ anchor: e
442
+ // For now, cursor and anchor are the same
443
+ };
444
+ }
445
+ setCursor(e) {
446
+ this.view.setCursorPosition(e), this.emit("cursor", this.getCursor());
447
+ }
448
+ getSelection() {
449
+ return this.view.getSelectionRange();
450
+ }
451
+ setSelection(e) {
452
+ this.view.setSelectionRange(e), this.emit("selection", e);
453
+ }
454
+ // Configuration
455
+ setTheme(e) {
456
+ this.currentTheme = e;
457
+ const t = {
458
+ "editor-background": e === "dark" ? "#1e1e1e" : "#ffffff",
459
+ "editor-foreground": e === "dark" ? "#f8f9fa" : "#1a1a1a",
460
+ "editor-gutter-background": e === "dark" ? "#252526" : "#f8f9fa",
461
+ "editor-gutter-foreground": e === "dark" ? "#858585" : "#666666",
462
+ "editor-gutter-border": e === "dark" ? "#3e3e42" : "#e1e5e9"
463
+ };
464
+ this.view.applyTheme(t);
465
+ const s = this.extensions.get("syntax-highlighting");
466
+ if (s && typeof s.setTheme == "function")
467
+ try {
468
+ s.setTheme(e === "dark" ? "dark" : "light"), this.renderTextWithHighlight(this.textModel.getText());
469
+ } catch (i) {
470
+ console.warn("Error applying theme to syntax-highlighting extension", i);
471
+ }
472
+ }
473
+ setReadOnly(e) {
474
+ this.config.readOnly = e, this.view.setReadOnly(e);
475
+ }
476
+ // Extensions & Commands
477
+ addExtension(e) {
478
+ if (this.extensions.has(e.name))
479
+ throw new Error(`Extension '${e.name}' already exists`);
480
+ this.extensions.set(e.name, e), e.setup(this), e.name === "syntax-highlighting" && typeof e.highlightHTML == "function" && this.renderTextWithHighlight(this.textModel.getText());
481
+ }
482
+ removeExtension(e) {
483
+ const t = this.extensions.get(e);
484
+ t && t.destroy && t.destroy(), this.extensions.delete(e);
485
+ }
486
+ executeCommand(e, ...t) {
487
+ const s = this.commands.get(e);
488
+ s ? s(this, ...t) : console.warn(`Command '${e}' not found`);
489
+ }
490
+ // Register a command
491
+ registerCommand(e, t) {
492
+ this.commands.set(e, t);
493
+ }
494
+ // Search & Navigation
495
+ search(e, t = {}) {
496
+ const s = {
497
+ caseSensitive: !1,
498
+ regex: !1,
499
+ ...t
500
+ }, i = [], r = this.getValue();
501
+ r.split(`
502
+ `);
503
+ let n = s.caseSensitive ? r : r.toLowerCase(), o = s.caseSensitive ? e : e.toLowerCase();
504
+ if (s.regex) {
505
+ const a = new RegExp(o, s.caseSensitive ? "g" : "gi");
506
+ let c;
507
+ for (; (c = a.exec(n)) !== null; ) {
508
+ const l = this.textModel.offsetToPosition(c.index), h = this.textModel.offsetToPosition(c.index + c[0].length);
509
+ i.push({
510
+ range: { start: l, end: h },
511
+ match: c[0]
512
+ });
513
+ }
514
+ } else {
515
+ let a = 0, c = n.indexOf(o, a);
516
+ for (; c !== -1; ) {
517
+ const l = c + e.length, h = this.textModel.offsetToPosition(c), u = this.textModel.offsetToPosition(l);
518
+ i.push({
519
+ range: { start: h, end: u },
520
+ match: r.substring(c, l)
521
+ }), a = l, c = n.indexOf(o, a);
522
+ }
523
+ }
524
+ return i;
525
+ }
526
+ replace(e, t) {
527
+ const s = this.getValue();
528
+ if (!this.suppressHistory) {
529
+ const r = this.getCursor().position, n = this.textModel.positionToOffset(r), o = this.getSelection();
530
+ let a, c;
531
+ o && (a = this.textModel.positionToOffset(o.start), c = this.textModel.positionToOffset(o.end)), this.undoStack.push({ text: s, cursorOffset: n, anchorOffset: a, focusOffset: c }), this.undoStack.length > 100 && this.undoStack.shift(), this.redoStack.length = 0;
532
+ }
533
+ const i = this.textModel.replaceRange(e, t);
534
+ this.renderTextWithHighlight(this.getValue(), !1), this.emit("change", [i]);
535
+ }
536
+ replaceAll(e, t, s = {}) {
537
+ const i = this.search(e, s);
538
+ let r = 0;
539
+ for (let n = i.length - 1; n >= 0; n--)
540
+ this.replace(i[n].range, t), r++;
541
+ return r;
542
+ }
543
+ // Folding (basic implementation)
544
+ fold(e) {
545
+ const t = {
546
+ start: e.start,
547
+ end: e.end,
548
+ collapsed: !0,
549
+ level: 0
550
+ };
551
+ this.folds.push(t);
552
+ }
553
+ unfold(e) {
554
+ this.folds = this.folds.filter(
555
+ (t) => !(t.start.line === e.start.line && t.end.line === e.end.line)
556
+ );
557
+ }
558
+ getFolds() {
559
+ return [...this.folds];
560
+ }
561
+ // Utilities
562
+ focus() {
563
+ this.view.focus();
564
+ }
565
+ blur() {
566
+ this.view.blur();
567
+ }
568
+ // Render text using syntax highlighting extension if available
569
+ // If `restoreSelection` is true (default), the method captures current selection/caret
570
+ // and restores it after updating the DOM. Callers that will explicitly set the caret
571
+ // should pass `false` to avoid stomping programmatic cursor changes.
572
+ renderTextWithHighlight(e, t = !0) {
573
+ const s = this.extensions.get("syntax-highlighting");
574
+ if (s && typeof s.highlightHTML == "function")
575
+ try {
576
+ const i = !t && !this.expectingProgrammaticCursor;
577
+ let r, n, o, a;
578
+ if (t || i) {
579
+ r = this.getSelection();
580
+ const l = this.getCursor().position;
581
+ n = this.textModel.positionToOffset(l), r && (o = this.textModel.positionToOffset(r.start), a = this.textModel.positionToOffset(r.end));
582
+ }
583
+ const c = s.highlightHTML(e);
584
+ typeof this.view.setHighlightHTML == "function" ? this.view.setHighlightHTML(c) : this.view.setHTML(c), (t || i) && requestAnimationFrame(() => {
585
+ try {
586
+ if (r && (o !== void 0 || a !== void 0)) {
587
+ const l = o !== void 0 ? o : n, h = a !== void 0 ? a : n, u = Math.min(l, h), g = Math.max(l, h), d = this.textModel.offsetToPosition(u), f = this.textModel.offsetToPosition(g);
588
+ this.view.setSelectionRange({ start: d, end: f });
589
+ } else if (n !== void 0) {
590
+ const l = this.textModel.offsetToPosition(n);
591
+ this.view.setCursorPosition(l);
592
+ }
593
+ } catch (l) {
594
+ }
595
+ });
596
+ return;
597
+ } catch (i) {
598
+ console.warn("Syntax highlighting failed, falling back to plain text", i);
599
+ }
600
+ this.view.setText(e);
601
+ }
602
+ destroy() {
603
+ if (!this.isDestroyed) {
604
+ this.isDestroyed = !0;
605
+ for (const e of this.extensions.values())
606
+ e.destroy && e.destroy();
607
+ this.extensions.clear(), this.view.destroy(), this.commands.clear(), this.eventListeners.clear();
608
+ }
609
+ }
610
+ // History: undo/redo
611
+ undo() {
612
+ if (this.undoStack.length === 0) return;
613
+ const e = this.undoStack.pop(), t = { text: this.getValue(), cursorOffset: this.textModel.positionToOffset(this.getCursor().position) };
614
+ this.redoStack.push(t);
615
+ try {
616
+ this.suppressHistory = !0, this.expectingProgrammaticCursor = !0;
617
+ let s, i;
618
+ typeof e == "string" ? s = e : (s = e.text, i = e.cursorOffset), this.setValue(s), requestAnimationFrame(() => {
619
+ try {
620
+ if (i != null)
621
+ if (typeof e != "string" && (e.anchorOffset !== void 0 || e.focusOffset !== void 0)) {
622
+ const r = e.anchorOffset !== void 0 ? e.anchorOffset : i, n = e.focusOffset !== void 0 ? e.focusOffset : i, o = Math.min(r, n), a = Math.max(r, n), c = this.textModel.offsetToPosition(o), l = this.textModel.offsetToPosition(a);
623
+ this.setSelection({ start: c, end: l });
624
+ } else {
625
+ const r = this.textModel.offsetToPosition(i);
626
+ this.setCursor(r);
627
+ }
628
+ } catch (r) {
629
+ }
630
+ }), setTimeout(() => {
631
+ this.expectingProgrammaticCursor = !1;
632
+ }, 30);
633
+ } finally {
634
+ this.suppressHistory = !1;
635
+ }
636
+ }
637
+ redo() {
638
+ if (this.redoStack.length === 0) return;
639
+ const e = this.redoStack.pop(), t = { text: this.getValue(), cursorOffset: this.textModel.positionToOffset(this.getCursor().position) };
640
+ this.undoStack.push(t);
641
+ try {
642
+ this.suppressHistory = !0, this.expectingProgrammaticCursor = !0;
643
+ let s, i;
644
+ typeof e == "string" ? s = e : (s = e.text, i = e.cursorOffset), this.setValue(s), requestAnimationFrame(() => {
645
+ try {
646
+ if (i != null)
647
+ if (typeof e != "string" && (e.anchorOffset !== void 0 || e.focusOffset !== void 0)) {
648
+ const r = e.anchorOffset !== void 0 ? e.anchorOffset : i, n = e.focusOffset !== void 0 ? e.focusOffset : i, o = Math.min(r, n), a = Math.max(r, n), c = this.textModel.offsetToPosition(o), l = this.textModel.offsetToPosition(a);
649
+ this.setSelection({ start: c, end: l });
650
+ } else {
651
+ const r = this.textModel.offsetToPosition(i);
652
+ this.setCursor(r);
653
+ }
654
+ } catch (r) {
655
+ }
656
+ }), setTimeout(() => {
657
+ this.expectingProgrammaticCursor = !1;
658
+ }, 30);
659
+ } finally {
660
+ this.suppressHistory = !1;
661
+ }
662
+ }
663
+ // Insert a tab character or spaces at current cursor
664
+ insertTab() {
665
+ if (this.config.readOnly) return;
666
+ const e = this.getCursor().position, t = this.textModel.positionToOffset(e), s = " ".repeat(this.config.tabSize || 2), i = this.textModel.insertText(e, s), r = this.textModel.offsetToPosition(this.textModel.positionToOffset(e) + s.length);
667
+ if (!this.suppressHistory) {
668
+ const n = this.getSelection();
669
+ let o, a;
670
+ n && (o = this.textModel.positionToOffset(n.start), a = this.textModel.positionToOffset(n.end)), this.undoStack.push({ text: this.getValue(), cursorOffset: t, anchorOffset: o, focusOffset: a }), this.redoStack.length = 0;
671
+ }
672
+ this.expectingProgrammaticCursor = !0, this.renderTextWithHighlight(this.getValue(), !1), this.setCursor(r), setTimeout(() => {
673
+ this.expectingProgrammaticCursor = !1;
674
+ }, 20), this.emit("change", [i]);
675
+ }
676
+ // Insert a newline at current cursor position
677
+ insertNewLine() {
678
+ if (this.config.readOnly) return;
679
+ const e = this.getCursor().position, t = this.textModel.positionToOffset(e), s = this.textModel.insertText(e, `
680
+ `), i = this.textModel.offsetToPosition(this.textModel.positionToOffset(e) + 1);
681
+ if (!this.suppressHistory) {
682
+ const r = this.getSelection();
683
+ let n, o;
684
+ r && (n = this.textModel.positionToOffset(r.start), o = this.textModel.positionToOffset(r.end)), this.undoStack.push({ text: this.getValue(), cursorOffset: t, anchorOffset: n, focusOffset: o }), this.redoStack.length = 0;
685
+ }
686
+ this.expectingProgrammaticCursor = !0, this.renderTextWithHighlight(this.getValue(), !1), this.setCursor(i), setTimeout(() => {
687
+ this.expectingProgrammaticCursor = !1;
688
+ }, 20), this.emit("change", [s]);
689
+ }
690
+ // Events
691
+ on(e, t) {
692
+ this.eventListeners.has(e) || this.eventListeners.set(e, []), this.eventListeners.get(e).push(t);
693
+ }
694
+ off(e, t) {
695
+ if (!this.eventListeners.has(e)) return;
696
+ const s = this.eventListeners.get(e);
697
+ if (t) {
698
+ const i = s.indexOf(t);
699
+ i !== -1 && s.splice(i, 1);
700
+ } else
701
+ s.length = 0;
702
+ }
703
+ }
704
+ class V {
705
+ constructor(e) {
706
+ this.name = "keymap", this.editor = null, this.keymap = {}, this.isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0, this.keymap = e || this.getDefaultKeymap();
707
+ }
708
+ setup(e) {
709
+ this.editor = e;
710
+ }
711
+ handleKeyDown(e) {
712
+ if (!this.editor) return;
713
+ const t = this.findMatchingBinding(e);
714
+ if (t)
715
+ return this.editor.executeCommand(t.command), e.preventDefault(), e.stopPropagation(), !1;
716
+ }
717
+ findMatchingBinding(e) {
718
+ const { key: t, ctrlKey: s, altKey: i, shiftKey: r, metaKey: n } = e, o = String(t).toLowerCase(), a = this.keymap[o];
719
+ if (!a) return null;
720
+ for (const c of a) {
721
+ const l = c.ctrlKey === void 0 || c.ctrlKey === s, h = c.altKey === void 0 || c.altKey === i, u = c.shiftKey === void 0 || c.shiftKey === r, g = c.metaKey === void 0 || c.metaKey === n;
722
+ if (l && h && u && g)
723
+ return c;
724
+ }
725
+ return null;
726
+ }
727
+ // Allow EditorCore to call this directly when checking extension.onKeyDown
728
+ onKeyDown(e) {
729
+ return this.handleKeyDown(e);
730
+ }
731
+ getDefaultKeymap() {
732
+ const e = {};
733
+ return this.addBinding(e, "f", { ctrlKey: !this.isMac, metaKey: this.isMac }, "find"), this.addBinding(e, "h", { ctrlKey: !this.isMac, metaKey: this.isMac }, "replace"), this.addBinding(e, "f3", {}, "findNext"), this.addBinding(e, "f3", { shiftKey: !0 }, "findPrev"), this.addBinding(e, "g", { ctrlKey: !this.isMac, metaKey: this.isMac }, "findNext"), this.addBinding(e, "[", { ctrlKey: !this.isMac, metaKey: this.isMac, shiftKey: !0 }, "fold"), this.addBinding(e, "]", { ctrlKey: !this.isMac, metaKey: this.isMac, shiftKey: !0 }, "unfold"), this.addBinding(e, "s", { ctrlKey: !0 }, "save"), this.addBinding(e, "s", { metaKey: !0 }, "save"), this.addBinding(e, "z", { ctrlKey: !0 }, "undo"), this.addBinding(e, "z", { metaKey: !0 }, "undo"), this.addBinding(e, "y", { ctrlKey: !0 }, "redo"), this.addBinding(e, "y", { metaKey: !0 }, "redo"), this.addBinding(e, "z", { ctrlKey: !0, shiftKey: !0 }, "redo"), this.addBinding(e, "z", { metaKey: !0, shiftKey: !0 }, "redo"), this.addBinding(e, "tab", {}, "insertTab"), this.addBinding(e, "t", { ctrlKey: !this.isMac, metaKey: this.isMac, shiftKey: !0 }, "toggleTheme"), e;
734
+ }
735
+ addBinding(e, t, s, i) {
736
+ const r = t.toLowerCase();
737
+ e[r] || (e[r] = []), e[r].push({
738
+ key: r,
739
+ command: i,
740
+ ...s
741
+ });
742
+ }
743
+ // Public API for customizing keymap
744
+ setKeymap(e) {
745
+ this.keymap = { ...e };
746
+ }
747
+ addKeyBinding(e) {
748
+ const t = e.key.toLowerCase();
749
+ this.keymap[t] || (this.keymap[t] = []), this.keymap[t] = this.keymap[t].filter((s) => s.command !== e.command), this.keymap[t].push({
750
+ ...e,
751
+ key: t
752
+ });
753
+ }
754
+ removeKeyBinding(e, t) {
755
+ const s = e.toLowerCase();
756
+ t ? this.keymap[s] && (this.keymap[s] = this.keymap[s].filter((i) => i.command !== t), this.keymap[s].length === 0 && delete this.keymap[s]) : delete this.keymap[s];
757
+ }
758
+ getKeymap() {
759
+ return { ...this.keymap };
760
+ }
761
+ getBindingsForCommand(e) {
762
+ const t = [];
763
+ for (const s in this.keymap)
764
+ for (const i of this.keymap[s])
765
+ i.command === e && t.push({ ...i });
766
+ return t;
767
+ }
768
+ getPlatformInfo() {
769
+ return {
770
+ isMac: this.isMac,
771
+ platform: navigator.platform
772
+ };
773
+ }
774
+ destroy() {
775
+ this.keymap = {}, this.editor = null;
776
+ }
777
+ }
778
+ class A {
779
+ constructor() {
780
+ this.name = "transaction", this.transactions = [];
781
+ }
782
+ setup(e) {
783
+ e.on("change", (t) => {
784
+ const s = {
785
+ changes: [t],
786
+ selection: e.getSelection(),
787
+ effects: [],
788
+ annotations: []
789
+ };
790
+ this.transactions.push(s);
791
+ });
792
+ }
793
+ getTransactions() {
794
+ return this.transactions;
795
+ }
796
+ destroy() {
797
+ this.transactions = [];
798
+ }
799
+ }
800
+ class U {
801
+ constructor() {
802
+ this.name = "line-numbers", this.editor = null, this.lineNumbersElement = null, this.isEnabled = !0;
803
+ }
804
+ setup(e) {
805
+ this.editor = e, this.createLineNumbers(), e.registerCommand("toggleLineNumbers", () => {
806
+ this.toggle();
807
+ }), e.on("change", () => {
808
+ this.updateLineNumbers();
809
+ }), this.updateLineNumbers();
810
+ }
811
+ createLineNumbers() {
812
+ if (!this.editor) return;
813
+ const e = this.editor.getView().getLineNumbersElement();
814
+ e && (this.lineNumbersElement = e);
815
+ }
816
+ updateLineNumbers() {
817
+ if (!this.lineNumbersElement || !this.editor || !this.isEnabled) return;
818
+ const e = this.editor.getValue().split(`
819
+ `).length, t = Array.from({ length: Math.max(e, 20) }, (s, i) => i + 1);
820
+ this.lineNumbersElement.innerHTML = t.map((s) => `<div style="height: 21px; line-height: 21px; padding-right: 12px;">${s}</div>`).join("");
821
+ }
822
+ toggle() {
823
+ this.isEnabled = !this.isEnabled, this.lineNumbersElement && (this.lineNumbersElement.style.display = this.isEnabled ? "block" : "none");
824
+ const e = this.editor.getView().getContentElement();
825
+ e && (e.style.marginLeft = this.isEnabled ? "60px" : "0"), this.updateLineNumbers();
826
+ }
827
+ destroy() {
828
+ this.lineNumbersElement = null, this.editor = null;
829
+ }
830
+ }
831
+ class z {
832
+ constructor() {
833
+ this.name = "theme", this.editor = null, this.currentTheme = "dark";
834
+ }
835
+ setup(e) {
836
+ this.editor = e, e.registerCommand("setTheme", (t) => {
837
+ this.setTheme(t);
838
+ }), e.registerCommand("toggleTheme", () => {
839
+ this.toggleTheme();
840
+ }), this.setTheme(this.currentTheme);
841
+ }
842
+ setTheme(e) {
843
+ this.editor && (this.currentTheme = e, this.editor.setTheme(e));
844
+ }
845
+ toggleTheme() {
846
+ const e = this.currentTheme === "dark" ? "light" : "dark";
847
+ this.setTheme(e);
848
+ }
849
+ getCurrentTheme() {
850
+ return this.currentTheme;
851
+ }
852
+ destroy() {
853
+ this.editor = null;
854
+ }
855
+ }
856
+ class q {
857
+ constructor() {
858
+ this.name = "read-only", this.editor = null, this.isReadOnly = !1;
859
+ }
860
+ setup(e) {
861
+ this.editor = e, e.registerCommand("setReadOnly", (t) => {
862
+ this.setReadOnly(t);
863
+ }), e.registerCommand("toggleReadOnly", () => {
864
+ this.toggleReadOnly();
865
+ }), e.on("keydown", (t) => {
866
+ if (t.ctrlKey && t.key === "r")
867
+ return t.preventDefault(), this.toggleReadOnly(), !1;
868
+ });
869
+ }
870
+ setReadOnly(e) {
871
+ this.editor && (this.isReadOnly = e, this.editor.setReadOnly(e));
872
+ }
873
+ toggleReadOnly() {
874
+ this.setReadOnly(!this.isReadOnly);
875
+ }
876
+ isCurrentlyReadOnly() {
877
+ return this.isReadOnly;
878
+ }
879
+ destroy() {
880
+ this.editor = null;
881
+ }
882
+ }
883
+ class F {
884
+ constructor() {
885
+ this.name = "search", this.editor = null, this.searchUI = null, this.isVisible = !1, this.currentResults = [], this.currentIndex = -1;
886
+ }
887
+ setup(e) {
888
+ this.editor = e, e.registerCommand("find", () => {
889
+ this.showSearch();
890
+ }), e.registerCommand("findNext", () => {
891
+ this.findNext();
892
+ }), e.registerCommand("findPrev", () => {
893
+ this.findPrev();
894
+ }), e.registerCommand("replace", () => {
895
+ this.showReplace();
896
+ }), e.registerCommand("replaceAll", (t, s) => {
897
+ this.replaceAll(t, s);
898
+ });
899
+ }
900
+ showSearch() {
901
+ if (this.editor && (this.searchUI || this.createSearchUI(), this.isVisible = !0, this.searchUI)) {
902
+ this.searchUI.style.display = "block";
903
+ const e = this.searchUI.querySelector("input");
904
+ e && (e.focus(), e.select());
905
+ }
906
+ }
907
+ showReplace() {
908
+ var s, i;
909
+ this.showSearch();
910
+ const e = (s = this.searchUI) == null ? void 0 : s.querySelector(".search-replace-input");
911
+ e && (e.style.display = "block", e.focus());
912
+ const t = (i = this.searchUI) == null ? void 0 : i.querySelector(".search-status");
913
+ t && (t.textContent = "Replace mode - Enter to replace, Shift+Enter to replace all");
914
+ }
915
+ hideSearch() {
916
+ this.isVisible = !1, this.searchUI && (this.searchUI.style.display = "none"), this.clearHighlights();
917
+ }
918
+ createSearchUI() {
919
+ if (!this.editor) return;
920
+ const e = document.querySelector(".rte-source-editor-modal");
921
+ if (!e) return;
922
+ this.searchUI = document.createElement("div"), this.searchUI.style.cssText = `
923
+ position: absolute;
924
+ top: 10px;
925
+ right: 10px;
926
+ background: var(--editor-background, #1e1e1e);
927
+ border: 1px solid var(--editor-gutter-border, #3e3e42);
928
+ border-radius: 4px;
929
+ padding: 8px;
930
+ z-index: 1000;
931
+ display: none;
932
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
933
+ min-width: 250px;
934
+ `, this.searchUI.innerHTML = `
935
+ <div style="display: flex; align-items: center; gap: 4px; margin-bottom: 4px;">
936
+ <input type="text" placeholder="Find..." style="
937
+ flex: 1;
938
+ padding: 4px 8px;
939
+ background: var(--editor-gutter-background, #252526);
940
+ color: var(--editor-foreground, #f8f9fa);
941
+ border: 1px solid var(--editor-gutter-border, #3e3e42);
942
+ border-radius: 3px;
943
+ font-size: 12px;
944
+ outline: none;
945
+ " />
946
+ <button class="search-prev" style="
947
+ padding: 2px 6px;
948
+ background: var(--editor-gutter-background, #252526);
949
+ color: var(--editor-gutter-foreground, #858585);
950
+ border: 1px solid var(--editor-gutter-border, #3e3e42);
951
+ border-radius: 3px;
952
+ cursor: pointer;
953
+ font-size: 11px;
954
+ ">↑</button>
955
+ <button class="search-next" style="
956
+ padding: 2px 6px;
957
+ background: var(--editor-gutter-background, #252526);
958
+ color: var(--editor-gutter-foreground, #858585);
959
+ border: 1px solid var(--editor-gutter-border, #3e3e42);
960
+ border-radius: 3px;
961
+ cursor: pointer;
962
+ font-size: 11px;
963
+ ">↓</button>
964
+ <button class="search-close" style="
965
+ padding: 2px 6px;
966
+ background: var(--editor-gutter-background, #252526);
967
+ color: var(--editor-gutter-foreground, #858585);
968
+ border: 1px solid var(--editor-gutter-border, #3e3e42);
969
+ border-radius: 3px;
970
+ cursor: pointer;
971
+ font-size: 11px;
972
+ ">×</button>
973
+ </div>
974
+ <div class="search-status" style="
975
+ font-size: 11px;
976
+ color: var(--editor-gutter-foreground, #858585);
977
+ text-align: center;
978
+ "></div>
979
+ <input type="text" class="search-replace-input" placeholder="Replace with..." style="
980
+ width: 100%;
981
+ padding: 4px 8px;
982
+ background: var(--editor-gutter-background, #252526);
983
+ color: var(--editor-foreground, #f8f9fa);
984
+ border: 1px solid var(--editor-gutter-border, #3e3e42);
985
+ border-radius: 3px;
986
+ font-size: 12px;
987
+ outline: none;
988
+ display: none;
989
+ margin-top: 4px;
990
+ " />
991
+ `;
992
+ const t = this.searchUI.querySelector("input"), s = this.searchUI.querySelector(".search-replace-input"), i = this.searchUI.querySelector(".search-prev"), r = this.searchUI.querySelector(".search-next"), n = this.searchUI.querySelector(".search-close");
993
+ t.addEventListener("input", () => {
994
+ this.performSearch(t.value);
995
+ }), t.addEventListener("keydown", (o) => {
996
+ o.key === "Enter" && (o.preventDefault(), o.shiftKey ? this.findPrev() : this.findNext());
997
+ }), s.addEventListener("keydown", (o) => {
998
+ o.key === "Enter" && (o.preventDefault(), o.shiftKey ? this.replaceAll(t.value, s.value) : this.replaceCurrent(t.value, s.value));
999
+ }), i.addEventListener("click", () => this.findPrev()), r.addEventListener("click", () => this.findNext()), n.addEventListener("click", () => this.hideSearch()), e.appendChild(this.searchUI);
1000
+ }
1001
+ performSearch(e) {
1002
+ if (!this.editor || !e.trim()) {
1003
+ this.clearHighlights(), this.updateStatus("");
1004
+ return;
1005
+ }
1006
+ const t = this.editor.getValue(), s = [];
1007
+ let i = t.toLowerCase().indexOf(e.toLowerCase());
1008
+ for (; i !== -1; ) {
1009
+ const r = this.getPositionFromOffset(t, i), n = this.getPositionFromOffset(t, i + e.length);
1010
+ s.push({
1011
+ range: { start: r, end: n },
1012
+ match: t.substring(i, i + e.length)
1013
+ }), i = t.toLowerCase().indexOf(e.toLowerCase(), i + 1);
1014
+ }
1015
+ this.currentResults = s, this.currentIndex = this.currentResults.length > 0 ? 0 : -1, this.updateHighlights(), this.updateStatus(`${this.currentResults.length} matches`);
1016
+ }
1017
+ getPositionFromOffset(e, t) {
1018
+ const s = e.substring(0, t).split(`
1019
+ `), i = s.length - 1, r = s[s.length - 1].length;
1020
+ return { line: i, column: r };
1021
+ }
1022
+ findNext() {
1023
+ this.currentResults.length !== 0 && (this.currentIndex = (this.currentIndex + 1) % this.currentResults.length, this.updateHighlights());
1024
+ }
1025
+ findPrev() {
1026
+ this.currentResults.length !== 0 && (this.currentIndex = this.currentIndex <= 0 ? this.currentResults.length - 1 : this.currentIndex - 1, this.updateHighlights());
1027
+ }
1028
+ replaceCurrent(e, t) {
1029
+ if (!this.editor || !e.trim() || this.currentIndex === -1) return;
1030
+ const s = this.currentResults[this.currentIndex];
1031
+ if (!s) return;
1032
+ const i = this.editor.getValue(), r = this.getOffsetFromPosition(i, s.range.start), n = i.substring(0, r), o = i.substring(r + e.length), a = n + t + o;
1033
+ this.editor.setValue(a), this.performSearch(e), this.updateStatus("Replaced current occurrence");
1034
+ }
1035
+ replaceAll(e, t) {
1036
+ if (!this.editor || !e.trim()) return;
1037
+ let s = this.editor.getValue(), i = 0, r = s.toLowerCase().indexOf(e.toLowerCase());
1038
+ for (; r !== -1; )
1039
+ s = s.substring(0, r) + t + s.substring(r + e.length), i++, r = s.toLowerCase().indexOf(e.toLowerCase(), r + t.length);
1040
+ i > 0 && (this.editor.setValue(s), this.updateStatus(`Replaced ${i} occurrences`));
1041
+ }
1042
+ getOffsetFromPosition(e, t) {
1043
+ const s = e.split(`
1044
+ `);
1045
+ let i = 0;
1046
+ for (let r = 0; r < t.line; r++)
1047
+ i += s[r].length + 1;
1048
+ return i += t.column, i;
1049
+ }
1050
+ updateHighlights() {
1051
+ this.clearHighlights(), !(this.currentResults.length === 0 || this.currentIndex === -1) && (this.currentResults[this.currentIndex], this.updateStatus(`${this.currentResults.length} matches (showing ${this.currentIndex + 1}/${this.currentResults.length})`));
1052
+ }
1053
+ clearHighlights() {
1054
+ }
1055
+ updateStatus(e) {
1056
+ var s;
1057
+ const t = (s = this.searchUI) == null ? void 0 : s.querySelector(".search-status");
1058
+ t && (t.textContent = e);
1059
+ }
1060
+ destroy() {
1061
+ this.searchUI && this.searchUI.parentNode && this.searchUI.parentNode.removeChild(this.searchUI), this.searchUI = null, this.editor = null;
1062
+ }
1063
+ }
1064
+ class _ {
1065
+ constructor() {
1066
+ this.name = "bracket-matching", this.editor = null, this.bracketPairs = {
1067
+ "(": ")",
1068
+ "[": "]",
1069
+ "{": "}",
1070
+ "<": ">"
1071
+ }, this.reverseBracketPairs = {
1072
+ ")": "(",
1073
+ "]": "[",
1074
+ "}": "{",
1075
+ ">": "<"
1076
+ }, this.currentMatch = null;
1077
+ }
1078
+ setup(e) {
1079
+ this.editor = e, e.on("cursor", () => {
1080
+ this.updateBracketMatching();
1081
+ }), e.on("change", () => {
1082
+ this.updateBracketMatching();
1083
+ });
1084
+ }
1085
+ updateBracketMatching() {
1086
+ if (!this.editor) return;
1087
+ const e = this.editor.getCursor(), t = this.editor.getValue();
1088
+ this.clearBracketHighlighting();
1089
+ const s = this.getBracketAtPosition(t, e.position);
1090
+ if (!s) return;
1091
+ const i = this.findMatchingBracket(t, s);
1092
+ i && (this.currentMatch = i, this.highlightBrackets(i));
1093
+ }
1094
+ getBracketAtPosition(e, t) {
1095
+ const s = e.split(`
1096
+ `);
1097
+ if (t.line >= s.length) return null;
1098
+ const i = s[t.line];
1099
+ if (t.column >= i.length) return null;
1100
+ const r = i[t.column];
1101
+ return this.bracketPairs[r] || this.reverseBracketPairs[r] ? { char: r, position: t } : null;
1102
+ }
1103
+ findMatchingBracket(e, t) {
1104
+ const s = e.split(`
1105
+ `), i = t.position.line, r = t.position.column, n = t.char;
1106
+ return this.bracketPairs[n] ? this.findClosingBracket(e, s, i, r, n) : this.reverseBracketPairs[n] ? this.findOpeningBracket(e, s, i, r, n) : null;
1107
+ }
1108
+ findClosingBracket(e, t, s, i, r) {
1109
+ const n = this.bracketPairs[r];
1110
+ let o = 0;
1111
+ for (let a = s; a < t.length; a++) {
1112
+ const c = t[a], l = a === s ? i : 0;
1113
+ for (let h = l; h < c.length; h++) {
1114
+ const u = c[h];
1115
+ if (u === r)
1116
+ o++;
1117
+ else if (u === n && (o--, o === 0))
1118
+ return {
1119
+ open: { start: { line: s, column: i }, end: { line: s, column: i + 1 } },
1120
+ close: { start: { line: a, column: h }, end: { line: a, column: h + 1 } },
1121
+ type: r
1122
+ };
1123
+ }
1124
+ }
1125
+ return null;
1126
+ }
1127
+ findOpeningBracket(e, t, s, i, r) {
1128
+ const n = this.reverseBracketPairs[r];
1129
+ let o = 0;
1130
+ for (let a = s; a >= 0; a--) {
1131
+ const c = t[a], l = a === s ? i : c.length - 1;
1132
+ for (let h = l; h >= 0; h--) {
1133
+ const u = c[h];
1134
+ if (u === r)
1135
+ o++;
1136
+ else if (u === n && (o--, o === 0))
1137
+ return {
1138
+ open: { start: { line: a, column: h }, end: { line: a, column: h + 1 } },
1139
+ close: { start: { line: s, column: i }, end: { line: s, column: i + 1 } },
1140
+ type: n
1141
+ };
1142
+ }
1143
+ }
1144
+ return null;
1145
+ }
1146
+ highlightBrackets(e) {
1147
+ }
1148
+ clearBracketHighlighting() {
1149
+ this.currentMatch = null;
1150
+ }
1151
+ getCurrentMatch() {
1152
+ return this.currentMatch;
1153
+ }
1154
+ destroy() {
1155
+ this.clearBracketHighlighting(), this.editor = null;
1156
+ }
1157
+ }
1158
+ class D {
1159
+ constructor() {
1160
+ this.name = "code-folding", this.editor = null, this.foldIndicators = [], this.foldingUI = null;
1161
+ }
1162
+ setup(e) {
1163
+ this.editor = e, e.registerCommand("fold", () => {
1164
+ this.foldAtCursor();
1165
+ }), e.registerCommand("unfold", () => {
1166
+ this.unfoldAtCursor();
1167
+ }), e.registerCommand("foldAll", () => {
1168
+ this.foldAll();
1169
+ }), e.registerCommand("unfoldAll", () => {
1170
+ this.unfoldAll();
1171
+ }), e.on("change", () => {
1172
+ this.updateFoldIndicators();
1173
+ }), this.createFoldingUI(), this.updateFoldIndicators();
1174
+ }
1175
+ createFoldingUI() {
1176
+ if (!this.editor) return;
1177
+ const e = document.querySelector(".rte-source-editor-modal");
1178
+ e && (this.foldingUI = document.createElement("div"), this.foldingUI.style.cssText = `
1179
+ position: absolute;
1180
+ left: 40px;
1181
+ top: 0;
1182
+ bottom: 0;
1183
+ width: 20px;
1184
+ pointer-events: none;
1185
+ z-index: 2;
1186
+ `, e.appendChild(this.foldingUI));
1187
+ }
1188
+ updateFoldIndicators() {
1189
+ if (!this.editor || !this.foldingUI) return;
1190
+ this.foldingUI.innerHTML = "", this.foldIndicators = [];
1191
+ const e = this.editor.getValue().split(`
1192
+ `);
1193
+ this.findFoldableLines(e).forEach((t) => {
1194
+ this.createFoldIndicator(t);
1195
+ });
1196
+ }
1197
+ findFoldableLines(e) {
1198
+ const t = [];
1199
+ for (let s = 0; s < e.length; s++) {
1200
+ const i = e[s].trim();
1201
+ (i.startsWith("{") || i.startsWith("function") || i.startsWith("class") || i.startsWith("if") || i.includes("=>") || i.startsWith("for") || i.startsWith("while") || i.startsWith("try")) && t.push(s);
1202
+ }
1203
+ return t;
1204
+ }
1205
+ createFoldIndicator(e) {
1206
+ if (!this.foldingUI) return;
1207
+ const t = document.createElement("div");
1208
+ t.style.cssText = `
1209
+ position: absolute;
1210
+ left: 0;
1211
+ top: ${e * 21}px;
1212
+ width: 20px;
1213
+ height: 21px;
1214
+ display: flex;
1215
+ align-items: center;
1216
+ justify-content: center;
1217
+ cursor: pointer;
1218
+ pointer-events: auto;
1219
+ color: var(--editor-gutter-foreground, #858585);
1220
+ font-size: 10px;
1221
+ user-select: none;
1222
+ `, t.innerHTML = "▶", t.title = "Code folding not yet implemented - click shows fold indicators", t.addEventListener("click", () => {
1223
+ }), this.foldingUI.appendChild(t), this.foldIndicators.push(t);
1224
+ }
1225
+ foldAtCursor() {
1226
+ }
1227
+ unfoldAtCursor() {
1228
+ }
1229
+ foldAll() {
1230
+ }
1231
+ unfoldAll() {
1232
+ }
1233
+ destroy() {
1234
+ this.foldingUI && this.foldingUI.parentNode && this.foldingUI.parentNode.removeChild(this.foldingUI), this.foldingUI = null, this.foldIndicators = [], this.editor = null;
1235
+ }
1236
+ }
1237
+ class W {
1238
+ constructor() {
1239
+ this.name = "syntax-highlighting", this.editor = null, this.currentTheme = "dark", this.currentLanguage = null, this.modes = /* @__PURE__ */ new Map();
1240
+ }
1241
+ setup(e) {
1242
+ this.editor = e, this.registerMode("html", { name: "html", highlight: (t, s) => this._highlightHTML(t, s) }), this.registerMode("javascript", { name: "javascript", highlight: (t, s) => this._highlightJS(t, s) }), this.registerMode("typescript", { name: "typescript", highlight: (t, s) => this._highlightJS(t, s) }), this.registerMode("php", { name: "php", highlight: (t, s) => this._highlightPHP(t, s) });
1243
+ }
1244
+ // Extension provides methods that can be called by the editor
1245
+ setTheme(e) {
1246
+ this.currentTheme = e;
1247
+ }
1248
+ setLanguage(e) {
1249
+ this.currentLanguage = e;
1250
+ }
1251
+ registerMode(e, t) {
1252
+ this.modes.set(e.toLowerCase(), t);
1253
+ }
1254
+ // Method to get syntax highlighting colors for a given theme
1255
+ getSyntaxColors() {
1256
+ return this.currentTheme === "dark" ? {
1257
+ tag: "#569cd6",
1258
+ // Blue
1259
+ comment: "#6a9955",
1260
+ // Green
1261
+ attrName: "#9cdcfe",
1262
+ // Light blue for attribute names
1263
+ attrValue: "#ce9178",
1264
+ // Orange for attribute values
1265
+ styleProp: "#c586c0",
1266
+ // Purple for CSS property names
1267
+ styleVal: "#dcdcaa",
1268
+ // Yellow-ish for CSS values
1269
+ doctype: "#808080",
1270
+ // Gray for doctype
1271
+ text: "#d4d4d4",
1272
+ // Light gray for normal text
1273
+ keyword: "#c586c0",
1274
+ // JS/PHP keywords (purple)
1275
+ string: "#ce9178",
1276
+ // JS strings
1277
+ number: "#b5cea8",
1278
+ // numbers
1279
+ variable: "#9cdcfe"
1280
+ // php variable color
1281
+ } : {
1282
+ tag: "#0000ff",
1283
+ // Blue
1284
+ comment: "#008000",
1285
+ // Green
1286
+ attrName: "#001080",
1287
+ attrValue: "#a31515",
1288
+ // Red
1289
+ styleProp: "#6a00a8",
1290
+ styleVal: "#804000",
1291
+ doctype: "#444444",
1292
+ text: "#000000",
1293
+ // Black
1294
+ keyword: "#000080",
1295
+ string: "#a31515",
1296
+ number: "#0086b3",
1297
+ variable: "#001080"
1298
+ };
1299
+ }
1300
+ // Public API: highlight a source string using the chosen mode (or detect html)
1301
+ highlight(e, t) {
1302
+ const s = this.getSyntaxColors(), i = (t || this.currentLanguage || "html").toLowerCase();
1303
+ return (this.modes.get(i) || this.modes.get("html")).highlight(e, s);
1304
+ }
1305
+ // Backwards-compatible method
1306
+ highlightHTML(e) {
1307
+ return this.highlight(e, "html");
1308
+ }
1309
+ // --- Internal mode implementations ---
1310
+ escapeHTML(e) {
1311
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#39;");
1312
+ }
1313
+ // Robustly unescape common HTML entities, repeating a few times to handle nested encoding like &amp;amp;...
1314
+ unescapeEntitiesRepeated(e) {
1315
+ let t = e || "";
1316
+ for (let s = 0; s < 5; s++) {
1317
+ const i = t;
1318
+ if (t = t.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'"), t === i) break;
1319
+ }
1320
+ return t;
1321
+ }
1322
+ _highlightHTML(e, t) {
1323
+ const s = t, i = (c) => this.escapeHTML(c);
1324
+ let r = i(e);
1325
+ const n = (c) => {
1326
+ let l = c.replace(/&quot;/g, '"').replace(/&#39;/g, "'");
1327
+ return l = l.replace(/(\/\*[\s\S]*?\*\/)/g, `<span style="color: ${s.comment};">$1</span>`), l = l.replace(/([a-zA-Z-]+)(\s*:\s*)([^;{]+)(;?)/g, (h, u, g, d, f) => {
1328
+ const p = String(d).trim(), x = i(p);
1329
+ return `<span style="color: ${s.styleProp};">${u}</span>${g}<span style="color: ${s.styleVal};">${x}</span>${f}`;
1330
+ }), l;
1331
+ }, o = [];
1332
+ try {
1333
+ e.replace(/<script\b([^>]*)>([\s\S]*?)<\/script>/gi, (c, l, h) => (o.push({ attrs: String(l || ""), inner: String(h || "") }), c));
1334
+ } catch (c) {
1335
+ }
1336
+ let a = 0;
1337
+ return r = r.replace(/(&lt;script\b([^&>]*)&gt;)([\s\S]*?)(&lt;\/script&gt;)/gi, (c, l, h, u, g) => {
1338
+ var p, x, y;
1339
+ const d = (x = (p = o[a++]) == null ? void 0 : p.inner) != null ? x : this.unescapeEntitiesRepeated(u || "");
1340
+ (((y = o[a - 1]) == null ? void 0 : y.attrs) || h || "").toLowerCase();
1341
+ const f = this._highlightJS(d, s);
1342
+ return `${l}${f}${g}`;
1343
+ }), r = r.replace(/(&lt;style\b[^&]*&gt;)([\s\S]*?)(&lt;\/style&gt;)/gi, (c, l, h, u) => {
1344
+ const g = n(h);
1345
+ return `${l}${g}${u}`;
1346
+ }), r = r.replace(/(&lt;!--[\s\S]*?--&gt;)/g, `<span style="color: ${s.comment};">$1</span>`), r = r.replace(/(&lt;!DOCTYPE[\s\S]*?&gt;)/i, `<span style="color: ${s.doctype};">$1</span>`), r = r.replace(/(&lt;\/?\s*)([^\s&>\/]+)([\s\S]*?)(\/?&gt;)/g, (c, l, h, u, g) => {
1347
+ const d = `<span style="color: ${s.tag};">${h}</span>`;
1348
+ let f = u;
1349
+ return f = f.replace(/([\w:-]+)(\s*=\s*)((&quot;[\s\S]*?&quot;|&#39;[\s\S]*?&#39;|[^\s&>]+))/g, (p, x, y, v) => {
1350
+ const C = String(x).toLowerCase(), L = `<span style="color: ${s.attrName};">${x}</span>`;
1351
+ let T = v, k = "";
1352
+ v.startsWith("&quot;") && v.endsWith("&quot;") ? (T = v.slice(6, -6), k = "&quot;") : v.startsWith("&#39;") && v.endsWith("&#39;") && (T = v.slice(5, -5), k = "&#39;");
1353
+ let w = v;
1354
+ if (C === "style") {
1355
+ const S = T.replace(/([\w-]+)\s*:\s*([^;]+)(;?)/g, ($, E, O, H) => `<span style="color: ${s.styleProp};">${E}</span>:<span style="color: ${s.styleVal};">${O.trim()}</span>${H}`);
1356
+ k ? w = `${k}${S}${k}` : w = S, w = `<span style="color: ${s.attrValue};">${w}</span>`;
1357
+ } else
1358
+ k && (w = `${k}${T}${k}`), w = `<span style="color: ${s.attrValue};">${w}</span>`;
1359
+ return `${L}${y}${w}`;
1360
+ }), `${l}${d}${f}${g}`;
1361
+ }), r;
1362
+ }
1363
+ _highlightJS(e, t) {
1364
+ const s = this.unescapeEntitiesRepeated(e);
1365
+ this.escapeHTML(s);
1366
+ const i = [], r = (u) => {
1367
+ let g = "", d = u;
1368
+ do
1369
+ g = String.fromCharCode(97 + d % 26) + g, d = Math.floor(d / 26) - 1;
1370
+ while (d >= 0);
1371
+ return g || "a";
1372
+ }, n = (u) => `\0${r(u)}\0`, o = (u) => {
1373
+ const g = i.length;
1374
+ return i.push(u), n(g);
1375
+ };
1376
+ let a;
1377
+ const c = /(\/\*[\s\S]*?\*\/)|(\/\/[^\n\r]*)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`)/g;
1378
+ let l = 0, h = "";
1379
+ for (; a = c.exec(s); ) {
1380
+ const u = a.index;
1381
+ l < u && (h += this.escapeHTML(s.slice(l, u)));
1382
+ const g = a[0];
1383
+ /^\/\*/.test(g) || /^\/\//.test(g) ? h += o(`<span style="color: ${t.comment};">${this.escapeHTML(g)}</span>`) : h += o(`<span style="color: ${t.string};">${this.escapeHTML(g)}</span>`), l = c.lastIndex;
1384
+ }
1385
+ return l < s.length && (h += this.escapeHTML(s.slice(l))), h = h.replace(/\b(0x[0-9a-fA-F]+|\d+\.?\d*|\d*\.\d+)\b/g, (u, g, d) => {
1386
+ const f = h[d - 1] || "", p = h[d + u.length] || "";
1387
+ return f === "&" || f === "#" || p === ";" || p === "#" ? u : `<span style="color: ${t.number};">${u}</span>`;
1388
+ }), h = h.replace(/\b(const|let|var|function|class|if|else|return|for|while|switch|case|break|import|from|export|extends|new|try|catch|finally|throw|await|async|interface|type)\b/g, `<span style="color: ${t.keyword};">$1</span>`), h.replace(/\u0000([a-z]+)\u0000/g, (u, g) => {
1389
+ let d = 0;
1390
+ for (let f = 0; f < g.length; f++)
1391
+ d = d * 26 + (g.charCodeAt(f) - 97 + 1);
1392
+ return d = d - 1, i[d] || "";
1393
+ });
1394
+ }
1395
+ _highlightPHP(e, t) {
1396
+ const s = this.unescapeEntitiesRepeated(e);
1397
+ let i = this.escapeHTML(s);
1398
+ const r = [], n = (d) => {
1399
+ let f = "", p = d;
1400
+ do
1401
+ f = String.fromCharCode(97 + p % 26) + f, p = Math.floor(p / 26) - 1;
1402
+ while (p >= 0);
1403
+ return f || "a";
1404
+ }, o = (d) => {
1405
+ const f = r.length;
1406
+ return r.push(d), `\0${n(f)}\0`;
1407
+ }, a = (d, f) => {
1408
+ const p = i.indexOf(d);
1409
+ return p === -1 ? !1 : (i = i.slice(0, p) + f + i.slice(p + d.length), !0);
1410
+ };
1411
+ let c;
1412
+ const l = /\/\*[\s\S]*?\*\//g, h = /\/\/[^\n\r]*/g, u = /\#([^\n\r]*)/g, g = /("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/g;
1413
+ for (; c = l.exec(s); ) {
1414
+ const d = c[0];
1415
+ a(this.escapeHTML(d), o(`<span style="color: ${t.comment};">${this.escapeHTML(d)}</span>`));
1416
+ }
1417
+ for (; c = h.exec(s); ) {
1418
+ const d = c[0];
1419
+ a(this.escapeHTML(d), o(`<span style="color: ${t.comment};">${this.escapeHTML(d)}</span>`));
1420
+ }
1421
+ for (; c = u.exec(s); ) {
1422
+ const d = c[0];
1423
+ a(this.escapeHTML(d), o(`<span style="color: ${t.comment};">${this.escapeHTML(d)}</span>`));
1424
+ }
1425
+ for (; c = g.exec(s); ) {
1426
+ const d = c[0];
1427
+ a(this.escapeHTML(d), o(`<span style="color: ${t.string};">${this.escapeHTML(d)}</span>`));
1428
+ }
1429
+ return i = i.replace(/(\$[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)/g, `<span style="color: ${t.variable};">$1</span>`), i = i.replace(/\b(echo|print|function|class|if|else|elseif|foreach|as|return|namespace|use|new|extends|public|protected|private|static)\b/g, `<span style="color: ${t.keyword};">$1</span>`), i = i.replace(/\u0000([a-z]+)\u0000/g, (d, f) => {
1430
+ let p = 0;
1431
+ for (let x = 0; x < f.length; x++)
1432
+ p = p * 26 + (f.charCodeAt(x) - 97 + 1);
1433
+ return p = p - 1, r[p] || "";
1434
+ }), i;
1435
+ }
1436
+ // Method to check if content contains syntax that should be highlighted
1437
+ shouldHighlight(e) {
1438
+ return /<\/?[\w:-]+|<!--/.test(e);
1439
+ }
1440
+ destroy() {
1441
+ this.editor = null, this.modes.clear();
1442
+ }
1443
+ }
1444
+ function j(b, e) {
1445
+ const t = { ...e };
1446
+ return t.extensions || (t.extensions = []), t.extensions.some((s) => s.name === "keymap") || t.extensions.unshift(new V(t.keymap)), t.extensions.some((s) => s.name === "transaction") || t.extensions.unshift(new A()), new K(b, t);
1447
+ }
1448
+ const Z = `/* Source Editor Dialog Styles */
1449
+ .rte-source-editor-overlay {
1450
+ position: fixed !important;
1451
+ top: 0 !important;
1452
+ left: 0 !important;
1453
+ right: 0 !important;
1454
+ bottom: 0 !important;
1455
+ width: 100vw !important;
1456
+ height: 100vh !important;
1457
+ background-color: rgba(0, 0, 0, 0.6) !important;
1458
+ display: flex !important;
1459
+ align-items: center !important;
1460
+ justify-content: center !important;
1461
+ z-index: 10000 !important;
1462
+ padding: 20px !important;
1463
+ box-sizing: border-box !important;
1464
+ margin: 0 !important;
1465
+ }
1466
+
1467
+ .rte-source-editor-overlay.fullscreen {
1468
+ padding: 0 !important;
1469
+ }
1470
+
1471
+ .rte-source-editor-modal {
1472
+ background: white;
1473
+ border-radius: 8px;
1474
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
1475
+ width: 100%;
1476
+ max-width: 1200px;
1477
+ max-height: 90vh;
1478
+ display: flex;
1479
+ flex-direction: column;
1480
+ overflow: hidden;
1481
+ position: relative;
1482
+ }
1483
+
1484
+ .rte-source-editor-overlay.fullscreen .rte-source-editor-modal {
1485
+ border-radius: 0;
1486
+ max-width: 100%;
1487
+ max-height: 100vh;
1488
+ width: 100%;
1489
+ height: 100vh;
1490
+ }
1491
+
1492
+ .rte-source-editor-header {
1493
+ display: flex;
1494
+ align-items: center;
1495
+ justify-content: space-between;
1496
+ padding: 16px 20px;
1497
+ border-bottom: 1px solid #e1e5e9;
1498
+ background: #f8f9fa;
1499
+ border-radius: 8px 8px 0 0;
1500
+ }
1501
+
1502
+ .rte-source-editor-overlay.fullscreen .rte-source-editor-header {
1503
+ border-radius: 0;
1504
+ }
1505
+
1506
+ .rte-source-editor-header h2 {
1507
+ margin: 0;
1508
+ font-size: 18px;
1509
+ font-weight: 600;
1510
+ color: #1a1a1a;
1511
+ }
1512
+
1513
+ .rte-source-editor-header-toolbar {
1514
+ display: flex;
1515
+ gap: 8px;
1516
+ margin-left: auto;
1517
+ margin-right: 16px;
1518
+ }
1519
+
1520
+ .rte-source-editor-toolbar-btn {
1521
+ background: none;
1522
+ border: none;
1523
+ cursor: pointer;
1524
+ padding: 6px;
1525
+ border-radius: 4px;
1526
+ font-size: 16px;
1527
+ line-height: 1;
1528
+ transition: all 0.2s ease;
1529
+ color: #666;
1530
+ }
1531
+
1532
+ .rte-source-editor-toolbar-btn:hover:not(:disabled) {
1533
+ background: #e1e5e9;
1534
+ color: #1a1a1a;
1535
+ }
1536
+
1537
+ .rte-source-editor-toolbar-btn:disabled {
1538
+ opacity: 0.5;
1539
+ cursor: not-allowed;
1540
+ }
1541
+
1542
+ .rte-source-editor-toolbar-btn.active {
1543
+ background: #007acc;
1544
+ color: white;
1545
+ }
1546
+
1547
+ .rte-source-editor-toolbar-btn.active:hover {
1548
+ background: #0056b3;
1549
+ }
1550
+
1551
+ .rte-source-editor-header-actions {
1552
+ display: flex;
1553
+ gap: 8px;
1554
+ }
1555
+
1556
+ .rte-source-editor-fullscreen-btn,
1557
+ .rte-source-editor-close-btn {
1558
+ background: none;
1559
+ border: none;
1560
+ cursor: pointer;
1561
+ padding: 4px;
1562
+ border-radius: 4px;
1563
+ color: #666;
1564
+ font-size: 16px;
1565
+ line-height: 1;
1566
+ transition: all 0.2s ease;
1567
+ }
1568
+
1569
+ .rte-source-editor-fullscreen-btn:hover,
1570
+ .rte-source-editor-close-btn:hover {
1571
+ background: #e1e5e9;
1572
+ color: #1a1a1a;
1573
+ }
1574
+
1575
+ .rte-source-editor-body {
1576
+ flex: 1;
1577
+ overflow: hidden;
1578
+ display: flex;
1579
+ flex-direction: column;
1580
+ }
1581
+
1582
+ .rte-source-editor-loading {
1583
+ display: flex;
1584
+ flex-direction: column;
1585
+ align-items: center;
1586
+ justify-content: center;
1587
+ padding: 40px;
1588
+ color: #666;
1589
+ position: absolute;
1590
+ z-index: 9;
1591
+ margin: 0 auto;
1592
+ width: 100%;
1593
+ top: 44%;
1594
+ }
1595
+
1596
+ .rte-source-editor-spinner {
1597
+ width: 32px;
1598
+ height: 32px;
1599
+ border: 3px solid #e1e5e9;
1600
+ border-top: 3px solid #007acc;
1601
+ border-radius: 50%;
1602
+ animation: spin 1s linear infinite;
1603
+ margin-bottom: 16px;
1604
+ }
1605
+
1606
+ @keyframes spin {
1607
+ 0% { transform: rotate(0deg); }
1608
+ 100% { transform: rotate(360deg); }
1609
+ }
1610
+
1611
+ .rte-source-editor-error {
1612
+ background: #fee;
1613
+ color: #c53030;
1614
+ padding: 12px 16px;
1615
+ border-left: 4px solid #c53030;
1616
+ margin: 16px;
1617
+ border-radius: 4px;
1618
+ font-size: 14px;
1619
+ }
1620
+
1621
+ .rte-source-editor-content {
1622
+ flex: 1;
1623
+ display: flex;
1624
+ flex-direction: column;
1625
+ overflow: hidden;
1626
+ }
1627
+
1628
+ .rte-source-editor-warning {
1629
+ background: #fefcbf;
1630
+ color: #744210;
1631
+ padding: 8px 16px;
1632
+ font-size: 12px;
1633
+ font-weight: 500;
1634
+ border-bottom: 1px solid #f6e05e;
1635
+ }
1636
+
1637
+ .rte-source-editor-codemirror {
1638
+ flex: 1;
1639
+ overflow: auto;
1640
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
1641
+ font-size: 14px;
1642
+ line-height: 1.5;
1643
+ }
1644
+
1645
+ .rte-source-editor-codemirror .cm-editor {
1646
+ height: 100%;
1647
+ }
1648
+
1649
+ .rte-source-editor-codemirror .cm-focused {
1650
+ outline: none;
1651
+ }
1652
+
1653
+ .rte-source-editor-footer {
1654
+ display: flex;
1655
+ align-items: center;
1656
+ justify-content: space-between;
1657
+ padding: 16px 20px;
1658
+ border-top: 1px solid #e1e5e9;
1659
+ background: #f8f9fa;
1660
+ border-radius: 0 0 8px 8px;
1661
+ }
1662
+
1663
+ .rte-source-editor-overlay.fullscreen .rte-source-editor-footer {
1664
+ border-radius: 0;
1665
+ }
1666
+
1667
+ .rte-source-editor-footer-info {
1668
+ font-size: 12px;
1669
+ color: #666;
1670
+ }
1671
+
1672
+ .unsaved-changes {
1673
+ color: #d69e2e;
1674
+ font-weight: 500;
1675
+ }
1676
+
1677
+ .rte-source-editor-footer-actions {
1678
+ display: flex;
1679
+ gap: 12px;
1680
+ }
1681
+
1682
+ .rte-source-editor-btn {
1683
+ padding: 8px 16px;
1684
+ border-radius: 4px;
1685
+ font-size: 14px;
1686
+ font-weight: 500;
1687
+ cursor: pointer;
1688
+ border: 1px solid transparent;
1689
+ transition: all 0.2s ease;
1690
+ }
1691
+
1692
+ .rte-source-editor-btn:disabled {
1693
+ opacity: 0.6;
1694
+ cursor: not-allowed;
1695
+ }
1696
+
1697
+ .rte-source-editor-btn-cancel {
1698
+ background: white;
1699
+ border-color: #d1d5db;
1700
+ color: #374151;
1701
+ }
1702
+
1703
+ .rte-source-editor-btn-cancel:hover:not(:disabled) {
1704
+ background: #f9fafb;
1705
+ border-color: #9ca3af;
1706
+ }
1707
+
1708
+ .rte-source-editor-btn-save {
1709
+ background: #007acc;
1710
+ color: white;
1711
+ }
1712
+
1713
+ .rte-source-editor-btn-save:hover:not(:disabled) {
1714
+ background: #0056b3;
1715
+ }
1716
+
1717
+ /* Dark theme support */
1718
+ @media (prefers-color-scheme: dark) {
1719
+ .rte-source-editor-modal {
1720
+ background: #1e1e1e;
1721
+ color: #f8f9fa;
1722
+ }
1723
+
1724
+ .rte-source-editor-header {
1725
+ background: #2d2d2d;
1726
+ border-color: #404040;
1727
+ }
1728
+
1729
+ .rte-source-editor-header h2 {
1730
+ color: #f8f9fa;
1731
+ }
1732
+
1733
+ .rte-source-editor-fullscreen-btn,
1734
+ .rte-source-editor-close-btn {
1735
+ color: #ccc;
1736
+ }
1737
+
1738
+ .rte-source-editor-fullscreen-btn:hover,
1739
+ .rte-source-editor-close-btn:hover {
1740
+ background: #404040;
1741
+ color: #f8f9fa;
1742
+ }
1743
+
1744
+ .rte-source-editor-error {
1745
+ background: #2d1b1b;
1746
+ color: #fca5a5;
1747
+ border-color: #dc2626;
1748
+ }
1749
+
1750
+ .rte-source-editor-warning {
1751
+ background: #2d2a1b;
1752
+ color: #fcd34d;
1753
+ border-color: #d97706;
1754
+ }
1755
+
1756
+ .rte-source-editor-footer {
1757
+ background: #2d2d2d;
1758
+ border-color: #404040;
1759
+ }
1760
+
1761
+ .rte-source-editor-footer-info {
1762
+ color: #ccc;
1763
+ }
1764
+
1765
+ .rte-source-editor-btn-cancel {
1766
+ background: #374151;
1767
+ border-color: #4b5563;
1768
+ color: #f9fafb;
1769
+ }
1770
+
1771
+ .rte-source-editor-btn-cancel:hover:not(:disabled) {
1772
+ background: #4b5563;
1773
+ border-color: #6b7280;
1774
+ }
1775
+ }
1776
+
1777
+ /* Responsive design */
1778
+ @media (max-width: 768px) {
1779
+ .rte-source-editor-overlay {
1780
+ padding: 10px;
1781
+ }
1782
+
1783
+ .rte-source-editor-modal {
1784
+ max-height: 95vh;
1785
+ }
1786
+
1787
+ .rte-source-editor-header {
1788
+ padding: 12px 16px;
1789
+ }
1790
+
1791
+ .rte-source-editor-footer {
1792
+ padding: 12px 16px;
1793
+ flex-direction: column;
1794
+ gap: 12px;
1795
+ align-items: stretch;
1796
+ }
1797
+
1798
+ .rte-source-editor-footer-actions {
1799
+ justify-content: stretch;
1800
+ }
1801
+
1802
+ .rte-source-editor-btn {
1803
+ flex: 1;
1804
+ text-align: center;
1805
+ }
1806
+ }`, Y = () => ({
1807
+ name: "code",
1808
+ // Toolbar button configuration
1809
+ toolbar: [
1810
+ {
1811
+ label: "Source",
1812
+ command: "toggleSourceView",
1813
+ type: "button",
1814
+ icon: "<>",
1815
+ shortcut: "Mod-Shift-S"
1816
+ }
1817
+ ],
1818
+ // Native command implementations
1819
+ commands: {
1820
+ /**
1821
+ * Toggle HTML source view
1822
+ * Opens a dialog to edit raw HTML
1823
+ */
1824
+ toggleSourceView: () => {
1825
+ const e = (() => {
1826
+ var o, a, c;
1827
+ const r = window.getSelection();
1828
+ if (r && r.anchorNode) {
1829
+ let l = r.anchorNode instanceof HTMLElement ? r.anchorNode : r.anchorNode.parentElement;
1830
+ for (; l; ) {
1831
+ if ((o = l.classList) != null && o.contains("rte-content"))
1832
+ return l;
1833
+ l = l.parentElement;
1834
+ }
1835
+ }
1836
+ if (document.activeElement) {
1837
+ let l = document.activeElement;
1838
+ if ((a = l.classList) != null && a.contains("rte-content"))
1839
+ return l;
1840
+ for (; l && l !== document.body; ) {
1841
+ if ((c = l.classList) != null && c.contains("rte-content"))
1842
+ return l;
1843
+ const h = l.querySelector(".rte-content");
1844
+ if (h) return h;
1845
+ l = l.parentElement;
1846
+ }
1847
+ }
1848
+ const n = document.querySelector("[data-editora-editor]");
1849
+ if (n) {
1850
+ const l = n.querySelector(".rte-content");
1851
+ if (l) return l;
1852
+ }
1853
+ return document.querySelector(".rte-content");
1854
+ })();
1855
+ if (!e)
1856
+ return console.error("[CodePlugin] Editor content area not found"), alert("Editor content area not found. Please click inside the editor first."), !1;
1857
+ const t = e.innerHTML, s = (r) => {
1858
+ let n = "", o = 0;
1859
+ const a = 2, c = r.split(/(<\/?[a-zA-Z][^>]*>)/);
1860
+ for (const l of c)
1861
+ l.trim() && (l.match(/^<\/[a-zA-Z]/) ? (o = Math.max(0, o - 1), n += `
1862
+ ` + " ".repeat(o * a) + l) : l.match(/^<[a-zA-Z]/) && !l.match(/\/>$/) ? (n += `
1863
+ ` + " ".repeat(o * a) + l, o++) : l.match(/^<[a-zA-Z].*\/>$/) ? n += `
1864
+ ` + " ".repeat(o * a) + l : n += l.trim());
1865
+ return n.trim();
1866
+ };
1867
+ return (() => {
1868
+ var $, E, O, H, R, N;
1869
+ let r = null, n = "dark", o = !1, a = !1, c = !1;
1870
+ const l = t, h = document.createElement("div");
1871
+ h.className = "rte-source-editor-overlay";
1872
+ const u = document.createElement("div");
1873
+ u.className = "rte-source-editor-modal", u.setAttribute("role", "dialog"), u.setAttribute("aria-modal", "true"), u.setAttribute("aria-labelledby", "source-editor-title");
1874
+ const g = document.createElement("div");
1875
+ g.className = "rte-source-editor-header", g.innerHTML = `
1876
+ <h2 id="source-editor-title">Source Editor</h2>
1877
+ <div class="rte-source-editor-header-toolbar">
1878
+ <button class="rte-source-editor-toolbar-btn theme-toggle-btn" title="Switch theme">
1879
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1880
+ <circle cx="12" cy="12" r="5"/>
1881
+ <line x1="12" y1="1" x2="12" y2="3"/>
1882
+ <line x1="12" y1="21" x2="12" y2="23"/>
1883
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
1884
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
1885
+ <line x1="1" y1="12" x2="3" y2="12"/>
1886
+ <line x1="21" y1="12" x2="23" y2="12"/>
1887
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
1888
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
1889
+ </svg>
1890
+ </button>
1891
+ <button class="rte-source-editor-toolbar-btn readonly-toggle-btn" title="Toggle read-only">
1892
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1893
+ <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
1894
+ <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
1895
+ </svg>
1896
+ </button>
1897
+ </div>
1898
+ <div class="rte-source-editor-header-actions">
1899
+ <button class="rte-source-editor-fullscreen-btn" title="Toggle fullscreen">
1900
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1901
+ <path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/>
1902
+ </svg>
1903
+ </button>
1904
+ <button class="rte-source-editor-close-btn" aria-label="Close source editor">
1905
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1906
+ <line x1="18" y1="6" x2="6" y2="18"/>
1907
+ <line x1="6" y1="6" x2="18" y2="18"/>
1908
+ </svg>
1909
+ </button>
1910
+ </div>
1911
+ `;
1912
+ const d = document.createElement("div");
1913
+ d.className = "rte-source-editor-body";
1914
+ const f = document.createElement("div");
1915
+ f.className = "rte-source-editor-content";
1916
+ const p = document.createElement("div");
1917
+ p.className = "rte-source-editor-warning", p.textContent = "⚠️ Advanced users only. Invalid HTML may break the editor.";
1918
+ const x = document.createElement("div");
1919
+ x.className = "rte-source-editor-light-editor", x.style.height = "400px", f.appendChild(p), f.appendChild(x), d.appendChild(f);
1920
+ const y = document.createElement("div");
1921
+ if (y.className = "rte-source-editor-footer", y.innerHTML = `
1922
+ <div class="rte-source-editor-footer-info">
1923
+ <span class="unsaved-changes" style="display: none;">• Unsaved changes</span>
1924
+ </div>
1925
+ <div class="rte-source-editor-footer-actions">
1926
+ <button class="rte-source-editor-btn rte-source-editor-btn-cancel">Cancel</button>
1927
+ <button class="rte-source-editor-btn rte-source-editor-btn-save">Save</button>
1928
+ </div>
1929
+ `, u.appendChild(g), u.appendChild(d), u.appendChild(y), h.appendChild(u), !document.getElementById("rte-source-editor-styles")) {
1930
+ const m = document.createElement("style");
1931
+ m.id = "rte-source-editor-styles", m.textContent = Z, document.head.appendChild(m);
1932
+ }
1933
+ document.body.appendChild(h);
1934
+ try {
1935
+ r = j(x, {
1936
+ value: s(t),
1937
+ theme: "dark",
1938
+ readOnly: !1,
1939
+ extensions: [
1940
+ new U(),
1941
+ new z(),
1942
+ new q(),
1943
+ new _(),
1944
+ new F(),
1945
+ new D(),
1946
+ new W()
1947
+ ]
1948
+ }), r.on("change", () => {
1949
+ c = ((r == null ? void 0 : r.getValue()) || "") !== s(l);
1950
+ const M = y.querySelector(".unsaved-changes");
1951
+ M && (M.style.display = c ? "inline" : "none");
1952
+ }), setTimeout(() => r == null ? void 0 : r.focus(), 100);
1953
+ } catch (m) {
1954
+ console.error("Failed to initialize code editor:", m);
1955
+ }
1956
+ const v = () => {
1957
+ n = n === "dark" ? "light" : "dark", r == null || r.setTheme(n);
1958
+ const m = g.querySelector(".theme-toggle-btn");
1959
+ m && n === "light" && (m.innerHTML = `
1960
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1961
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
1962
+ </svg>
1963
+ `);
1964
+ }, C = () => {
1965
+ o = !o, r == null || r.setReadOnly(o);
1966
+ const m = g.querySelector(".readonly-toggle-btn");
1967
+ m && (o ? (m.classList.add("active"), m.innerHTML = `
1968
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1969
+ <rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
1970
+ <circle cx="12" cy="16" r="1"/>
1971
+ <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
1972
+ </svg>
1973
+ `) : (m.classList.remove("active"), m.innerHTML = `
1974
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1975
+ <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
1976
+ <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
1977
+ </svg>
1978
+ `));
1979
+ }, L = () => {
1980
+ a = !a, a ? (h.classList.add("fullscreen"), x.style.height = "calc(100vh - 200px)") : (h.classList.remove("fullscreen"), x.style.height = "400px");
1981
+ const m = g.querySelector(".rte-source-editor-fullscreen-btn");
1982
+ m && (m.innerHTML = a ? `
1983
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1984
+ <path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 0 2-2h3M3 16h3a2 2 0 0 0 2 2v3"/>
1985
+ </svg>
1986
+ ` : `
1987
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1988
+ <path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/>
1989
+ </svg>
1990
+ `);
1991
+ }, T = () => {
1992
+ r && (r.destroy(), r = null), document.body.removeChild(h);
1993
+ }, k = () => {
1994
+ c && !confirm("You have unsaved changes. Are you sure you want to cancel?") || T();
1995
+ }, w = () => {
1996
+ try {
1997
+ const m = (r == null ? void 0 : r.getValue()) || "", M = document.createElement("div");
1998
+ M.innerHTML = m, M.querySelectorAll('script, iframe[src^="javascript:"], object, embed').forEach((I) => I.remove()), e.innerHTML = M.innerHTML, c = !1, T();
1999
+ } catch (m) {
2000
+ alert("Failed to update HTML. Please check your syntax."), console.error("HTML update error:", m);
2001
+ }
2002
+ };
2003
+ ($ = g.querySelector(".theme-toggle-btn")) == null || $.addEventListener("click", v), (E = g.querySelector(".readonly-toggle-btn")) == null || E.addEventListener("click", C), (O = g.querySelector(".rte-source-editor-fullscreen-btn")) == null || O.addEventListener("click", L), (H = g.querySelector(".rte-source-editor-close-btn")) == null || H.addEventListener("click", T), (R = y.querySelector(".rte-source-editor-btn-cancel")) == null || R.addEventListener("click", k), (N = y.querySelector(".rte-source-editor-btn-save")) == null || N.addEventListener("click", w), h.addEventListener("click", (m) => {
2004
+ m.target === h && T();
2005
+ });
2006
+ const S = (m) => {
2007
+ m.key === "Escape" && (T(), document.removeEventListener("keydown", S));
2008
+ };
2009
+ document.addEventListener("keydown", S);
2010
+ })(), !0;
2011
+ }
2012
+ },
2013
+ // Keyboard shortcuts
2014
+ keymap: {
2015
+ "Mod-Shift-s": "toggleSourceView",
2016
+ "Mod-Shift-S": "toggleSourceView"
2017
+ }
2018
+ });
2019
+ export {
2020
+ Y as CodePlugin
2021
+ };
2022
+ //# sourceMappingURL=CodePlugin.native-CK9d8rmt.mjs.map