@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.
@@ -1,1679 +0,0 @@
1
- class k {
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 n = e.start.line + 1; n < e.end.line; n++)
34
- t.push(this.getLine(n));
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 n = this.getTextInRange(e);
41
- if (e.start.line === e.end.line) {
42
- const r = this.getLine(e.start.line), i = r.substring(0, e.start.column) + t + r.substring(e.end.column);
43
- this._lines[e.start.line] = i;
44
- } else {
45
- const r = this.getLine(e.start.line), i = this.getLine(e.end.line), o = r.substring(0, e.start.column) + t, l = i.substring(e.end.column), s = t.split(`
46
- `);
47
- s[0] = o + s[0], s[s.length - 1] = s[s.length - 1] + l, this._lines.splice(e.start.line, e.end.line - e.start.line + 1, ...s);
48
- }
49
- return this._version++, { range: e, text: t, oldText: n };
50
- }
51
- // Insert text at position
52
- insertText(e, t) {
53
- const n = { start: e, end: e };
54
- return this.replaceRange(n, 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 n = 0; n < e.line; n++)
64
- t += this.getLine(n).length + 1;
65
- return t += e.column, t;
66
- }
67
- // Convert offset to position
68
- offsetToPosition(e) {
69
- let t = e;
70
- for (let n = 0; n < this.getLineCount(); n++) {
71
- const r = this.getLine(n).length;
72
- if (t <= r)
73
- return { line: n, column: t };
74
- t -= r + 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 k();
96
- return e._lines = [...this._lines], e._version = this._version, e;
97
- }
98
- }
99
- class U {
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
- 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
- overflow: hidden;
117
- `, this.lineNumbersElement = document.createElement("div"), this.lineNumbersElement.style.cssText = `
118
- position: sticky;
119
- left: 0;
120
- top: 0;
121
- width: ${this.gutterWidth}px;
122
- background: var(--editor-gutter-background, #252526);
123
- color: var(--editor-gutter-foreground, #858585);
124
- padding: 0;
125
- text-align: right;
126
- border-right: 1px solid var(--editor-gutter-border, #3e3e42);
127
- user-select: none;
128
- overflow: hidden;
129
- z-index: 1;
130
- `, this.contentElement = document.createElement("div"), this.contentElement.style.cssText = `
131
- flex: 1;
132
- padding: 0;
133
- background: transparent;
134
- border: none;
135
- outline: none;
136
- white-space: pre;
137
- overflow-x: auto;
138
- overflow-y: auto;
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, e.appendChild(this.lineNumbersElement), e.appendChild(this.contentElement), this.container.appendChild(e), this.updateLineNumbers(1);
147
- }
148
- // Update line numbers
149
- updateLineNumbers(e) {
150
- const t = Math.max(e, 20), n = Array.from({ length: t }, (r, i) => i + 1);
151
- this.lineNumbersElement.innerHTML = n.map((r) => `<div style="height: ${this.lineHeight}px; line-height: ${this.lineHeight}px; padding-right: 12px;">${r}</div>`).join("");
152
- }
153
- // Get content element
154
- getContentElement() {
155
- return this.contentElement;
156
- }
157
- // Get line numbers element
158
- getLineNumbersElement() {
159
- return this.lineNumbersElement;
160
- }
161
- // Get text content
162
- getText() {
163
- return this.contentElement.textContent || "";
164
- }
165
- // Set text content
166
- setText(e) {
167
- this.contentElement.textContent = e;
168
- const t = e.split(`
169
- `).length;
170
- this.updateLineNumbers(t);
171
- }
172
- // Get cursor position from DOM selection
173
- getCursorPosition() {
174
- const e = window.getSelection();
175
- if (!e || e.rangeCount === 0)
176
- return { line: 0, column: 0 };
177
- const t = e.getRangeAt(0), n = t.cloneRange();
178
- n.selectNodeContents(this.contentElement), n.setEnd(t.endContainer, t.endOffset);
179
- const r = n.toString().split(`
180
- `);
181
- return {
182
- line: r.length - 1,
183
- column: r[r.length - 1].length
184
- };
185
- }
186
- // Set cursor position
187
- setCursorPosition(e) {
188
- var g, f;
189
- const t = this.getText().split(`
190
- `), n = Math.min(e.line, t.length - 1), r = Math.min(e.column, ((g = t[n]) == null ? void 0 : g.length) || 0);
191
- let i = 0;
192
- for (let m = 0; m < n; m++)
193
- i += t[m].length + 1;
194
- i += r;
195
- const o = document.createRange(), l = window.getSelection();
196
- let s = 0, d = null, a = 0;
197
- const c = document.createTreeWalker(
198
- this.contentElement,
199
- NodeFilter.SHOW_TEXT,
200
- null
201
- );
202
- let u;
203
- for (; u = c.nextNode(); ) {
204
- const m = ((f = u.textContent) == null ? void 0 : f.length) || 0;
205
- if (s + m >= i) {
206
- d = u, a = i - s;
207
- break;
208
- }
209
- s += m;
210
- }
211
- if (d)
212
- try {
213
- o.setStart(d, a), o.setEnd(d, a), l == null || l.removeAllRanges(), l == null || l.addRange(o);
214
- } catch (m) {
215
- console.warn("Could not set cursor position:", m);
216
- }
217
- }
218
- // Get selection range
219
- getSelectionRange() {
220
- const e = window.getSelection();
221
- if (!e || e.rangeCount === 0 || e.isCollapsed)
222
- return;
223
- const t = e.getRangeAt(0), n = t.cloneRange();
224
- n.selectNodeContents(this.contentElement), n.setEnd(t.startContainer, t.startOffset);
225
- const r = n.toString().split(`
226
- `), i = t.cloneRange();
227
- i.selectNodeContents(this.contentElement), i.setEnd(t.endContainer, t.endOffset);
228
- const o = i.toString().split(`
229
- `);
230
- return {
231
- start: {
232
- line: r.length - 1,
233
- column: r[r.length - 1].length
234
- },
235
- end: {
236
- line: o.length - 1,
237
- column: o[o.length - 1].length
238
- }
239
- };
240
- }
241
- // Set selection range
242
- setSelectionRange(e) {
243
- this.setCursorPosition(e.start);
244
- }
245
- // Focus the editor
246
- focus() {
247
- this.contentElement.focus();
248
- }
249
- // Blur the editor
250
- blur() {
251
- this.contentElement.blur();
252
- }
253
- // Set read-only mode
254
- setReadOnly(e) {
255
- this.contentElement.contentEditable = e ? "false" : "true";
256
- }
257
- // Apply theme
258
- applyTheme(e) {
259
- Object.entries(e).forEach(([t, n]) => {
260
- this.container.style.setProperty(`--${t}`, n);
261
- });
262
- }
263
- // Scroll to position
264
- scrollToPosition(e) {
265
- const t = this.lineNumbersElement.children[e.line];
266
- t && t.scrollIntoView({ block: "center", behavior: "smooth" });
267
- }
268
- // Get scroll position
269
- getScrollTop() {
270
- return this.contentElement.scrollTop;
271
- }
272
- // Set scroll position
273
- setScrollTop(e) {
274
- this.contentElement.scrollTop = e, this.lineNumbersElement.scrollTop = e;
275
- }
276
- // Destroy the view
277
- destroy() {
278
- this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container);
279
- }
280
- }
281
- class P {
282
- constructor(e, t = {}) {
283
- this.extensions = /* @__PURE__ */ new Map(), this.commands = /* @__PURE__ */ new Map(), this.eventListeners = /* @__PURE__ */ new Map(), this.folds = [], this.currentTheme = "default", this.isDestroyed = !1, this.config = {
284
- value: "",
285
- theme: "default",
286
- readOnly: !1,
287
- tabSize: 2,
288
- lineWrapping: !1,
289
- lineNumbers: !0,
290
- ...t
291
- }, this.textModel = new k(this.config.value), this.view = new U(e), this.view.setText(this.textModel.getText()), this.view.setReadOnly(this.config.readOnly || !1), this.setupEventHandlers(), this.config.extensions && this.config.extensions.forEach((n) => this.addExtension(n)), this.setTheme(this.config.theme);
292
- }
293
- // Public accessors for extensions
294
- getTextModel() {
295
- return this.textModel;
296
- }
297
- getView() {
298
- return this.view;
299
- }
300
- getConfig() {
301
- return { ...this.config };
302
- }
303
- // Get keymap extension if available
304
- getKeymapExtension() {
305
- return this.extensions.get("keymap");
306
- }
307
- // Setup DOM event handlers
308
- setupEventHandlers() {
309
- const e = this.view.getContentElement();
310
- e.addEventListener("input", () => {
311
- const t = this.view.getText(), n = this.textModel.getText();
312
- t !== n && (this.textModel.setText(t), this.emit("change", [{ range: this.getFullRange(), text: t, oldText: n }]), this.updateLineNumbers());
313
- }), e.addEventListener("selectionchange", () => {
314
- const t = this.getCursor(), n = this.getSelection();
315
- this.emit("cursor", t), n && this.emit("selection", n);
316
- }), e.addEventListener("keydown", (t) => {
317
- this.emit("keydown", t);
318
- for (const n of this.extensions.values())
319
- if (n.onKeyDown && n.onKeyDown(t) === !1) {
320
- t.preventDefault(), t.stopPropagation();
321
- return;
322
- }
323
- }), e.addEventListener("mousedown", (t) => {
324
- this.emit("mousedown", t);
325
- for (const n of this.extensions.values())
326
- if (n.onMouseDown && n.onMouseDown(t) === !1) {
327
- t.preventDefault(), t.stopPropagation();
328
- return;
329
- }
330
- }), e.addEventListener("focus", () => {
331
- this.emit("focus");
332
- }), e.addEventListener("blur", () => {
333
- this.emit("blur");
334
- });
335
- }
336
- // Update line numbers display
337
- updateLineNumbers() {
338
- const e = this.textModel.getLineCount();
339
- this.view.updateLineNumbers(e);
340
- }
341
- // Get full range of document
342
- getFullRange() {
343
- return {
344
- start: { line: 0, column: 0 },
345
- end: {
346
- line: this.textModel.getLineCount() - 1,
347
- column: this.textModel.getLine(this.textModel.getLineCount() - 1).length
348
- }
349
- };
350
- }
351
- // Emit events to listeners
352
- emit(e, ...t) {
353
- const n = this.eventListeners.get(e);
354
- n && n.forEach((r) => r(...t));
355
- }
356
- // State management
357
- getValue() {
358
- return this.textModel.getText();
359
- }
360
- setValue(e) {
361
- this.textModel.setText(e), this.view.setText(e), this.updateLineNumbers(), this.emit("change", [{ range: this.getFullRange(), text: e, oldText: this.getValue() }]);
362
- }
363
- getState() {
364
- return {
365
- text: this.getValue(),
366
- cursor: this.getCursor(),
367
- selection: this.getSelection(),
368
- readOnly: this.config.readOnly || !1,
369
- theme: this.currentTheme
370
- };
371
- }
372
- // Cursor & Selection
373
- getCursor() {
374
- const e = this.view.getCursorPosition();
375
- return {
376
- position: e,
377
- anchor: e
378
- // For now, cursor and anchor are the same
379
- };
380
- }
381
- setCursor(e) {
382
- this.view.setCursorPosition(e), this.emit("cursor", this.getCursor());
383
- }
384
- getSelection() {
385
- return this.view.getSelectionRange();
386
- }
387
- setSelection(e) {
388
- this.view.setSelectionRange(e), this.emit("selection", e);
389
- }
390
- // Configuration
391
- setTheme(e) {
392
- this.currentTheme = e;
393
- const t = {
394
- "editor-background": e === "dark" ? "#1e1e1e" : "#ffffff",
395
- "editor-foreground": e === "dark" ? "#f8f9fa" : "#1a1a1a",
396
- "editor-gutter-background": e === "dark" ? "#252526" : "#f8f9fa",
397
- "editor-gutter-foreground": e === "dark" ? "#858585" : "#666666",
398
- "editor-gutter-border": e === "dark" ? "#3e3e42" : "#e1e5e9"
399
- };
400
- this.view.applyTheme(t);
401
- }
402
- setReadOnly(e) {
403
- this.config.readOnly = e, this.view.setReadOnly(e);
404
- }
405
- // Extensions & Commands
406
- addExtension(e) {
407
- if (this.extensions.has(e.name))
408
- throw new Error(`Extension '${e.name}' already exists`);
409
- this.extensions.set(e.name, e), e.setup(this);
410
- }
411
- removeExtension(e) {
412
- const t = this.extensions.get(e);
413
- t && t.destroy && t.destroy(), this.extensions.delete(e);
414
- }
415
- executeCommand(e, ...t) {
416
- const n = this.commands.get(e);
417
- n ? n(this, ...t) : console.warn(`Command '${e}' not found`);
418
- }
419
- // Register a command
420
- registerCommand(e, t) {
421
- this.commands.set(e, t);
422
- }
423
- // Search & Navigation
424
- search(e, t = {}) {
425
- const n = {
426
- caseSensitive: !1,
427
- regex: !1,
428
- ...t
429
- }, r = [], i = this.getValue();
430
- i.split(`
431
- `);
432
- let o = n.caseSensitive ? i : i.toLowerCase(), l = n.caseSensitive ? e : e.toLowerCase();
433
- if (n.regex) {
434
- const s = new RegExp(l, n.caseSensitive ? "g" : "gi");
435
- let d;
436
- for (; (d = s.exec(o)) !== null; ) {
437
- const a = this.textModel.offsetToPosition(d.index), c = this.textModel.offsetToPosition(d.index + d[0].length);
438
- r.push({
439
- range: { start: a, end: c },
440
- match: d[0]
441
- });
442
- }
443
- } else {
444
- let s = 0, d = o.indexOf(l, s);
445
- for (; d !== -1; ) {
446
- const a = d + e.length, c = this.textModel.offsetToPosition(d), u = this.textModel.offsetToPosition(a);
447
- r.push({
448
- range: { start: c, end: u },
449
- match: i.substring(d, a)
450
- }), s = a, d = o.indexOf(l, s);
451
- }
452
- }
453
- return r;
454
- }
455
- replace(e, t) {
456
- const n = this.textModel.replaceRange(e, t);
457
- this.view.setText(this.getValue()), this.emit("change", [n]);
458
- }
459
- replaceAll(e, t, n = {}) {
460
- const r = this.search(e, n);
461
- let i = 0;
462
- for (let o = r.length - 1; o >= 0; o--)
463
- this.replace(r[o].range, t), i++;
464
- return i;
465
- }
466
- // Folding (basic implementation)
467
- fold(e) {
468
- const t = {
469
- start: e.start,
470
- end: e.end,
471
- collapsed: !0,
472
- level: 0
473
- };
474
- this.folds.push(t);
475
- }
476
- unfold(e) {
477
- this.folds = this.folds.filter(
478
- (t) => !(t.start.line === e.start.line && t.end.line === e.end.line)
479
- );
480
- }
481
- getFolds() {
482
- return [...this.folds];
483
- }
484
- // Utilities
485
- focus() {
486
- this.view.focus();
487
- }
488
- blur() {
489
- this.view.blur();
490
- }
491
- destroy() {
492
- if (!this.isDestroyed) {
493
- this.isDestroyed = !0;
494
- for (const e of this.extensions.values())
495
- e.destroy && e.destroy();
496
- this.extensions.clear(), this.view.destroy(), this.commands.clear(), this.eventListeners.clear();
497
- }
498
- }
499
- // Events
500
- on(e, t) {
501
- this.eventListeners.has(e) || this.eventListeners.set(e, []), this.eventListeners.get(e).push(t);
502
- }
503
- off(e, t) {
504
- if (!this.eventListeners.has(e)) return;
505
- const n = this.eventListeners.get(e);
506
- if (t) {
507
- const r = n.indexOf(t);
508
- r !== -1 && n.splice(r, 1);
509
- } else
510
- n.length = 0;
511
- }
512
- }
513
- class z {
514
- constructor(e) {
515
- this.name = "keymap", this.editor = null, this.keymap = {}, this.isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0, this.keymap = e || this.getDefaultKeymap();
516
- }
517
- setup(e) {
518
- this.editor = e, e.on("keydown", (t) => this.handleKeyDown(t));
519
- }
520
- handleKeyDown(e) {
521
- if (!this.editor) return;
522
- const t = this.findMatchingBinding(e);
523
- if (t)
524
- return this.editor.executeCommand(t.command), e.preventDefault(), e.stopPropagation(), !1;
525
- }
526
- findMatchingBinding(e) {
527
- const { key: t, ctrlKey: n, altKey: r, shiftKey: i, metaKey: o } = e, l = t.toLowerCase(), s = this.keymap[l];
528
- if (!s) return null;
529
- for (const d of s)
530
- if ((d.ctrlKey === n || !d.ctrlKey && !n) && (d.altKey === r || !d.altKey && !r) && (d.shiftKey === i || !d.shiftKey && !i) && (d.metaKey === o || !d.metaKey && !o))
531
- return d;
532
- return null;
533
- }
534
- getDefaultKeymap() {
535
- const e = {};
536
- 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: !this.isMac, metaKey: this.isMac }, "save"), this.addBinding(e, "z", { ctrlKey: !this.isMac, metaKey: this.isMac }, "undo"), this.addBinding(e, "y", { ctrlKey: !this.isMac, metaKey: this.isMac }, "redo"), this.addBinding(e, "z", { ctrlKey: !this.isMac, metaKey: this.isMac, shiftKey: !0 }, "redo"), this.addBinding(e, "t", { ctrlKey: !this.isMac, metaKey: this.isMac, shiftKey: !0 }, "toggleTheme"), e;
537
- }
538
- addBinding(e, t, n, r) {
539
- const i = t.toLowerCase();
540
- e[i] || (e[i] = []), e[i].push({
541
- key: i,
542
- command: r,
543
- ...n
544
- });
545
- }
546
- // Public API for customizing keymap
547
- setKeymap(e) {
548
- this.keymap = { ...e };
549
- }
550
- addKeyBinding(e) {
551
- const t = e.key.toLowerCase();
552
- this.keymap[t] || (this.keymap[t] = []), this.keymap[t] = this.keymap[t].filter((n) => n.command !== e.command), this.keymap[t].push({
553
- ...e,
554
- key: t
555
- });
556
- }
557
- removeKeyBinding(e, t) {
558
- const n = e.toLowerCase();
559
- t ? this.keymap[n] && (this.keymap[n] = this.keymap[n].filter((r) => r.command !== t), this.keymap[n].length === 0 && delete this.keymap[n]) : delete this.keymap[n];
560
- }
561
- getKeymap() {
562
- return { ...this.keymap };
563
- }
564
- getBindingsForCommand(e) {
565
- const t = [];
566
- for (const n in this.keymap)
567
- for (const r of this.keymap[n])
568
- r.command === e && t.push({ ...r });
569
- return t;
570
- }
571
- getPlatformInfo() {
572
- return {
573
- isMac: this.isMac,
574
- platform: navigator.platform
575
- };
576
- }
577
- destroy() {
578
- this.keymap = {}, this.editor = null;
579
- }
580
- }
581
- class A {
582
- constructor() {
583
- this.name = "line-numbers", this.editor = null, this.lineNumbersElement = null, this.isEnabled = !0;
584
- }
585
- setup(e) {
586
- this.editor = e, this.createLineNumbers(), e.registerCommand("toggleLineNumbers", () => {
587
- this.toggle();
588
- }), e.on("change", () => {
589
- this.updateLineNumbers();
590
- }), this.updateLineNumbers();
591
- }
592
- createLineNumbers() {
593
- if (!this.editor) return;
594
- const e = this.editor.getView();
595
- if (!e.container) return;
596
- this.lineNumbersElement = document.createElement("div"), this.lineNumbersElement.style.cssText = `
597
- position: absolute;
598
- left: 0;
599
- top: 0;
600
- bottom: 0;
601
- width: 50px;
602
- background: var(--editor-gutter-background, #252526);
603
- color: var(--editor-gutter-foreground, #858585);
604
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
605
- font-size: 14px;
606
- line-height: 21px;
607
- padding: 0;
608
- text-align: right;
609
- border-right: 1px solid var(--editor-gutter-border, #3e3e42);
610
- user-select: none;
611
- overflow: hidden;
612
- z-index: 1;
613
- pointer-events: none;
614
- `;
615
- const t = e.getContentElement();
616
- t && t.parentNode && (t.parentNode.insertBefore(this.lineNumbersElement, t), t.style.marginLeft = "60px");
617
- }
618
- updateLineNumbers() {
619
- if (!this.lineNumbersElement || !this.editor || !this.isEnabled) return;
620
- const e = this.editor.getValue().split(`
621
- `).length, t = Array.from({ length: Math.max(e, 20) }, (n, r) => r + 1);
622
- this.lineNumbersElement.innerHTML = t.map((n) => `<div style="height: 21px; line-height: 21px; padding-right: 12px;">${n}</div>`).join("");
623
- }
624
- toggle() {
625
- this.isEnabled = !this.isEnabled, this.lineNumbersElement && (this.lineNumbersElement.style.display = this.isEnabled ? "block" : "none");
626
- const e = this.editor.getView().getContentElement();
627
- e && (e.style.marginLeft = this.isEnabled ? "60px" : "0"), this.updateLineNumbers();
628
- }
629
- destroy() {
630
- this.lineNumbersElement && this.lineNumbersElement.parentNode && this.lineNumbersElement.parentNode.removeChild(this.lineNumbersElement), this.lineNumbersElement = null, this.editor = null;
631
- }
632
- }
633
- class V {
634
- constructor() {
635
- this.name = "theme", this.editor = null, this.currentTheme = "dark";
636
- }
637
- setup(e) {
638
- this.editor = e, e.registerCommand("setTheme", (t) => {
639
- this.setTheme(t);
640
- }), e.registerCommand("toggleTheme", () => {
641
- this.toggleTheme();
642
- }), this.setTheme(this.currentTheme);
643
- }
644
- setTheme(e) {
645
- this.editor && (this.currentTheme = e, this.editor.setTheme(e));
646
- }
647
- toggleTheme() {
648
- const e = this.currentTheme === "dark" ? "light" : "dark";
649
- this.setTheme(e);
650
- }
651
- getCurrentTheme() {
652
- return this.currentTheme;
653
- }
654
- destroy() {
655
- this.editor = null;
656
- }
657
- }
658
- class F {
659
- constructor() {
660
- this.name = "read-only", this.editor = null, this.isReadOnly = !1;
661
- }
662
- setup(e) {
663
- this.editor = e, e.registerCommand("setReadOnly", (t) => {
664
- this.setReadOnly(t);
665
- }), e.registerCommand("toggleReadOnly", () => {
666
- this.toggleReadOnly();
667
- }), e.on("keydown", (t) => {
668
- if (t.ctrlKey && t.key === "r")
669
- return t.preventDefault(), this.toggleReadOnly(), !1;
670
- });
671
- }
672
- setReadOnly(e) {
673
- this.editor && (this.isReadOnly = e, this.editor.setReadOnly(e));
674
- }
675
- toggleReadOnly() {
676
- this.setReadOnly(!this.isReadOnly);
677
- }
678
- isCurrentlyReadOnly() {
679
- return this.isReadOnly;
680
- }
681
- destroy() {
682
- this.editor = null;
683
- }
684
- }
685
- class q {
686
- constructor() {
687
- this.name = "search", this.editor = null, this.searchUI = null, this.isVisible = !1, this.currentResults = [], this.currentIndex = -1;
688
- }
689
- setup(e) {
690
- this.editor = e, e.registerCommand("find", () => {
691
- this.showSearch();
692
- }), e.registerCommand("findNext", () => {
693
- this.findNext();
694
- }), e.registerCommand("findPrev", () => {
695
- this.findPrev();
696
- }), e.registerCommand("replace", () => {
697
- this.showReplace();
698
- }), e.registerCommand("replaceAll", (t, n) => {
699
- this.replaceAll(t, n);
700
- });
701
- }
702
- showSearch() {
703
- if (this.editor && (this.searchUI || this.createSearchUI(), this.isVisible = !0, this.searchUI)) {
704
- this.searchUI.style.display = "block";
705
- const e = this.searchUI.querySelector("input");
706
- e && (e.focus(), e.select());
707
- }
708
- }
709
- showReplace() {
710
- var n, r;
711
- this.showSearch();
712
- const e = (n = this.searchUI) == null ? void 0 : n.querySelector(".search-replace-input");
713
- e && (e.style.display = "block", e.focus());
714
- const t = (r = this.searchUI) == null ? void 0 : r.querySelector(".search-status");
715
- t && (t.textContent = "Replace mode - Enter to replace, Shift+Enter to replace all");
716
- }
717
- hideSearch() {
718
- this.isVisible = !1, this.searchUI && (this.searchUI.style.display = "none"), this.clearHighlights();
719
- }
720
- createSearchUI() {
721
- if (!this.editor) return;
722
- const e = document.querySelector(".rte-source-editor-modal");
723
- if (!e) return;
724
- this.searchUI = document.createElement("div"), this.searchUI.style.cssText = `
725
- position: absolute;
726
- top: 10px;
727
- right: 10px;
728
- background: var(--editor-background, #1e1e1e);
729
- border: 1px solid var(--editor-gutter-border, #3e3e42);
730
- border-radius: 4px;
731
- padding: 8px;
732
- z-index: 1000;
733
- display: none;
734
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
735
- min-width: 250px;
736
- `, this.searchUI.innerHTML = `
737
- <div style="display: flex; align-items: center; gap: 4px; margin-bottom: 4px;">
738
- <input type="text" placeholder="Find..." style="
739
- flex: 1;
740
- padding: 4px 8px;
741
- background: var(--editor-gutter-background, #252526);
742
- color: var(--editor-foreground, #f8f9fa);
743
- border: 1px solid var(--editor-gutter-border, #3e3e42);
744
- border-radius: 3px;
745
- font-size: 12px;
746
- outline: none;
747
- " />
748
- <button class="search-prev" style="
749
- padding: 2px 6px;
750
- background: var(--editor-gutter-background, #252526);
751
- color: var(--editor-gutter-foreground, #858585);
752
- border: 1px solid var(--editor-gutter-border, #3e3e42);
753
- border-radius: 3px;
754
- cursor: pointer;
755
- font-size: 11px;
756
- ">↑</button>
757
- <button class="search-next" style="
758
- padding: 2px 6px;
759
- background: var(--editor-gutter-background, #252526);
760
- color: var(--editor-gutter-foreground, #858585);
761
- border: 1px solid var(--editor-gutter-border, #3e3e42);
762
- border-radius: 3px;
763
- cursor: pointer;
764
- font-size: 11px;
765
- ">↓</button>
766
- <button class="search-close" style="
767
- padding: 2px 6px;
768
- background: var(--editor-gutter-background, #252526);
769
- color: var(--editor-gutter-foreground, #858585);
770
- border: 1px solid var(--editor-gutter-border, #3e3e42);
771
- border-radius: 3px;
772
- cursor: pointer;
773
- font-size: 11px;
774
- ">×</button>
775
- </div>
776
- <div class="search-status" style="
777
- font-size: 11px;
778
- color: var(--editor-gutter-foreground, #858585);
779
- text-align: center;
780
- "></div>
781
- <input type="text" class="search-replace-input" placeholder="Replace with..." style="
782
- width: 100%;
783
- padding: 4px 8px;
784
- background: var(--editor-gutter-background, #252526);
785
- color: var(--editor-foreground, #f8f9fa);
786
- border: 1px solid var(--editor-gutter-border, #3e3e42);
787
- border-radius: 3px;
788
- font-size: 12px;
789
- outline: none;
790
- display: none;
791
- margin-top: 4px;
792
- " />
793
- `;
794
- const t = this.searchUI.querySelector("input"), n = this.searchUI.querySelector(".search-replace-input"), r = this.searchUI.querySelector(".search-prev"), i = this.searchUI.querySelector(".search-next"), o = this.searchUI.querySelector(".search-close");
795
- t.addEventListener("input", () => {
796
- this.performSearch(t.value);
797
- }), t.addEventListener("keydown", (l) => {
798
- l.key === "Enter" && (l.preventDefault(), l.shiftKey ? this.findPrev() : this.findNext());
799
- }), n.addEventListener("keydown", (l) => {
800
- l.key === "Enter" && (l.preventDefault(), l.shiftKey ? this.replaceAll(t.value, n.value) : this.replaceCurrent(t.value, n.value));
801
- }), r.addEventListener("click", () => this.findPrev()), i.addEventListener("click", () => this.findNext()), o.addEventListener("click", () => this.hideSearch()), e.appendChild(this.searchUI);
802
- }
803
- performSearch(e) {
804
- if (!this.editor || !e.trim()) {
805
- this.clearHighlights(), this.updateStatus("");
806
- return;
807
- }
808
- const t = this.editor.getValue(), n = [];
809
- let r = t.toLowerCase().indexOf(e.toLowerCase());
810
- for (; r !== -1; ) {
811
- const i = this.getPositionFromOffset(t, r), o = this.getPositionFromOffset(t, r + e.length);
812
- n.push({
813
- range: { start: i, end: o },
814
- match: t.substring(r, r + e.length)
815
- }), r = t.toLowerCase().indexOf(e.toLowerCase(), r + 1);
816
- }
817
- this.currentResults = n, this.currentIndex = this.currentResults.length > 0 ? 0 : -1, this.updateHighlights(), this.updateStatus(`${this.currentResults.length} matches`);
818
- }
819
- getPositionFromOffset(e, t) {
820
- const n = e.substring(0, t).split(`
821
- `), r = n.length - 1, i = n[n.length - 1].length;
822
- return { line: r, column: i };
823
- }
824
- findNext() {
825
- this.currentResults.length !== 0 && (this.currentIndex = (this.currentIndex + 1) % this.currentResults.length, this.updateHighlights());
826
- }
827
- findPrev() {
828
- this.currentResults.length !== 0 && (this.currentIndex = this.currentIndex <= 0 ? this.currentResults.length - 1 : this.currentIndex - 1, this.updateHighlights());
829
- }
830
- replaceCurrent(e, t) {
831
- if (!this.editor || !e.trim() || this.currentIndex === -1) return;
832
- const n = this.currentResults[this.currentIndex];
833
- if (!n) return;
834
- const r = this.editor.getValue(), i = this.getOffsetFromPosition(r, n.range.start), o = r.substring(0, i), l = r.substring(i + e.length), s = o + t + l;
835
- this.editor.setValue(s), this.performSearch(e), this.updateStatus("Replaced current occurrence");
836
- }
837
- replaceAll(e, t) {
838
- if (!this.editor || !e.trim()) return;
839
- let n = this.editor.getValue(), r = 0, i = n.toLowerCase().indexOf(e.toLowerCase());
840
- for (; i !== -1; )
841
- n = n.substring(0, i) + t + n.substring(i + e.length), r++, i = n.toLowerCase().indexOf(e.toLowerCase(), i + t.length);
842
- r > 0 && (this.editor.setValue(n), this.updateStatus(`Replaced ${r} occurrences`));
843
- }
844
- getOffsetFromPosition(e, t) {
845
- const n = e.split(`
846
- `);
847
- let r = 0;
848
- for (let i = 0; i < t.line; i++)
849
- r += n[i].length + 1;
850
- return r += t.column, r;
851
- }
852
- updateHighlights() {
853
- 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})`));
854
- }
855
- clearHighlights() {
856
- }
857
- updateStatus(e) {
858
- var n;
859
- const t = (n = this.searchUI) == null ? void 0 : n.querySelector(".search-status");
860
- t && (t.textContent = e);
861
- }
862
- destroy() {
863
- this.searchUI && this.searchUI.parentNode && this.searchUI.parentNode.removeChild(this.searchUI), this.searchUI = null, this.editor = null;
864
- }
865
- }
866
- class D {
867
- constructor() {
868
- this.name = "bracket-matching", this.editor = null, this.bracketPairs = {
869
- "(": ")",
870
- "[": "]",
871
- "{": "}",
872
- "<": ">"
873
- }, this.reverseBracketPairs = {
874
- ")": "(",
875
- "]": "[",
876
- "}": "{",
877
- ">": "<"
878
- }, this.currentMatch = null;
879
- }
880
- setup(e) {
881
- this.editor = e, e.on("cursor", () => {
882
- this.updateBracketMatching();
883
- }), e.on("change", () => {
884
- this.updateBracketMatching();
885
- });
886
- }
887
- updateBracketMatching() {
888
- if (!this.editor) return;
889
- const e = this.editor.getCursor(), t = this.editor.getValue();
890
- this.clearBracketHighlighting();
891
- const n = this.getBracketAtPosition(t, e.position);
892
- if (!n) return;
893
- const r = this.findMatchingBracket(t, n);
894
- r && (this.currentMatch = r, this.highlightBrackets(r));
895
- }
896
- getBracketAtPosition(e, t) {
897
- const n = e.split(`
898
- `);
899
- if (t.line >= n.length) return null;
900
- const r = n[t.line];
901
- if (t.column >= r.length) return null;
902
- const i = r[t.column];
903
- return this.bracketPairs[i] || this.reverseBracketPairs[i] ? { char: i, position: t } : null;
904
- }
905
- findMatchingBracket(e, t) {
906
- const n = e.split(`
907
- `), r = t.position.line, i = t.position.column, o = t.char;
908
- return this.bracketPairs[o] ? this.findClosingBracket(e, n, r, i, o) : this.reverseBracketPairs[o] ? this.findOpeningBracket(e, n, r, i, o) : null;
909
- }
910
- findClosingBracket(e, t, n, r, i) {
911
- const o = this.bracketPairs[i];
912
- let l = 0;
913
- for (let s = n; s < t.length; s++) {
914
- const d = t[s], a = s === n ? r : 0;
915
- for (let c = a; c < d.length; c++) {
916
- const u = d[c];
917
- if (u === i)
918
- l++;
919
- else if (u === o && (l--, l === 0))
920
- return {
921
- open: { start: { line: n, column: r }, end: { line: n, column: r + 1 } },
922
- close: { start: { line: s, column: c }, end: { line: s, column: c + 1 } },
923
- type: i
924
- };
925
- }
926
- }
927
- return null;
928
- }
929
- findOpeningBracket(e, t, n, r, i) {
930
- const o = this.reverseBracketPairs[i];
931
- let l = 0;
932
- for (let s = n; s >= 0; s--) {
933
- const d = t[s], a = s === n ? r : d.length - 1;
934
- for (let c = a; c >= 0; c--) {
935
- const u = d[c];
936
- if (u === i)
937
- l++;
938
- else if (u === o && (l--, l === 0))
939
- return {
940
- open: { start: { line: s, column: c }, end: { line: s, column: c + 1 } },
941
- close: { start: { line: n, column: r }, end: { line: n, column: r + 1 } },
942
- type: o
943
- };
944
- }
945
- }
946
- return null;
947
- }
948
- highlightBrackets(e) {
949
- console.log("Bracket match found:", e);
950
- }
951
- clearBracketHighlighting() {
952
- this.currentMatch = null;
953
- }
954
- getCurrentMatch() {
955
- return this.currentMatch;
956
- }
957
- destroy() {
958
- this.clearBracketHighlighting(), this.editor = null;
959
- }
960
- }
961
- class $ {
962
- constructor() {
963
- this.name = "code-folding", this.editor = null, this.foldIndicators = [], this.foldingUI = null;
964
- }
965
- setup(e) {
966
- this.editor = e, e.registerCommand("fold", () => {
967
- console.log("Fold command executed - folding not yet implemented"), this.foldAtCursor();
968
- }), e.registerCommand("unfold", () => {
969
- console.log("Unfold command executed - unfolding not yet implemented"), this.unfoldAtCursor();
970
- }), e.registerCommand("foldAll", () => {
971
- console.log("Fold all command executed - folding not yet implemented"), this.foldAll();
972
- }), e.registerCommand("unfoldAll", () => {
973
- console.log("Unfold all command executed - unfolding not yet implemented"), this.unfoldAll();
974
- }), e.on("change", () => {
975
- this.updateFoldIndicators();
976
- }), this.createFoldingUI(), this.updateFoldIndicators();
977
- }
978
- createFoldingUI() {
979
- if (!this.editor) return;
980
- const e = document.querySelector(".rte-source-editor-modal");
981
- e && (this.foldingUI = document.createElement("div"), this.foldingUI.style.cssText = `
982
- position: absolute;
983
- left: 40px;
984
- top: 0;
985
- bottom: 0;
986
- width: 20px;
987
- pointer-events: none;
988
- z-index: 2;
989
- `, e.appendChild(this.foldingUI));
990
- }
991
- updateFoldIndicators() {
992
- if (!this.editor || !this.foldingUI) return;
993
- this.foldingUI.innerHTML = "", this.foldIndicators = [];
994
- const e = this.editor.getValue().split(`
995
- `);
996
- this.findFoldableLines(e).forEach((t) => {
997
- this.createFoldIndicator(t);
998
- });
999
- }
1000
- findFoldableLines(e) {
1001
- const t = [];
1002
- for (let n = 0; n < e.length; n++) {
1003
- const r = e[n].trim();
1004
- (r.startsWith("{") || r.startsWith("function") || r.startsWith("class") || r.startsWith("if") || r.includes("=>") || r.startsWith("for") || r.startsWith("while") || r.startsWith("try")) && t.push(n);
1005
- }
1006
- return t;
1007
- }
1008
- createFoldIndicator(e) {
1009
- if (!this.foldingUI) return;
1010
- const t = document.createElement("div");
1011
- t.style.cssText = `
1012
- position: absolute;
1013
- left: 0;
1014
- top: ${e * 21}px;
1015
- width: 20px;
1016
- height: 21px;
1017
- display: flex;
1018
- align-items: center;
1019
- justify-content: center;
1020
- cursor: pointer;
1021
- pointer-events: auto;
1022
- color: var(--editor-gutter-foreground, #858585);
1023
- font-size: 10px;
1024
- user-select: none;
1025
- `, t.innerHTML = "▶", t.title = "Code folding not yet implemented - click shows fold indicators", t.addEventListener("click", () => {
1026
- console.log(`Fold toggle clicked at line ${e} - implementation pending`);
1027
- }), this.foldingUI.appendChild(t), this.foldIndicators.push(t);
1028
- }
1029
- foldAtCursor() {
1030
- console.log("foldAtCursor called - implementation pending");
1031
- }
1032
- unfoldAtCursor() {
1033
- console.log("unfoldAtCursor called - implementation pending");
1034
- }
1035
- foldAll() {
1036
- console.log("foldAll called - implementation pending");
1037
- }
1038
- unfoldAll() {
1039
- console.log("unfoldAll called - implementation pending");
1040
- }
1041
- destroy() {
1042
- this.foldingUI && this.foldingUI.parentNode && this.foldingUI.parentNode.removeChild(this.foldingUI), this.foldingUI = null, this.foldIndicators = [], this.editor = null;
1043
- }
1044
- }
1045
- class _ {
1046
- constructor() {
1047
- this.name = "syntax-highlighting", this.editor = null, this.currentTheme = "dark";
1048
- }
1049
- setup(e) {
1050
- this.editor = e, console.log("SyntaxHighlightingExtension: Isolated extension loaded - ready for use");
1051
- }
1052
- // Extension provides methods that can be called by the editor
1053
- setTheme(e) {
1054
- this.currentTheme = e, console.log(`SyntaxHighlightingExtension: Theme changed to ${e}`);
1055
- }
1056
- // Method to get syntax highlighting colors for a given theme
1057
- getSyntaxColors() {
1058
- return this.currentTheme === "dark" ? {
1059
- tag: "#569cd6",
1060
- // Blue
1061
- comment: "#6a9955",
1062
- // Green
1063
- attrValue: "#ce9178",
1064
- // Orange
1065
- text: "#d4d4d4"
1066
- // Light gray
1067
- } : {
1068
- tag: "#0000ff",
1069
- // Blue
1070
- comment: "#008000",
1071
- // Green
1072
- attrValue: "#a31515",
1073
- // Red
1074
- text: "#000000"
1075
- // Black
1076
- };
1077
- }
1078
- // Method to parse and highlight HTML content (returns highlighted HTML string)
1079
- highlightHTML(e) {
1080
- const t = this.getSyntaxColors();
1081
- let n = e;
1082
- return n = n.replace(
1083
- /(<\/?[\w:-]+(?:\s[^>]*?)?\/?>)/g,
1084
- `<span style="color: ${t.tag};">$1</span>`
1085
- ), n = n.replace(
1086
- /(<!--[\s\S]*?-->)/g,
1087
- `<span style="color: ${t.comment};">$1</span>`
1088
- ), n = n.replace(
1089
- /("[^"]*"|'[^']*')/g,
1090
- `<span style="color: ${t.attrValue};">$1</span>`
1091
- ), n;
1092
- }
1093
- // Method to check if content contains syntax that should be highlighted
1094
- shouldHighlight(e) {
1095
- return /<\/?[\w:-]+|<!--/.test(e);
1096
- }
1097
- destroy() {
1098
- this.editor = null, console.log("SyntaxHighlightingExtension: Extension destroyed");
1099
- }
1100
- }
1101
- function j(p, e) {
1102
- const t = { ...e };
1103
- return t.extensions || (t.extensions = []), t.extensions.some((n) => n.name === "keymap") || t.extensions.unshift(new z(t.keymap)), new P(p, t);
1104
- }
1105
- const W = `/* Source Editor Dialog Styles */
1106
- .rte-source-editor-overlay {
1107
- position: fixed !important;
1108
- top: 0 !important;
1109
- left: 0 !important;
1110
- right: 0 !important;
1111
- bottom: 0 !important;
1112
- width: 100vw !important;
1113
- height: 100vh !important;
1114
- background-color: rgba(0, 0, 0, 0.6) !important;
1115
- display: flex !important;
1116
- align-items: center !important;
1117
- justify-content: center !important;
1118
- z-index: 10000 !important;
1119
- padding: 20px !important;
1120
- box-sizing: border-box !important;
1121
- margin: 0 !important;
1122
- }
1123
-
1124
- .rte-source-editor-overlay.fullscreen {
1125
- padding: 0 !important;
1126
- }
1127
-
1128
- .rte-source-editor-modal {
1129
- background: white;
1130
- border-radius: 8px;
1131
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
1132
- width: 100%;
1133
- max-width: 1200px;
1134
- max-height: 90vh;
1135
- display: flex;
1136
- flex-direction: column;
1137
- overflow: hidden;
1138
- position: relative;
1139
- }
1140
-
1141
- .rte-source-editor-overlay.fullscreen .rte-source-editor-modal {
1142
- border-radius: 0;
1143
- max-width: 100%;
1144
- max-height: 100vh;
1145
- width: 100%;
1146
- height: 100vh;
1147
- }
1148
-
1149
- .rte-source-editor-header {
1150
- display: flex;
1151
- align-items: center;
1152
- justify-content: space-between;
1153
- padding: 16px 20px;
1154
- border-bottom: 1px solid #e1e5e9;
1155
- background: #f8f9fa;
1156
- border-radius: 8px 8px 0 0;
1157
- }
1158
-
1159
- .rte-source-editor-overlay.fullscreen .rte-source-editor-header {
1160
- border-radius: 0;
1161
- }
1162
-
1163
- .rte-source-editor-header h2 {
1164
- margin: 0;
1165
- font-size: 18px;
1166
- font-weight: 600;
1167
- color: #1a1a1a;
1168
- }
1169
-
1170
- .rte-source-editor-header-toolbar {
1171
- display: flex;
1172
- gap: 8px;
1173
- margin-left: auto;
1174
- margin-right: 16px;
1175
- }
1176
-
1177
- .rte-source-editor-toolbar-btn {
1178
- background: none;
1179
- border: none;
1180
- cursor: pointer;
1181
- padding: 6px;
1182
- border-radius: 4px;
1183
- font-size: 16px;
1184
- line-height: 1;
1185
- transition: all 0.2s ease;
1186
- color: #666;
1187
- }
1188
-
1189
- .rte-source-editor-toolbar-btn:hover:not(:disabled) {
1190
- background: #e1e5e9;
1191
- color: #1a1a1a;
1192
- }
1193
-
1194
- .rte-source-editor-toolbar-btn:disabled {
1195
- opacity: 0.5;
1196
- cursor: not-allowed;
1197
- }
1198
-
1199
- .rte-source-editor-toolbar-btn.active {
1200
- background: #007acc;
1201
- color: white;
1202
- }
1203
-
1204
- .rte-source-editor-toolbar-btn.active:hover {
1205
- background: #0056b3;
1206
- }
1207
-
1208
- .rte-source-editor-header-actions {
1209
- display: flex;
1210
- gap: 8px;
1211
- }
1212
-
1213
- .rte-source-editor-fullscreen-btn,
1214
- .rte-source-editor-close-btn {
1215
- background: none;
1216
- border: none;
1217
- cursor: pointer;
1218
- padding: 4px;
1219
- border-radius: 4px;
1220
- color: #666;
1221
- font-size: 16px;
1222
- line-height: 1;
1223
- transition: all 0.2s ease;
1224
- }
1225
-
1226
- .rte-source-editor-fullscreen-btn:hover,
1227
- .rte-source-editor-close-btn:hover {
1228
- background: #e1e5e9;
1229
- color: #1a1a1a;
1230
- }
1231
-
1232
- .rte-source-editor-body {
1233
- flex: 1;
1234
- overflow: hidden;
1235
- display: flex;
1236
- flex-direction: column;
1237
- }
1238
-
1239
- .rte-source-editor-loading {
1240
- display: flex;
1241
- flex-direction: column;
1242
- align-items: center;
1243
- justify-content: center;
1244
- padding: 40px;
1245
- color: #666;
1246
- position: absolute;
1247
- z-index: 9;
1248
- margin: 0 auto;
1249
- width: 100%;
1250
- top: 44%;
1251
- }
1252
-
1253
- .rte-source-editor-spinner {
1254
- width: 32px;
1255
- height: 32px;
1256
- border: 3px solid #e1e5e9;
1257
- border-top: 3px solid #007acc;
1258
- border-radius: 50%;
1259
- animation: spin 1s linear infinite;
1260
- margin-bottom: 16px;
1261
- }
1262
-
1263
- @keyframes spin {
1264
- 0% { transform: rotate(0deg); }
1265
- 100% { transform: rotate(360deg); }
1266
- }
1267
-
1268
- .rte-source-editor-error {
1269
- background: #fee;
1270
- color: #c53030;
1271
- padding: 12px 16px;
1272
- border-left: 4px solid #c53030;
1273
- margin: 16px;
1274
- border-radius: 4px;
1275
- font-size: 14px;
1276
- }
1277
-
1278
- .rte-source-editor-content {
1279
- flex: 1;
1280
- display: flex;
1281
- flex-direction: column;
1282
- overflow: hidden;
1283
- }
1284
-
1285
- .rte-source-editor-warning {
1286
- background: #fefcbf;
1287
- color: #744210;
1288
- padding: 8px 16px;
1289
- font-size: 12px;
1290
- font-weight: 500;
1291
- border-bottom: 1px solid #f6e05e;
1292
- }
1293
-
1294
- .rte-source-editor-codemirror {
1295
- flex: 1;
1296
- overflow: auto;
1297
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
1298
- font-size: 14px;
1299
- line-height: 1.5;
1300
- }
1301
-
1302
- .rte-source-editor-codemirror .cm-editor {
1303
- height: 100%;
1304
- }
1305
-
1306
- .rte-source-editor-codemirror .cm-focused {
1307
- outline: none;
1308
- }
1309
-
1310
- .rte-source-editor-footer {
1311
- display: flex;
1312
- align-items: center;
1313
- justify-content: space-between;
1314
- padding: 16px 20px;
1315
- border-top: 1px solid #e1e5e9;
1316
- background: #f8f9fa;
1317
- border-radius: 0 0 8px 8px;
1318
- }
1319
-
1320
- .rte-source-editor-overlay.fullscreen .rte-source-editor-footer {
1321
- border-radius: 0;
1322
- }
1323
-
1324
- .rte-source-editor-footer-info {
1325
- font-size: 12px;
1326
- color: #666;
1327
- }
1328
-
1329
- .unsaved-changes {
1330
- color: #d69e2e;
1331
- font-weight: 500;
1332
- }
1333
-
1334
- .rte-source-editor-footer-actions {
1335
- display: flex;
1336
- gap: 12px;
1337
- }
1338
-
1339
- .rte-source-editor-btn {
1340
- padding: 8px 16px;
1341
- border-radius: 4px;
1342
- font-size: 14px;
1343
- font-weight: 500;
1344
- cursor: pointer;
1345
- border: 1px solid transparent;
1346
- transition: all 0.2s ease;
1347
- }
1348
-
1349
- .rte-source-editor-btn:disabled {
1350
- opacity: 0.6;
1351
- cursor: not-allowed;
1352
- }
1353
-
1354
- .rte-source-editor-btn-cancel {
1355
- background: white;
1356
- border-color: #d1d5db;
1357
- color: #374151;
1358
- }
1359
-
1360
- .rte-source-editor-btn-cancel:hover:not(:disabled) {
1361
- background: #f9fafb;
1362
- border-color: #9ca3af;
1363
- }
1364
-
1365
- .rte-source-editor-btn-save {
1366
- background: #007acc;
1367
- color: white;
1368
- }
1369
-
1370
- .rte-source-editor-btn-save:hover:not(:disabled) {
1371
- background: #0056b3;
1372
- }
1373
-
1374
- /* Dark theme support */
1375
- @media (prefers-color-scheme: dark) {
1376
- .rte-source-editor-modal {
1377
- background: #1e1e1e;
1378
- color: #f8f9fa;
1379
- }
1380
-
1381
- .rte-source-editor-header {
1382
- background: #2d2d2d;
1383
- border-color: #404040;
1384
- }
1385
-
1386
- .rte-source-editor-header h2 {
1387
- color: #f8f9fa;
1388
- }
1389
-
1390
- .rte-source-editor-fullscreen-btn,
1391
- .rte-source-editor-close-btn {
1392
- color: #ccc;
1393
- }
1394
-
1395
- .rte-source-editor-fullscreen-btn:hover,
1396
- .rte-source-editor-close-btn:hover {
1397
- background: #404040;
1398
- color: #f8f9fa;
1399
- }
1400
-
1401
- .rte-source-editor-error {
1402
- background: #2d1b1b;
1403
- color: #fca5a5;
1404
- border-color: #dc2626;
1405
- }
1406
-
1407
- .rte-source-editor-warning {
1408
- background: #2d2a1b;
1409
- color: #fcd34d;
1410
- border-color: #d97706;
1411
- }
1412
-
1413
- .rte-source-editor-footer {
1414
- background: #2d2d2d;
1415
- border-color: #404040;
1416
- }
1417
-
1418
- .rte-source-editor-footer-info {
1419
- color: #ccc;
1420
- }
1421
-
1422
- .rte-source-editor-btn-cancel {
1423
- background: #374151;
1424
- border-color: #4b5563;
1425
- color: #f9fafb;
1426
- }
1427
-
1428
- .rte-source-editor-btn-cancel:hover:not(:disabled) {
1429
- background: #4b5563;
1430
- border-color: #6b7280;
1431
- }
1432
- }
1433
-
1434
- /* Responsive design */
1435
- @media (max-width: 768px) {
1436
- .rte-source-editor-overlay {
1437
- padding: 10px;
1438
- }
1439
-
1440
- .rte-source-editor-modal {
1441
- max-height: 95vh;
1442
- }
1443
-
1444
- .rte-source-editor-header {
1445
- padding: 12px 16px;
1446
- }
1447
-
1448
- .rte-source-editor-footer {
1449
- padding: 12px 16px;
1450
- flex-direction: column;
1451
- gap: 12px;
1452
- align-items: stretch;
1453
- }
1454
-
1455
- .rte-source-editor-footer-actions {
1456
- justify-content: stretch;
1457
- }
1458
-
1459
- .rte-source-editor-btn {
1460
- flex: 1;
1461
- text-align: center;
1462
- }
1463
- }`, X = () => ({
1464
- name: "code",
1465
- // Toolbar button configuration
1466
- toolbar: [
1467
- {
1468
- label: "Source",
1469
- command: "toggleSourceView",
1470
- type: "button",
1471
- icon: "<>",
1472
- shortcut: "Mod-Shift-S"
1473
- }
1474
- ],
1475
- // Native command implementations
1476
- commands: {
1477
- /**
1478
- * Toggle HTML source view
1479
- * Opens a dialog to edit raw HTML
1480
- */
1481
- toggleSourceView: () => {
1482
- const e = (() => {
1483
- var l, s, d;
1484
- const i = window.getSelection();
1485
- if (i && i.anchorNode) {
1486
- let a = i.anchorNode instanceof HTMLElement ? i.anchorNode : i.anchorNode.parentElement;
1487
- for (; a; ) {
1488
- if ((l = a.classList) != null && l.contains("rte-content"))
1489
- return a;
1490
- a = a.parentElement;
1491
- }
1492
- }
1493
- if (document.activeElement) {
1494
- let a = document.activeElement;
1495
- if ((s = a.classList) != null && s.contains("rte-content"))
1496
- return a;
1497
- for (; a && a !== document.body; ) {
1498
- if ((d = a.classList) != null && d.contains("rte-content"))
1499
- return a;
1500
- const c = a.querySelector(".rte-content");
1501
- if (c) return c;
1502
- a = a.parentElement;
1503
- }
1504
- }
1505
- const o = document.querySelector("[data-editora-editor]");
1506
- if (o) {
1507
- const a = o.querySelector(".rte-content");
1508
- if (a) return a;
1509
- }
1510
- return document.querySelector(".rte-content");
1511
- })();
1512
- if (!e)
1513
- return console.error("[CodePlugin] Editor content area not found"), alert("Editor content area not found. Please click inside the editor first."), !1;
1514
- const t = e.innerHTML, n = (i) => {
1515
- let o = "", l = 0;
1516
- const s = 2, d = i.split(/(<\/?[a-zA-Z][^>]*>)/);
1517
- for (const a of d)
1518
- a.trim() && (a.match(/^<\/[a-zA-Z]/) ? (l = Math.max(0, l - 1), o += `
1519
- ` + " ".repeat(l * s) + a) : a.match(/^<[a-zA-Z]/) && !a.match(/\/>$/) ? (o += `
1520
- ` + " ".repeat(l * s) + a, l++) : a.match(/^<[a-zA-Z].*\/>$/) ? o += `
1521
- ` + " ".repeat(l * s) + a : o += a.trim());
1522
- return o.trim();
1523
- };
1524
- return (() => {
1525
- var E, L, M, T, S, N;
1526
- let i = null, o = "dark", l = !1, s = !1, d = !1;
1527
- const a = t, c = document.createElement("div");
1528
- c.className = "rte-source-editor-overlay";
1529
- const u = document.createElement("div");
1530
- u.className = "rte-source-editor-modal", u.setAttribute("role", "dialog"), u.setAttribute("aria-modal", "true"), u.setAttribute("aria-labelledby", "source-editor-title");
1531
- const g = document.createElement("div");
1532
- g.className = "rte-source-editor-header", g.innerHTML = `
1533
- <h2 id="source-editor-title">Source Editor</h2>
1534
- <div class="rte-source-editor-header-toolbar">
1535
- <button class="rte-source-editor-toolbar-btn theme-toggle-btn" title="Switch theme">
1536
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1537
- <circle cx="12" cy="12" r="5"/>
1538
- <line x1="12" y1="1" x2="12" y2="3"/>
1539
- <line x1="12" y1="21" x2="12" y2="23"/>
1540
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
1541
- <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
1542
- <line x1="1" y1="12" x2="3" y2="12"/>
1543
- <line x1="21" y1="12" x2="23" y2="12"/>
1544
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
1545
- <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
1546
- </svg>
1547
- </button>
1548
- <button class="rte-source-editor-toolbar-btn readonly-toggle-btn" title="Toggle read-only">
1549
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1550
- <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
1551
- <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
1552
- </svg>
1553
- </button>
1554
- </div>
1555
- <div class="rte-source-editor-header-actions">
1556
- <button class="rte-source-editor-fullscreen-btn" title="Toggle fullscreen">
1557
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1558
- <path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/>
1559
- </svg>
1560
- </button>
1561
- <button class="rte-source-editor-close-btn" aria-label="Close source editor">
1562
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1563
- <line x1="18" y1="6" x2="6" y2="18"/>
1564
- <line x1="6" y1="6" x2="18" y2="18"/>
1565
- </svg>
1566
- </button>
1567
- </div>
1568
- `;
1569
- const f = document.createElement("div");
1570
- f.className = "rte-source-editor-body";
1571
- const m = document.createElement("div");
1572
- m.className = "rte-source-editor-content";
1573
- const w = document.createElement("div");
1574
- w.className = "rte-source-editor-warning", w.textContent = "⚠️ Advanced users only. Invalid HTML may break the editor.";
1575
- const x = document.createElement("div");
1576
- x.className = "rte-source-editor-light-editor", x.style.height = "400px", m.appendChild(w), m.appendChild(x), f.appendChild(m);
1577
- const y = document.createElement("div");
1578
- if (y.className = "rte-source-editor-footer", y.innerHTML = `
1579
- <div class="rte-source-editor-footer-info">
1580
- <span class="unsaved-changes" style="display: none;">• Unsaved changes</span>
1581
- </div>
1582
- <div class="rte-source-editor-footer-actions">
1583
- <button class="rte-source-editor-btn rte-source-editor-btn-cancel">Cancel</button>
1584
- <button class="rte-source-editor-btn rte-source-editor-btn-save">Save</button>
1585
- </div>
1586
- `, u.appendChild(g), u.appendChild(f), u.appendChild(y), c.appendChild(u), !document.getElementById("rte-source-editor-styles")) {
1587
- const h = document.createElement("style");
1588
- h.id = "rte-source-editor-styles", h.textContent = W, document.head.appendChild(h);
1589
- }
1590
- document.body.appendChild(c);
1591
- try {
1592
- i = j(x, {
1593
- value: n(t),
1594
- theme: "dark",
1595
- readOnly: !1,
1596
- extensions: [
1597
- new A(),
1598
- new V(),
1599
- new F(),
1600
- new D(),
1601
- new q(),
1602
- new $(),
1603
- new _()
1604
- ]
1605
- }), i.on("change", () => {
1606
- d = ((i == null ? void 0 : i.getValue()) || "") !== n(a);
1607
- const b = y.querySelector(".unsaved-changes");
1608
- b && (b.style.display = d ? "inline" : "none");
1609
- }), setTimeout(() => i == null ? void 0 : i.focus(), 100);
1610
- } catch (h) {
1611
- console.error("Failed to initialize code editor:", h);
1612
- }
1613
- const R = () => {
1614
- o = o === "dark" ? "light" : "dark", i == null || i.setTheme(o);
1615
- const h = g.querySelector(".theme-toggle-btn");
1616
- h && o === "light" && (h.innerHTML = `
1617
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1618
- <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
1619
- </svg>
1620
- `);
1621
- }, I = () => {
1622
- l = !l, i == null || i.setReadOnly(l);
1623
- const h = g.querySelector(".readonly-toggle-btn");
1624
- h && (l ? (h.classList.add("active"), h.innerHTML = `
1625
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1626
- <rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
1627
- <circle cx="12" cy="16" r="1"/>
1628
- <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
1629
- </svg>
1630
- `) : (h.classList.remove("active"), h.innerHTML = `
1631
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1632
- <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
1633
- <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
1634
- </svg>
1635
- `));
1636
- }, B = () => {
1637
- s = !s, s ? (c.classList.add("fullscreen"), x.style.height = "calc(100vh - 200px)") : (c.classList.remove("fullscreen"), x.style.height = "400px");
1638
- const h = g.querySelector(".rte-source-editor-fullscreen-btn");
1639
- h && (h.innerHTML = s ? `
1640
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1641
- <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"/>
1642
- </svg>
1643
- ` : `
1644
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1645
- <path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/>
1646
- </svg>
1647
- `);
1648
- }, v = () => {
1649
- i && (i.destroy(), i = null), document.body.removeChild(c);
1650
- }, H = () => {
1651
- d && !confirm("You have unsaved changes. Are you sure you want to cancel?") || v();
1652
- }, O = () => {
1653
- try {
1654
- const h = (i == null ? void 0 : i.getValue()) || "", b = document.createElement("div");
1655
- b.innerHTML = h, b.querySelectorAll('script, iframe[src^="javascript:"], object, embed').forEach((K) => K.remove()), e.innerHTML = b.innerHTML, d = !1, v();
1656
- } catch (h) {
1657
- alert("Failed to update HTML. Please check your syntax."), console.error("HTML update error:", h);
1658
- }
1659
- };
1660
- (E = g.querySelector(".theme-toggle-btn")) == null || E.addEventListener("click", R), (L = g.querySelector(".readonly-toggle-btn")) == null || L.addEventListener("click", I), (M = g.querySelector(".rte-source-editor-fullscreen-btn")) == null || M.addEventListener("click", B), (T = g.querySelector(".rte-source-editor-close-btn")) == null || T.addEventListener("click", v), (S = y.querySelector(".rte-source-editor-btn-cancel")) == null || S.addEventListener("click", H), (N = y.querySelector(".rte-source-editor-btn-save")) == null || N.addEventListener("click", O), c.addEventListener("click", (h) => {
1661
- h.target === c && v();
1662
- });
1663
- const C = (h) => {
1664
- h.key === "Escape" && (v(), document.removeEventListener("keydown", C));
1665
- };
1666
- document.addEventListener("keydown", C);
1667
- })(), !0;
1668
- }
1669
- },
1670
- // Keyboard shortcuts
1671
- keymap: {
1672
- "Mod-Shift-s": "toggleSourceView",
1673
- "Mod-Shift-S": "toggleSourceView"
1674
- }
1675
- });
1676
- export {
1677
- X as CodePlugin
1678
- };
1679
- //# sourceMappingURL=CodePlugin.native-DD9xFIid.mjs.map