autumnnote 2.1.0 → 2.3.0
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/README.md +74 -6
- package/dist/autumnnote.cjs +27 -22
- package/dist/autumnnote.es.js +474 -591
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.min.js +27 -22
- package/dist/autumnnote.umd.js +27 -22
- package/dist/autumnnote.umd.js.map +1 -1
- package/dist/icon-data-V0Xqv-wX.js +255 -0
- package/dist/icon-data-V0Xqv-wX.js.map +1 -0
- package/package.json +12 -3
- package/types/index.d.ts +8 -0
- package/src/js/Context.js +0 -854
- package/src/js/core/detectLang.js +0 -98
- package/src/js/core/dom.js +0 -372
- package/src/js/core/env.js +0 -38
- package/src/js/core/key.js +0 -66
- package/src/js/core/lists.js +0 -121
- package/src/js/core/markdown.js +0 -695
- package/src/js/core/range.js +0 -194
- package/src/js/core/sanitise.js +0 -304
- package/src/js/editing/History.js +0 -266
- package/src/js/editing/Style.js +0 -812
- package/src/js/editing/Table.js +0 -105
- package/src/js/editing/Typing.js +0 -397
- package/src/js/index.js +0 -193
- package/src/js/index.umd.js +0 -17
- package/src/js/module/AutoSaveRestore.js +0 -125
- package/src/js/module/BaseDialog.js +0 -133
- package/src/js/module/BaseMediaTooltip.js +0 -142
- package/src/js/module/BaseResizer.js +0 -322
- package/src/js/module/BubbleToolbar.js +0 -483
- package/src/js/module/Buttons.js +0 -399
- package/src/js/module/Clipboard.js +0 -579
- package/src/js/module/CodeTooltip.js +0 -493
- package/src/js/module/Codeview.js +0 -125
- package/src/js/module/ContextMenu.js +0 -621
- package/src/js/module/Editor.js +0 -747
- package/src/js/module/EmojiDialog.js +0 -254
- package/src/js/module/FindReplace.js +0 -512
- package/src/js/module/Fullscreen.js +0 -80
- package/src/js/module/IconDialog.js +0 -618
- package/src/js/module/ImageCropOverlay.js +0 -586
- package/src/js/module/ImageDialog.js +0 -193
- package/src/js/module/ImageResizer.js +0 -42
- package/src/js/module/ImageTooltip.js +0 -285
- package/src/js/module/LinkDialog.js +0 -145
- package/src/js/module/LinkTooltip.js +0 -250
- package/src/js/module/MarkdownShortcuts.js +0 -250
- package/src/js/module/Mention.js +0 -365
- package/src/js/module/Placeholder.js +0 -51
- package/src/js/module/ShortcutsDialog.js +0 -111
- package/src/js/module/SlashMenu.js +0 -376
- package/src/js/module/Statusbar.js +0 -246
- package/src/js/module/TableTooltip.js +0 -1392
- package/src/js/module/Toolbar.js +0 -855
- package/src/js/module/VideoDialog.js +0 -193
- package/src/js/module/VideoResizer.js +0 -66
- package/src/js/module/VideoTooltip.js +0 -248
- package/src/js/module/emoji-data.js +0 -496
- package/src/js/module/table-grid.js +0 -102
- package/src/js/module/table-icons.js +0 -33
- package/src/js/renderer.js +0 -120
- package/src/js/settings.js +0 -214
- package/src/styles/_variables.scss +0 -48
- package/src/styles/autumnnote.scss +0 -2877
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* History.js - Undo / redo stack for editor content
|
|
3
|
-
* Inspired by Summernote's History module, rewritten without jQuery
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export class History {
|
|
7
|
-
/**
|
|
8
|
-
* @param {HTMLElement} editable - the contenteditable element
|
|
9
|
-
* @param {number} [limit=100] - maximum number of undo/redo states
|
|
10
|
-
* @param {number} [maxBytes=10485760] - maximum combined size (chars) of all
|
|
11
|
-
* stacked snapshots (html + tokenized image data). Oldest states are
|
|
12
|
-
* evicted first when exceeded, even if `limit` hasn't been reached —
|
|
13
|
-
* documents with many large embedded images can otherwise hold dozens of
|
|
14
|
-
* full-size copies in memory despite the step-count limit.
|
|
15
|
-
*/
|
|
16
|
-
constructor(editable, limit = 100, maxBytes = 10 * 1024 * 1024) {
|
|
17
|
-
this.editable = editable;
|
|
18
|
-
this._limit = limit;
|
|
19
|
-
this._maxBytes = maxBytes;
|
|
20
|
-
this._bytes = 0;
|
|
21
|
-
/** @type {Array<{html: string, images?: Record<string,string>, sel: {start: number, end: number}|null}>} */
|
|
22
|
-
this.stack = [];
|
|
23
|
-
this.stackOffset = -1;
|
|
24
|
-
this._savePoint();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Approximate in-memory size (chars) of one stacked snapshot: the tokenized
|
|
29
|
-
* HTML string plus every image data URL it references.
|
|
30
|
-
* @param {{html: string, images?: Record<string,string>}} entry
|
|
31
|
-
* @returns {number}
|
|
32
|
-
*/
|
|
33
|
-
_entrySize(entry) {
|
|
34
|
-
let size = entry.html.length;
|
|
35
|
-
if (entry.images) {
|
|
36
|
-
for (const key in entry.images) size += entry.images[key].length;
|
|
37
|
-
}
|
|
38
|
-
return size;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
// Private helpers
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
|
|
45
|
-
_serialize() {
|
|
46
|
-
return this.editable.innerHTML;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Serializes the current selection as character offsets from the start of
|
|
51
|
-
* the editable element, so it can be restored after innerHTML replacement.
|
|
52
|
-
* @returns {{ start: number, end: number }|null}
|
|
53
|
-
*/
|
|
54
|
-
_serializeSelection() {
|
|
55
|
-
const sel = globalThis.getSelection();
|
|
56
|
-
if (!sel || sel.rangeCount === 0) return null;
|
|
57
|
-
const range = sel.getRangeAt(0);
|
|
58
|
-
if (!this.editable.contains(range.startContainer)) return null;
|
|
59
|
-
return {
|
|
60
|
-
start: this._charOffset(range.startContainer, range.startOffset),
|
|
61
|
-
end: this._charOffset(range.endContainer, range.endOffset),
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Returns the character offset of (node, offset) from the beginning of
|
|
67
|
-
* the editable's text content.
|
|
68
|
-
* @param {Node} node
|
|
69
|
-
* @param {number} offset
|
|
70
|
-
* @returns {number}
|
|
71
|
-
*/
|
|
72
|
-
_charOffset(node, offset) {
|
|
73
|
-
let count = 0;
|
|
74
|
-
const walker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);
|
|
75
|
-
let cur;
|
|
76
|
-
while ((cur = walker.nextNode())) {
|
|
77
|
-
if (cur === node) return count + offset;
|
|
78
|
-
count += /** @type {Text} */ (cur).length;
|
|
79
|
-
}
|
|
80
|
-
return 0;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Restores a previously serialized selection inside the editable.
|
|
85
|
-
* @param {{ start: number, end: number }|null} saved
|
|
86
|
-
*/
|
|
87
|
-
_restoreSelection(saved) {
|
|
88
|
-
if (!saved) return;
|
|
89
|
-
let startNode = null, startOff = 0;
|
|
90
|
-
let endNode = null, endOff = 0;
|
|
91
|
-
let count = 0;
|
|
92
|
-
const walker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);
|
|
93
|
-
let cur;
|
|
94
|
-
while ((cur = walker.nextNode())) {
|
|
95
|
-
const len = /** @type {Text} */ (cur).length;
|
|
96
|
-
if (!startNode && count + len >= saved.start) {
|
|
97
|
-
startNode = cur;
|
|
98
|
-
startOff = saved.start - count;
|
|
99
|
-
}
|
|
100
|
-
if (!endNode && count + len >= saved.end) {
|
|
101
|
-
endNode = cur;
|
|
102
|
-
endOff = saved.end - count;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
count += len;
|
|
106
|
-
}
|
|
107
|
-
if (!startNode) {
|
|
108
|
-
// Offset exceeds content (e.g. undo to a shorter state): place at end
|
|
109
|
-
const lastWalker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);
|
|
110
|
-
let lastNode = null;
|
|
111
|
-
while ((lastNode = lastWalker.nextNode())) { startNode = lastNode; }
|
|
112
|
-
startOff = startNode ? /** @type {Text} */ (startNode).length : 0;
|
|
113
|
-
endNode = startNode;
|
|
114
|
-
endOff = startOff;
|
|
115
|
-
}
|
|
116
|
-
if (!endNode) { endNode = startNode; endOff = startOff; }
|
|
117
|
-
try {
|
|
118
|
-
const range = document.createRange();
|
|
119
|
-
range.setStart(startNode, startOff);
|
|
120
|
-
range.setEnd(endNode, endOff);
|
|
121
|
-
const sel = globalThis.getSelection();
|
|
122
|
-
sel.removeAllRanges();
|
|
123
|
-
sel.addRange(range);
|
|
124
|
-
} catch (_) {
|
|
125
|
-
void _; // detached node — fall back to placing cursor at start of editable
|
|
126
|
-
try {
|
|
127
|
-
const fb = document.createRange();
|
|
128
|
-
fb.setStart(this.editable, 0);
|
|
129
|
-
fb.collapse(true);
|
|
130
|
-
const s = globalThis.getSelection();
|
|
131
|
-
if (s) { s.removeAllRanges(); s.addRange(fb); }
|
|
132
|
-
} catch (_2) { void _2; /* fully give up */ }
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
_savePoint() {
|
|
137
|
-
// Trim future history if we're mid-stack
|
|
138
|
-
if (this.stackOffset < this.stack.length - 1) {
|
|
139
|
-
for (const entry of this.stack.slice(this.stackOffset + 1)) {
|
|
140
|
-
this._bytes -= this._entrySize(entry);
|
|
141
|
-
}
|
|
142
|
-
this.stack = this.stack.slice(0, this.stackOffset + 1);
|
|
143
|
-
}
|
|
144
|
-
const raw = this._serialize();
|
|
145
|
-
const { html, images } = this._tokenizeImages(raw);
|
|
146
|
-
const entry = { html, images, sel: this._serializeSelection() };
|
|
147
|
-
this.stack.push(entry);
|
|
148
|
-
this._bytes += this._entrySize(entry);
|
|
149
|
-
|
|
150
|
-
// Evict oldest states first, whichever budget (step count or byte size)
|
|
151
|
-
// is exceeded — always keep at least the just-pushed current state.
|
|
152
|
-
while (this.stack.length > 1 && (this.stack.length > this._limit || this._bytes > this._maxBytes)) {
|
|
153
|
-
this._bytes -= this._entrySize(this.stack.shift());
|
|
154
|
-
}
|
|
155
|
-
// The newly-pushed current state is always the final entry. Recompute the
|
|
156
|
-
// offset from the resulting stack instead of incrementing conditionally:
|
|
157
|
-
// a single oversized snapshot may evict several older entries at once.
|
|
158
|
-
this.stackOffset = this.stack.length - 1;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
_restore(point) {
|
|
162
|
-
if (!point) return;
|
|
163
|
-
this.editable.innerHTML = this._detokenizeImages(point);
|
|
164
|
-
this._restoreSelection(point.sel);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ---------------------------------------------------------------------------
|
|
168
|
-
// Base64 tokenisation — keeps snapshot strings small so that the
|
|
169
|
-
// per-keystroke `recordUndo` string comparison stays fast even when the
|
|
170
|
-
// editor contains large embedded images.
|
|
171
|
-
// ---------------------------------------------------------------------------
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Replaces every `data:…;base64,…` occurrence in `html` with a compact
|
|
175
|
-
* token `__asn_img_0__`, `__asn_img_1__`, … and returns the tokenized
|
|
176
|
-
* string together with a map from token → original data URL.
|
|
177
|
-
* @param {string} html
|
|
178
|
-
* @returns {{ html: string, images: Object<string,string> }}
|
|
179
|
-
*/
|
|
180
|
-
_tokenizeImages(html) {
|
|
181
|
-
// Fast-path: skip regex entirely when there are no data URIs (common case)
|
|
182
|
-
if (!html.includes('data:')) return { html, images: /** @type {Record<string,string>} */ ({}) };
|
|
183
|
-
const images = /** @type {Record<string,string>} */ ({});
|
|
184
|
-
let index = 0;
|
|
185
|
-
const tokenized = html.replace(/data:[^;]+;base64,[^"' >]*/g, (match) => {
|
|
186
|
-
const token = `__asn_img_${index}__`;
|
|
187
|
-
images[token] = match;
|
|
188
|
-
index++;
|
|
189
|
-
return token;
|
|
190
|
-
});
|
|
191
|
-
return { html: tokenized, images };
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Restores a snapshot by replacing tokens back with their data URLs.
|
|
196
|
-
* @param {{ html: string, images: Object<string,string> }} point
|
|
197
|
-
* @returns {string}
|
|
198
|
-
*/
|
|
199
|
-
_detokenizeImages(point) {
|
|
200
|
-
if (!point.images || Object.keys(point.images).length === 0) return point.html;
|
|
201
|
-
return point.html.replace(/__asn_img_\d+__/g, (token) => point.images[token] || token);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// ---------------------------------------------------------------------------
|
|
205
|
-
// Public API
|
|
206
|
-
// ---------------------------------------------------------------------------
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Records the current editor state as a history checkpoint.
|
|
210
|
-
*/
|
|
211
|
-
recordUndo() {
|
|
212
|
-
const current = this._serialize();
|
|
213
|
-
const { html: tokenized } = this._tokenizeImages(current);
|
|
214
|
-
const prev = this.stack[this.stackOffset];
|
|
215
|
-
if (prev?.html === tokenized) return; // No change
|
|
216
|
-
this._savePoint();
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Undo to the previous state.
|
|
221
|
-
*/
|
|
222
|
-
undo() {
|
|
223
|
-
if (this.stackOffset <= 0) return;
|
|
224
|
-
this.stackOffset--;
|
|
225
|
-
this._restore(this.stack[this.stackOffset]);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Redo to the next state.
|
|
230
|
-
*/
|
|
231
|
-
redo() {
|
|
232
|
-
if (this.stackOffset >= this.stack.length - 1) return;
|
|
233
|
-
this.stackOffset++;
|
|
234
|
-
this._restore(this.stack[this.stackOffset]);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Resets the history stack (e.g. on editor destroy or full content replace).
|
|
239
|
-
*/
|
|
240
|
-
reset() {
|
|
241
|
-
this.stack = [];
|
|
242
|
-
this.stackOffset = -1;
|
|
243
|
-
this._bytes = 0;
|
|
244
|
-
this._savePoint();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** @returns {boolean} */
|
|
248
|
-
canUndo() {
|
|
249
|
-
return this.stackOffset > 0;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/** @returns {boolean} */
|
|
253
|
-
canRedo() {
|
|
254
|
-
return this.stackOffset < this.stack.length - 1;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/** @returns {number} */
|
|
258
|
-
getUndoCount() {
|
|
259
|
-
return Math.max(0, this.stackOffset);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/** @returns {number} */
|
|
263
|
-
getRedoCount() {
|
|
264
|
-
return Math.max(0, this.stack.length - 1 - this.stackOffset);
|
|
265
|
-
}
|
|
266
|
-
}
|