@kerebron/extension-codejar 0.4.25 → 0.4.27
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.
- package/package.json +8 -7
- package/assets/codejar-linenumbers.css +0 -17
- package/assets/codejar.css +0 -135
- package/esm/CodeJar.d.ts +0 -51
- package/esm/CodeJar.d.ts.map +0 -1
- package/esm/CodeJar.js +0 -548
- package/esm/Decorator.d.ts +0 -11
- package/esm/Decorator.d.ts.map +0 -1
- package/esm/Decorator.js +0 -45
- package/esm/ExtensionCodeJar.d.ts +0 -15
- package/esm/ExtensionCodeJar.d.ts.map +0 -1
- package/esm/ExtensionCodeJar.js +0 -61
- package/esm/NodeCodeJar.d.ts +0 -18
- package/esm/NodeCodeJar.d.ts.map +0 -1
- package/esm/NodeCodeJar.js +0 -69
- package/esm/TreeSitterHighlighter.d.ts +0 -11
- package/esm/TreeSitterHighlighter.d.ts.map +0 -1
- package/esm/TreeSitterHighlighter.js +0 -62
- package/esm/_dnt.shims.d.ts +0 -2
- package/esm/_dnt.shims.d.ts.map +0 -1
- package/esm/_dnt.shims.js +0 -57
- package/esm/codeJarBlockNodeView.d.ts +0 -6
- package/esm/codeJarBlockNodeView.d.ts.map +0 -1
- package/esm/codeJarBlockNodeView.js +0 -253
- package/esm/codeJarLineNumbers.d.ts +0 -13
- package/esm/codeJarLineNumbers.d.ts.map +0 -1
- package/esm/codeJarLineNumbers.js +0 -85
- package/esm/mod.d.ts +0 -2
- package/esm/mod.d.ts.map +0 -1
- package/esm/mod.js +0 -1
- package/esm/package.json +0 -3
- package/esm/utils.d.ts +0 -13
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -48
package/esm/CodeJar.js
DELETED
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
import * as dntShim from "./_dnt.shims.js";
|
|
2
|
-
const globalWindow = dntShim.dntGlobalThis;
|
|
3
|
-
function visit(editor, visitor) {
|
|
4
|
-
const queue = [];
|
|
5
|
-
if (editor.firstChild)
|
|
6
|
-
queue.push(editor.firstChild);
|
|
7
|
-
let el = queue.pop();
|
|
8
|
-
while (el) {
|
|
9
|
-
if (visitor(el) === 'stop')
|
|
10
|
-
break;
|
|
11
|
-
if (el.nextSibling)
|
|
12
|
-
queue.push(el.nextSibling);
|
|
13
|
-
if (el.firstChild)
|
|
14
|
-
queue.push(el.firstChild);
|
|
15
|
-
el = queue.pop();
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function isCtrl(event) {
|
|
19
|
-
return event.metaKey || event.ctrlKey;
|
|
20
|
-
}
|
|
21
|
-
function isUndo(event) {
|
|
22
|
-
return isCtrl(event) && !event.shiftKey && getKeyCode(event) === 'Z';
|
|
23
|
-
}
|
|
24
|
-
function isRedo(event) {
|
|
25
|
-
return isCtrl(event) && event.shiftKey && getKeyCode(event) === 'Z';
|
|
26
|
-
}
|
|
27
|
-
function isCopy(event) {
|
|
28
|
-
return isCtrl(event) && getKeyCode(event) === 'C';
|
|
29
|
-
}
|
|
30
|
-
function getKeyCode(event) {
|
|
31
|
-
let key = event.key || event.keyCode || event.which;
|
|
32
|
-
if (!key)
|
|
33
|
-
return undefined;
|
|
34
|
-
return (typeof key === 'string' ? key : String.fromCharCode(key))
|
|
35
|
-
.toUpperCase();
|
|
36
|
-
}
|
|
37
|
-
function insert(text) {
|
|
38
|
-
text = text
|
|
39
|
-
.replace(/&/g, '&')
|
|
40
|
-
.replace(/</g, '<')
|
|
41
|
-
.replace(/>/g, '>')
|
|
42
|
-
.replace(/"/g, '"')
|
|
43
|
-
.replace(/'/g, ''');
|
|
44
|
-
document.execCommand('insertHTML', false, text);
|
|
45
|
-
}
|
|
46
|
-
function debounce(cb, wait) {
|
|
47
|
-
let timeout = 0;
|
|
48
|
-
return (...args) => {
|
|
49
|
-
clearTimeout(timeout);
|
|
50
|
-
timeout = globalThis.setTimeout(() => cb(...args), wait);
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function findPadding(text) {
|
|
54
|
-
// Find beginning of previous line.
|
|
55
|
-
let i = text.length - 1;
|
|
56
|
-
while (i >= 0 && text[i] !== '\n')
|
|
57
|
-
i--;
|
|
58
|
-
i++;
|
|
59
|
-
// Find padding of the line.
|
|
60
|
-
let j = i;
|
|
61
|
-
while (j < text.length && /[ \t]/.test(text[j]))
|
|
62
|
-
j++;
|
|
63
|
-
return [text.substring(i, j) || '', i, j];
|
|
64
|
-
}
|
|
65
|
-
export class CodeJar extends EventTarget {
|
|
66
|
-
editor;
|
|
67
|
-
highlight;
|
|
68
|
-
options;
|
|
69
|
-
listeners = [];
|
|
70
|
-
history = [];
|
|
71
|
-
at = -1;
|
|
72
|
-
onUpdateCbk = () => void 0;
|
|
73
|
-
focus = false;
|
|
74
|
-
prev; // code content prior keydown event
|
|
75
|
-
constructor(editor, highlight, opt = {}) {
|
|
76
|
-
super();
|
|
77
|
-
this.editor = editor;
|
|
78
|
-
this.highlight = highlight;
|
|
79
|
-
this.options = {
|
|
80
|
-
tab: '\t',
|
|
81
|
-
indentOn: /[({\[]$/,
|
|
82
|
-
moveToNewLine: /^[)}\]]/,
|
|
83
|
-
spellcheck: false,
|
|
84
|
-
catchTab: true,
|
|
85
|
-
preserveIdent: true,
|
|
86
|
-
addClosing: true,
|
|
87
|
-
history: true,
|
|
88
|
-
window: globalWindow,
|
|
89
|
-
autoclose: {
|
|
90
|
-
open: '',
|
|
91
|
-
close: '',
|
|
92
|
-
},
|
|
93
|
-
...opt,
|
|
94
|
-
};
|
|
95
|
-
const window = this.options.window;
|
|
96
|
-
const document = window.document;
|
|
97
|
-
editor.style.outline = 'none';
|
|
98
|
-
editor.style.overflowWrap = 'break-word';
|
|
99
|
-
editor.style.overflowY = 'auto';
|
|
100
|
-
editor.style.whiteSpace = 'pre-wrap';
|
|
101
|
-
const matchFirefoxVersion = window.navigator.userAgent.match(/Firefox\/([0-9]+)\./);
|
|
102
|
-
const firefoxVersion = matchFirefoxVersion
|
|
103
|
-
? parseInt(matchFirefoxVersion[1])
|
|
104
|
-
: 0;
|
|
105
|
-
let isLegacy = false; // true if plaintext-only is not supported
|
|
106
|
-
if (editor.contentEditable !== 'plaintext-only' || firefoxVersion >= 136) {
|
|
107
|
-
isLegacy = true;
|
|
108
|
-
}
|
|
109
|
-
if (isLegacy)
|
|
110
|
-
editor.setAttribute('contenteditable', 'true');
|
|
111
|
-
if (!opt.readOnly) {
|
|
112
|
-
editor.setAttribute('contenteditable', 'plaintext-only');
|
|
113
|
-
editor.setAttribute('spellcheck', this.options.spellcheck ? 'true' : 'false');
|
|
114
|
-
}
|
|
115
|
-
const debounceHighlight = debounce(() => {
|
|
116
|
-
const pos = this.save();
|
|
117
|
-
this.doHighlight(editor, pos);
|
|
118
|
-
this.restore(pos);
|
|
119
|
-
}, 30);
|
|
120
|
-
let recording = false;
|
|
121
|
-
const shouldRecord = (event) => {
|
|
122
|
-
return !isUndo(event) && !isRedo(event) &&
|
|
123
|
-
event.key !== 'Meta' &&
|
|
124
|
-
event.key !== 'Control' &&
|
|
125
|
-
event.key !== 'Alt' &&
|
|
126
|
-
!event.key.startsWith('Arrow');
|
|
127
|
-
};
|
|
128
|
-
const debounceRecordHistory = debounce((event) => {
|
|
129
|
-
if (shouldRecord(event)) {
|
|
130
|
-
this.recordHistory();
|
|
131
|
-
recording = false;
|
|
132
|
-
}
|
|
133
|
-
}, 300);
|
|
134
|
-
const on = (type, fn) => {
|
|
135
|
-
this.listeners.push([type, fn]);
|
|
136
|
-
this.editor.addEventListener(type, fn);
|
|
137
|
-
};
|
|
138
|
-
on('keydown', (event) => {
|
|
139
|
-
if (event.defaultPrevented)
|
|
140
|
-
return;
|
|
141
|
-
this.prev = this.toString();
|
|
142
|
-
if (this.options.preserveIdent)
|
|
143
|
-
handleNewLine(event);
|
|
144
|
-
else
|
|
145
|
-
legacyNewLineFix(event);
|
|
146
|
-
if (this.options.catchTab)
|
|
147
|
-
handleTabCharacters(event);
|
|
148
|
-
if (this.options.addClosing)
|
|
149
|
-
handleSelfClosingCharacters(event);
|
|
150
|
-
if (this.options.history) {
|
|
151
|
-
handleUndoRedo(event);
|
|
152
|
-
if (shouldRecord(event) && !recording) {
|
|
153
|
-
this.recordHistory();
|
|
154
|
-
recording = true;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (isLegacy && !isCopy(event))
|
|
158
|
-
this.restore(this.save());
|
|
159
|
-
});
|
|
160
|
-
on('keyup', (event) => {
|
|
161
|
-
if (event.defaultPrevented)
|
|
162
|
-
return;
|
|
163
|
-
if (event.isComposing)
|
|
164
|
-
return;
|
|
165
|
-
if (this.prev !== this.toString())
|
|
166
|
-
debounceHighlight();
|
|
167
|
-
debounceRecordHistory(event);
|
|
168
|
-
this.onUpdateCbk(this.toString());
|
|
169
|
-
});
|
|
170
|
-
on('focus', (_event) => {
|
|
171
|
-
this.focus = true;
|
|
172
|
-
});
|
|
173
|
-
on('blur', (_event) => {
|
|
174
|
-
this.focus = false;
|
|
175
|
-
});
|
|
176
|
-
on('paste', (event) => {
|
|
177
|
-
this.recordHistory();
|
|
178
|
-
handlePaste(event);
|
|
179
|
-
this.recordHistory();
|
|
180
|
-
this.onUpdateCbk(this.toString());
|
|
181
|
-
});
|
|
182
|
-
on('cut', (event) => {
|
|
183
|
-
this.recordHistory();
|
|
184
|
-
handleCut(event);
|
|
185
|
-
this.recordHistory();
|
|
186
|
-
this.onUpdateCbk(this.toString());
|
|
187
|
-
});
|
|
188
|
-
const beforeCursor = () => {
|
|
189
|
-
const s = this.getSelection();
|
|
190
|
-
const r0 = s.getRangeAt(0);
|
|
191
|
-
const r = document.createRange();
|
|
192
|
-
r.selectNodeContents(editor);
|
|
193
|
-
r.setEnd(r0.startContainer, r0.startOffset);
|
|
194
|
-
return r.toString();
|
|
195
|
-
};
|
|
196
|
-
const afterCursor = () => {
|
|
197
|
-
const s = this.getSelection();
|
|
198
|
-
const r0 = s.getRangeAt(0);
|
|
199
|
-
const r = document.createRange();
|
|
200
|
-
r.selectNodeContents(editor);
|
|
201
|
-
r.setStart(r0.endContainer, r0.endOffset);
|
|
202
|
-
return r.toString();
|
|
203
|
-
};
|
|
204
|
-
const handleNewLine = (event) => {
|
|
205
|
-
if (event.key === 'Enter') {
|
|
206
|
-
const before = beforeCursor();
|
|
207
|
-
const after = afterCursor();
|
|
208
|
-
let [padding] = findPadding(before);
|
|
209
|
-
let newLinePadding = padding;
|
|
210
|
-
// If last symbol is "{" ident new line
|
|
211
|
-
if (this.options.indentOn.test(before)) {
|
|
212
|
-
newLinePadding += this.options.tab;
|
|
213
|
-
}
|
|
214
|
-
// Preserve padding
|
|
215
|
-
if (newLinePadding.length > 0) {
|
|
216
|
-
event.preventDefault();
|
|
217
|
-
event.stopPropagation();
|
|
218
|
-
insert('\n' + newLinePadding);
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
legacyNewLineFix(event);
|
|
222
|
-
}
|
|
223
|
-
// Place adjacent "}" on next line
|
|
224
|
-
if (newLinePadding !== padding && this.options.moveToNewLine.test(after)) {
|
|
225
|
-
const pos = this.save();
|
|
226
|
-
insert('\n' + padding);
|
|
227
|
-
this.restore(pos);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
const legacyNewLineFix = (event) => {
|
|
232
|
-
// Firefox does not support plaintext-only mode
|
|
233
|
-
// and puts <div><br></div> on Enter. Let's help.
|
|
234
|
-
if (isLegacy && event.key === 'Enter') {
|
|
235
|
-
event.preventDefault();
|
|
236
|
-
event.stopPropagation();
|
|
237
|
-
if (afterCursor() == '') {
|
|
238
|
-
insert('\n ');
|
|
239
|
-
const pos = this.save();
|
|
240
|
-
pos.start = --pos.end;
|
|
241
|
-
this.restore(pos);
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
insert('\n');
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
const handleSelfClosingCharacters = (event) => {
|
|
249
|
-
const open = this.options.autoclose.open;
|
|
250
|
-
const close = this.options.autoclose.close;
|
|
251
|
-
if (open.includes(event.key)) {
|
|
252
|
-
event.preventDefault();
|
|
253
|
-
const pos = this.save();
|
|
254
|
-
const wrapText = pos.start == pos.end
|
|
255
|
-
? ''
|
|
256
|
-
: this.getSelection().toString();
|
|
257
|
-
const text = event.key + wrapText +
|
|
258
|
-
(close[open.indexOf(event.key)] ?? '');
|
|
259
|
-
insert(text);
|
|
260
|
-
pos.start++;
|
|
261
|
-
pos.end++;
|
|
262
|
-
this.restore(pos);
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
const handleTabCharacters = (event) => {
|
|
266
|
-
if (event.key === 'Tab') {
|
|
267
|
-
event.preventDefault();
|
|
268
|
-
if (event.shiftKey) {
|
|
269
|
-
const before = beforeCursor();
|
|
270
|
-
let [padding, start] = findPadding(before);
|
|
271
|
-
if (padding.length > 0) {
|
|
272
|
-
const pos = this.save();
|
|
273
|
-
// Remove full length tab or just remaining padding
|
|
274
|
-
const len = Math.min(this.options.tab.length, padding.length);
|
|
275
|
-
this.restore({ start, end: start + len });
|
|
276
|
-
document.execCommand('delete');
|
|
277
|
-
pos.start -= len;
|
|
278
|
-
pos.end -= len;
|
|
279
|
-
this.restore(pos);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
insert(this.options.tab);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
const handleUndoRedo = (event) => {
|
|
288
|
-
if (isUndo(event)) {
|
|
289
|
-
event.preventDefault();
|
|
290
|
-
this.at--;
|
|
291
|
-
const record = this.history[this.at];
|
|
292
|
-
if (record) {
|
|
293
|
-
editor.innerHTML = record.html;
|
|
294
|
-
this.restore(record.pos);
|
|
295
|
-
}
|
|
296
|
-
if (this.at < 0)
|
|
297
|
-
this.at = 0;
|
|
298
|
-
}
|
|
299
|
-
if (isRedo(event)) {
|
|
300
|
-
event.preventDefault();
|
|
301
|
-
this.at++;
|
|
302
|
-
const record = this.history[this.at];
|
|
303
|
-
if (record) {
|
|
304
|
-
editor.innerHTML = record.html;
|
|
305
|
-
this.restore(record.pos);
|
|
306
|
-
}
|
|
307
|
-
if (this.at >= history.length)
|
|
308
|
-
this.at--;
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
const handlePaste = (event) => {
|
|
312
|
-
if (event.defaultPrevented)
|
|
313
|
-
return;
|
|
314
|
-
event.preventDefault();
|
|
315
|
-
const originalEvent = event.originalEvent ?? event;
|
|
316
|
-
const text = originalEvent.clipboardData.getData('text/plain').replace(/\r\n?/g, '\n');
|
|
317
|
-
const pos = this.save();
|
|
318
|
-
insert(text);
|
|
319
|
-
this.doHighlight(editor);
|
|
320
|
-
this.restore({
|
|
321
|
-
start: Math.min(pos.start, pos.end) + text.length,
|
|
322
|
-
end: Math.min(pos.start, pos.end) + text.length,
|
|
323
|
-
dir: '<-',
|
|
324
|
-
});
|
|
325
|
-
};
|
|
326
|
-
const handleCut = (event) => {
|
|
327
|
-
const pos = this.save();
|
|
328
|
-
const selection = this.getSelection();
|
|
329
|
-
const originalEvent = event.originalEvent ?? event;
|
|
330
|
-
originalEvent.clipboardData.setData('text/plain', selection.toString());
|
|
331
|
-
document.execCommand('delete');
|
|
332
|
-
this.doHighlight(editor);
|
|
333
|
-
this.restore({
|
|
334
|
-
start: Math.min(pos.start, pos.end),
|
|
335
|
-
end: Math.min(pos.start, pos.end),
|
|
336
|
-
dir: '<-',
|
|
337
|
-
});
|
|
338
|
-
event.preventDefault();
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
getSelection() {
|
|
342
|
-
return this.editor.getRootNode().getSelection();
|
|
343
|
-
}
|
|
344
|
-
doHighlight(editor, pos) {
|
|
345
|
-
this.highlight(editor, pos);
|
|
346
|
-
}
|
|
347
|
-
uneditable(node) {
|
|
348
|
-
while (node && node !== this.editor) {
|
|
349
|
-
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
350
|
-
const el = node;
|
|
351
|
-
if (el.getAttribute('contenteditable') == 'false') {
|
|
352
|
-
return el;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
node = node.parentNode;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
toString() {
|
|
359
|
-
return this.editor.textContent || '';
|
|
360
|
-
}
|
|
361
|
-
updateOptions(newOptions) {
|
|
362
|
-
Object.assign(this.options, newOptions);
|
|
363
|
-
}
|
|
364
|
-
updateCode(code, callOnUpdate = true) {
|
|
365
|
-
this.editor.textContent = code;
|
|
366
|
-
this.doHighlight(this.editor);
|
|
367
|
-
callOnUpdate && this.onUpdateCbk(code);
|
|
368
|
-
}
|
|
369
|
-
onUpdate(callback) {
|
|
370
|
-
this.onUpdateCbk = callback;
|
|
371
|
-
}
|
|
372
|
-
save() {
|
|
373
|
-
const s = this.getSelection();
|
|
374
|
-
const pos = { start: 0, end: 0, dir: undefined };
|
|
375
|
-
if (!s) {
|
|
376
|
-
return pos;
|
|
377
|
-
}
|
|
378
|
-
let { anchorNode, anchorOffset, focusNode, focusOffset } = s;
|
|
379
|
-
if (!anchorNode) {
|
|
380
|
-
console.warn('No anchorNode');
|
|
381
|
-
return undefined;
|
|
382
|
-
}
|
|
383
|
-
if (!focusNode) {
|
|
384
|
-
console.warn('No focusNode');
|
|
385
|
-
return undefined;
|
|
386
|
-
}
|
|
387
|
-
// If the anchor and focus are the editor element, return either a full
|
|
388
|
-
// highlight or a start/end cursor position depending on the selection
|
|
389
|
-
if (anchorNode === this.editor && focusNode === this.editor) {
|
|
390
|
-
pos.start = (anchorOffset > 0 && this.editor.textContent)
|
|
391
|
-
? this.editor.textContent.length
|
|
392
|
-
: 0;
|
|
393
|
-
pos.end = (focusOffset > 0 && this.editor.textContent)
|
|
394
|
-
? this.editor.textContent.length
|
|
395
|
-
: 0;
|
|
396
|
-
pos.dir = (focusOffset >= anchorOffset) ? '->' : '<-';
|
|
397
|
-
return pos;
|
|
398
|
-
}
|
|
399
|
-
// Selection anchor and focus are expected to be text nodes,
|
|
400
|
-
// so normalize them.
|
|
401
|
-
if (anchorNode.nodeType === Node.ELEMENT_NODE) {
|
|
402
|
-
const node = document.createTextNode('');
|
|
403
|
-
anchorNode.insertBefore(node, anchorNode.childNodes[anchorOffset]);
|
|
404
|
-
anchorNode = node;
|
|
405
|
-
anchorOffset = 0;
|
|
406
|
-
}
|
|
407
|
-
if (focusNode.nodeType === Node.ELEMENT_NODE) {
|
|
408
|
-
const node = document.createTextNode('');
|
|
409
|
-
focusNode.insertBefore(node, focusNode.childNodes[focusOffset]);
|
|
410
|
-
focusNode = node;
|
|
411
|
-
focusOffset = 0;
|
|
412
|
-
}
|
|
413
|
-
visit(this.editor, (el) => {
|
|
414
|
-
if (el === anchorNode && el === focusNode) {
|
|
415
|
-
pos.start += anchorOffset;
|
|
416
|
-
pos.end += focusOffset;
|
|
417
|
-
pos.dir = anchorOffset <= focusOffset ? '->' : '<-';
|
|
418
|
-
return 'stop';
|
|
419
|
-
}
|
|
420
|
-
if (el === anchorNode) {
|
|
421
|
-
pos.start += anchorOffset;
|
|
422
|
-
if (!pos.dir) {
|
|
423
|
-
pos.dir = '->';
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
return 'stop';
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
else if (el === focusNode) {
|
|
430
|
-
pos.end += focusOffset;
|
|
431
|
-
if (!pos.dir) {
|
|
432
|
-
pos.dir = '<-';
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
return 'stop';
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
if (el.nodeType === Node.TEXT_NODE) {
|
|
439
|
-
if (pos.dir != '->')
|
|
440
|
-
pos.start += el.nodeValue.length;
|
|
441
|
-
if (pos.dir != '<-')
|
|
442
|
-
pos.end += el.nodeValue.length;
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
this.editor.normalize(); // collapse empty text nodes
|
|
446
|
-
return pos;
|
|
447
|
-
}
|
|
448
|
-
restore(pos) {
|
|
449
|
-
const s = this.getSelection();
|
|
450
|
-
if (!s) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
let startNode, startOffset = 0;
|
|
454
|
-
let endNode, endOffset = 0;
|
|
455
|
-
if (!pos.dir)
|
|
456
|
-
pos.dir = '->';
|
|
457
|
-
if (pos.start < 0)
|
|
458
|
-
pos.start = 0;
|
|
459
|
-
if (pos.end < 0)
|
|
460
|
-
pos.end = 0;
|
|
461
|
-
// Flip start and end if the direction reversed
|
|
462
|
-
if (pos.dir == '<-') {
|
|
463
|
-
const { start, end } = pos;
|
|
464
|
-
pos.start = end;
|
|
465
|
-
pos.end = start;
|
|
466
|
-
}
|
|
467
|
-
let current = 0;
|
|
468
|
-
visit(this.editor, (el) => {
|
|
469
|
-
if (el.nodeType !== Node.TEXT_NODE)
|
|
470
|
-
return;
|
|
471
|
-
const len = (el.nodeValue || '').length;
|
|
472
|
-
if (current + len > pos.start) {
|
|
473
|
-
if (!startNode) {
|
|
474
|
-
startNode = el;
|
|
475
|
-
startOffset = pos.start - current;
|
|
476
|
-
}
|
|
477
|
-
if (current + len > pos.end) {
|
|
478
|
-
endNode = el;
|
|
479
|
-
endOffset = pos.end - current;
|
|
480
|
-
return 'stop';
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
current += len;
|
|
484
|
-
});
|
|
485
|
-
if (!startNode) {
|
|
486
|
-
startNode = this.editor;
|
|
487
|
-
startOffset = this.editor.childNodes.length;
|
|
488
|
-
}
|
|
489
|
-
if (!endNode) {
|
|
490
|
-
endNode = this.editor;
|
|
491
|
-
endOffset = this.editor.childNodes.length;
|
|
492
|
-
}
|
|
493
|
-
// Flip back the selection
|
|
494
|
-
if (pos.dir == '<-') {
|
|
495
|
-
[startNode, startOffset, endNode, endOffset] = [
|
|
496
|
-
endNode,
|
|
497
|
-
endOffset,
|
|
498
|
-
startNode,
|
|
499
|
-
startOffset,
|
|
500
|
-
];
|
|
501
|
-
}
|
|
502
|
-
{
|
|
503
|
-
// If nodes not editable, create a text node.
|
|
504
|
-
const startEl = this.uneditable(startNode);
|
|
505
|
-
if (startEl) {
|
|
506
|
-
const node = document.createTextNode('');
|
|
507
|
-
startEl.parentNode?.insertBefore(node, startEl);
|
|
508
|
-
startNode = node;
|
|
509
|
-
startOffset = 0;
|
|
510
|
-
}
|
|
511
|
-
const endEl = this.uneditable(endNode);
|
|
512
|
-
if (endEl) {
|
|
513
|
-
const node = document.createTextNode('');
|
|
514
|
-
endEl.parentNode?.insertBefore(node, endEl);
|
|
515
|
-
endNode = node;
|
|
516
|
-
endOffset = 0;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
s.setBaseAndExtent(startNode, startOffset, endNode, endOffset);
|
|
520
|
-
this.editor.normalize(); // collapse empty text nodes
|
|
521
|
-
}
|
|
522
|
-
recordHistory() {
|
|
523
|
-
if (!focus)
|
|
524
|
-
return;
|
|
525
|
-
const html = this.editor.innerHTML;
|
|
526
|
-
const pos = this.save();
|
|
527
|
-
const lastRecord = this.history[this.at];
|
|
528
|
-
if (lastRecord) {
|
|
529
|
-
if (lastRecord.html === html &&
|
|
530
|
-
lastRecord.pos.start === pos.start &&
|
|
531
|
-
lastRecord.pos.end === pos.end)
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
this.at++;
|
|
535
|
-
this.history[this.at] = { html, pos };
|
|
536
|
-
this.history.splice(this.at + 1);
|
|
537
|
-
const maxHistory = 300;
|
|
538
|
-
if (this.at > maxHistory) {
|
|
539
|
-
this.at = maxHistory;
|
|
540
|
-
this.history.splice(0, 1);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
destroy() {
|
|
544
|
-
for (let [type, fn] of this.listeners) {
|
|
545
|
-
this.editor.removeEventListener(type, fn);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
package/esm/Decorator.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface DecorationInline {
|
|
2
|
-
startIndex: number;
|
|
3
|
-
endIndex: number;
|
|
4
|
-
className: string;
|
|
5
|
-
title?: string;
|
|
6
|
-
}
|
|
7
|
-
export declare class Decorator {
|
|
8
|
-
decorationGroups: Record<string, DecorationInline[]>;
|
|
9
|
-
highlight(code: string): string;
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=Decorator.d.ts.map
|
package/esm/Decorator.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Decorator.d.ts","sourceRoot":"","sources":["../src/Decorator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,SAAS;IACb,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAM;IAEjE,SAAS,CAAC,IAAI,EAAE,MAAM;CAiDvB"}
|
package/esm/Decorator.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export class Decorator {
|
|
2
|
-
decorationGroups = {};
|
|
3
|
-
highlight(code) {
|
|
4
|
-
const decorations = [];
|
|
5
|
-
for (const groupName in this.decorationGroups) {
|
|
6
|
-
const group = this.decorationGroups[groupName];
|
|
7
|
-
decorations.push(...group);
|
|
8
|
-
}
|
|
9
|
-
const cutIndexes = new Set();
|
|
10
|
-
for (const d of decorations) {
|
|
11
|
-
cutIndexes.add(d.startIndex);
|
|
12
|
-
cutIndexes.add(d.endIndex);
|
|
13
|
-
}
|
|
14
|
-
cutIndexes.add(0);
|
|
15
|
-
cutIndexes.add(code.length);
|
|
16
|
-
const cutIndexesArr = Array.from(cutIndexes);
|
|
17
|
-
cutIndexesArr.sort((a, b) => a - b);
|
|
18
|
-
let html = '';
|
|
19
|
-
let lastIndex = 0;
|
|
20
|
-
for (const currentIdx of cutIndexesArr) {
|
|
21
|
-
const text = code.substring(lastIndex, currentIdx);
|
|
22
|
-
const activeDecors = decorations.filter((d) => lastIndex >= d.startIndex && currentIdx <= d.endIndex);
|
|
23
|
-
for (const decor of activeDecors) {
|
|
24
|
-
if (decor.title) {
|
|
25
|
-
html += `<span class="${decor.className}" title="${escapeHtml(decor.title || '')}">`;
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
html += `<span class="${decor.className}">`;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
html += escapeHtml(text);
|
|
32
|
-
for (const decor of activeDecors) {
|
|
33
|
-
html += '</span>';
|
|
34
|
-
}
|
|
35
|
-
lastIndex = currentIdx;
|
|
36
|
-
}
|
|
37
|
-
return html;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function escapeHtml(text) {
|
|
41
|
-
return text
|
|
42
|
-
.replace(/&/g, '&')
|
|
43
|
-
.replace(/</g, '<')
|
|
44
|
-
.replace(/>/g, '>');
|
|
45
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Schema } from 'prosemirror-model';
|
|
2
|
-
import { AnyExtensionOrReq, type Converter, type CoreEditor, Extension } from '@kerebron/editor';
|
|
3
|
-
export * from './NodeCodeJar.js';
|
|
4
|
-
export interface ExtensionCodeJarConfig {
|
|
5
|
-
readOnly?: boolean;
|
|
6
|
-
languageWhitelist?: string[];
|
|
7
|
-
}
|
|
8
|
-
export declare class ExtensionCodeJar extends Extension {
|
|
9
|
-
protected config: ExtensionCodeJarConfig;
|
|
10
|
-
name: string;
|
|
11
|
-
requires: AnyExtensionOrReq[];
|
|
12
|
-
constructor(config?: ExtensionCodeJarConfig);
|
|
13
|
-
getConverters(editor: CoreEditor, schema: Schema): Record<string, Converter>;
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=ExtensionCodeJar.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ExtensionCodeJar.d.ts","sourceRoot":"","sources":["../src/ExtensionCodeJar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,SAAS,EACV,MAAM,kBAAkB,CAAC;AAI1B,cAAc,kBAAkB,CAAC;AAEjC,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,qBAAa,gBAAiB,SAAQ,SAAS;cAId,MAAM,EAAE,sBAAsB;IAHpD,IAAI,SAAc;IAC3B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;gBAEC,MAAM,GAAE,sBAA2B;IAWzD,aAAa,CACpB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC;CA+C7B"}
|
package/esm/ExtensionCodeJar.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Extension, } from '@kerebron/editor';
|
|
2
|
-
import { createNodeFromObject } from '@kerebron/editor/utilities';
|
|
3
|
-
import { NodeCodeJar } from './NodeCodeJar.js';
|
|
4
|
-
export * from './NodeCodeJar.js';
|
|
5
|
-
export class ExtensionCodeJar extends Extension {
|
|
6
|
-
config;
|
|
7
|
-
name = 'code-jar';
|
|
8
|
-
requires;
|
|
9
|
-
constructor(config = {}) {
|
|
10
|
-
super(config);
|
|
11
|
-
this.config = config;
|
|
12
|
-
this.requires = [
|
|
13
|
-
new NodeCodeJar({
|
|
14
|
-
languageWhitelist: config.languageWhitelist,
|
|
15
|
-
// theme: config.theme,
|
|
16
|
-
}),
|
|
17
|
-
];
|
|
18
|
-
}
|
|
19
|
-
getConverters(editor, schema) {
|
|
20
|
-
return {
|
|
21
|
-
'text/code-only': {
|
|
22
|
-
fromDoc: async (document) => {
|
|
23
|
-
const retVal = [];
|
|
24
|
-
if (document.content) {
|
|
25
|
-
for (const node of document.content.toJSON()) {
|
|
26
|
-
if ('code_block' === node.type && Array.isArray(node.content)) {
|
|
27
|
-
for (const content of node.content) {
|
|
28
|
-
retVal.push(content.text);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return new TextEncoder().encode(retVal.join(''));
|
|
34
|
-
},
|
|
35
|
-
toDoc: async (buffer) => {
|
|
36
|
-
const code = new TextDecoder().decode(buffer);
|
|
37
|
-
const content = {
|
|
38
|
-
'type': 'doc_code',
|
|
39
|
-
'content': [
|
|
40
|
-
{
|
|
41
|
-
'type': 'code_block',
|
|
42
|
-
'attrs': {
|
|
43
|
-
'lang': schema.topNodeType.spec.defaultAttrs?.lang,
|
|
44
|
-
},
|
|
45
|
-
'content': [
|
|
46
|
-
{
|
|
47
|
-
'type': 'text',
|
|
48
|
-
'text': code,
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
],
|
|
53
|
-
};
|
|
54
|
-
return createNodeFromObject(content, schema, {
|
|
55
|
-
errorOnInvalidContent: false,
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
}
|