autumnnote 1.6.7 → 1.8.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 +11 -5
- package/dist/autumnnote.css +164 -0
- package/dist/autumnnote.es.js +580 -39
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +658 -100
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/Context.js +63 -2
- package/src/js/editing/History.js +10 -0
- package/src/js/i18n/de.js +14 -0
- package/src/js/i18n/en.js +22 -0
- package/src/js/i18n/es.js +14 -0
- package/src/js/i18n/fr.js +15 -1
- package/src/js/i18n/ja.js +14 -0
- package/src/js/i18n/ko.js +14 -0
- package/src/js/i18n/vi.js +14 -0
- package/src/js/i18n/zh.js +14 -0
- package/src/js/index.js +5 -2
- package/src/js/module/BaseDialog.js +7 -0
- package/src/js/module/Buttons.js +49 -0
- package/src/js/module/Clipboard.js +12 -0
- package/src/js/module/CodeTooltip.js +23 -0
- package/src/js/module/Editor.js +8 -0
- package/src/js/module/FindReplace.js +50 -6
- package/src/js/module/ImageResizer.js +8 -7
- package/src/js/module/Mention.js +9 -2
- package/src/js/module/Statusbar.js +3 -3
- package/src/js/module/TableTooltip.js +287 -2
- package/src/js/renderer.js +5 -2
- package/src/styles/autumnnote.scss +181 -0
- package/types/index.d.ts +99 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autumnnote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "WYSIWYG rich-text editor built with vanilla JavaScript — zero dependencies, no jQuery. Dark mode, @mention, markdown shortcuts, bubble toolbar. React and Vue 3 wrappers included.",
|
|
5
5
|
"main": "dist/autumnnote.umd.js",
|
|
6
6
|
"module": "dist/autumnnote.es.js",
|
package/src/js/Context.js
CHANGED
|
@@ -339,10 +339,13 @@ export class Context {
|
|
|
339
339
|
|
|
340
340
|
/**
|
|
341
341
|
* Returns the current HTML content of the editor.
|
|
342
|
+
* Zero-width spaces (U+200B) inserted by inline editing helpers are stripped
|
|
343
|
+
* from the output so they don't leak into the consumer's HTML.
|
|
342
344
|
* @returns {string}
|
|
343
345
|
*/
|
|
344
346
|
getHTML() {
|
|
345
|
-
|
|
347
|
+
const html = this.invoke('editor.getHTML');
|
|
348
|
+
return typeof html === 'string' ? html.replace(//g, '') : html;
|
|
346
349
|
}
|
|
347
350
|
|
|
348
351
|
/**
|
|
@@ -385,6 +388,22 @@ export class Context {
|
|
|
385
388
|
this.invoke('editor.clearHistory');
|
|
386
389
|
}
|
|
387
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Returns the number of available undo steps.
|
|
393
|
+
* @returns {number}
|
|
394
|
+
*/
|
|
395
|
+
getUndoCount() {
|
|
396
|
+
return this.invoke('editor.getUndoCount') ?? 0;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Returns the number of available redo steps.
|
|
401
|
+
* @returns {number}
|
|
402
|
+
*/
|
|
403
|
+
getRedoCount() {
|
|
404
|
+
return this.invoke('editor.getRedoCount') ?? 0;
|
|
405
|
+
}
|
|
406
|
+
|
|
388
407
|
/**
|
|
389
408
|
* Returns true when the editor has no meaningful content.
|
|
390
409
|
* @returns {boolean}
|
|
@@ -513,6 +532,44 @@ export class Context {
|
|
|
513
532
|
});
|
|
514
533
|
}
|
|
515
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Returns an array of heading objects representing the table of contents.
|
|
537
|
+
* Each entry has: level (1-6), text (heading text), element (DOM element).
|
|
538
|
+
* @returns {{ level: number, text: string, element: HTMLElement }[]}
|
|
539
|
+
*/
|
|
540
|
+
getTableOfContents() {
|
|
541
|
+
const headings = Array.from(
|
|
542
|
+
this.layoutInfo.editable.querySelectorAll('h1,h2,h3,h4,h5,h6')
|
|
543
|
+
);
|
|
544
|
+
return headings.map((el) => ({
|
|
545
|
+
level: parseInt(el.tagName[1], 10),
|
|
546
|
+
text: el.textContent?.trim() ?? '',
|
|
547
|
+
element: /** @type {HTMLElement} */ (el),
|
|
548
|
+
}));
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Moves focus into the editable area.
|
|
553
|
+
*/
|
|
554
|
+
focus() {
|
|
555
|
+
this.layoutInfo.editable.focus();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Removes focus from the editable area.
|
|
560
|
+
*/
|
|
561
|
+
blur() {
|
|
562
|
+
this.layoutInfo.editable.blur();
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Returns true when the editor is currently in fullscreen mode.
|
|
567
|
+
* @returns {boolean}
|
|
568
|
+
*/
|
|
569
|
+
isFullscreen() {
|
|
570
|
+
return this.invoke('fullscreen.isActive') === true;
|
|
571
|
+
}
|
|
572
|
+
|
|
516
573
|
/**
|
|
517
574
|
* Sets whether the editor is disabled (readonly).
|
|
518
575
|
* @param {boolean} disabled
|
|
@@ -561,15 +618,19 @@ export class Context {
|
|
|
561
618
|
|
|
562
619
|
const container = this.layoutInfo.container;
|
|
563
620
|
const wasDark = container?.classList.contains('an-theme-dark');
|
|
621
|
+
const wasAuto = container?.classList.contains('an-theme-auto');
|
|
564
622
|
if (container?.parentNode) {
|
|
565
623
|
// Restore original element
|
|
566
624
|
this.targetEl.style.display = '';
|
|
567
625
|
container.remove();
|
|
568
626
|
}
|
|
569
|
-
//
|
|
627
|
+
// Clean up body theme classes if no other editors of that type remain
|
|
570
628
|
if (wasDark && !document.querySelector('.an-container.an-theme-dark')) {
|
|
571
629
|
document.body.classList.remove('an-theme-dark');
|
|
572
630
|
}
|
|
631
|
+
if (wasAuto && !document.querySelector('.an-container.an-theme-auto')) {
|
|
632
|
+
document.body.classList.remove('an-theme-auto');
|
|
633
|
+
}
|
|
573
634
|
|
|
574
635
|
if (typeof this.options.onDestroy === 'function') {
|
|
575
636
|
this.options.onDestroy(this);
|
|
@@ -221,4 +221,14 @@ export class History {
|
|
|
221
221
|
canRedo() {
|
|
222
222
|
return this.stackOffset < this.stack.length - 1;
|
|
223
223
|
}
|
|
224
|
+
|
|
225
|
+
/** @returns {number} */
|
|
226
|
+
getUndoCount() {
|
|
227
|
+
return Math.max(0, this.stackOffset);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** @returns {number} */
|
|
231
|
+
getRedoCount() {
|
|
232
|
+
return Math.max(0, this.stack.length - 1 - this.stackOffset);
|
|
233
|
+
}
|
|
224
234
|
}
|
package/src/js/i18n/de.js
CHANGED
|
@@ -157,6 +157,7 @@ export const de = {
|
|
|
157
157
|
replaceAriaLabel: 'Ersetzen durch',
|
|
158
158
|
replaceBtn: 'Ersetzen',
|
|
159
159
|
noResults: 'Keine Ergebnisse',
|
|
160
|
+
useRegex: 'Regulären Ausdruck verwenden',
|
|
160
161
|
replaceAllBtn: 'Alle ersetzen',
|
|
161
162
|
close: '×',
|
|
162
163
|
},
|
|
@@ -275,6 +276,7 @@ export const de = {
|
|
|
275
276
|
disableWordWrap: 'Zeilenumbruch deaktivieren',
|
|
276
277
|
convertToParagraph: 'In Absatz umwandeln',
|
|
277
278
|
deleteCodeBlock: 'Codeblock löschen',
|
|
279
|
+
lineNumbers: 'Zeilennummern umschalten',
|
|
278
280
|
},
|
|
279
281
|
table: {
|
|
280
282
|
ariaLabel: 'Tabellen-Aktionen',
|
|
@@ -297,6 +299,11 @@ export const de = {
|
|
|
297
299
|
tableBorderWidthPx: 'Tabellenrahmenbreite (px)',
|
|
298
300
|
cancelBtn: 'Abbrechen',
|
|
299
301
|
applyBtn: 'Anwenden',
|
|
302
|
+
sortAsc: 'Aufsteigend sortieren',
|
|
303
|
+
sortDesc: 'Absteigend sortieren',
|
|
304
|
+
exportCSV: 'Als CSV exportieren',
|
|
305
|
+
cellPadding: 'Zellauffüllung',
|
|
306
|
+
cellPaddingPx: 'Zellauffüllung (px)',
|
|
300
307
|
},
|
|
301
308
|
video: {
|
|
302
309
|
ariaLabel: 'Video-Aktionen',
|
|
@@ -318,4 +325,11 @@ export const de = {
|
|
|
318
325
|
imageSize: (maxSize) =>
|
|
319
326
|
`Die Bilddatei ist zu groß. Die maximal zulässige Größe beträgt ${maxSize} MB.`,
|
|
320
327
|
},
|
|
328
|
+
|
|
329
|
+
autoSaveRestore: {
|
|
330
|
+
found: 'Entwurf gefunden. Wiederherstellen?',
|
|
331
|
+
foundAt: 'Entwurf vom {date}. Wiederherstellen?',
|
|
332
|
+
restore: 'Wiederherstellen',
|
|
333
|
+
discard: 'Verwerfen',
|
|
334
|
+
},
|
|
321
335
|
};
|
package/src/js/i18n/en.js
CHANGED
|
@@ -153,6 +153,7 @@ export const en = {
|
|
|
153
153
|
findPlaceholder: 'Find\u2026',
|
|
154
154
|
searchAriaLabel: 'Search text',
|
|
155
155
|
caseSensitive: '\u00a0Case sensitive',
|
|
156
|
+
wholeWord: 'Whole Word',
|
|
156
157
|
prevBtn: '\u2190 Prev',
|
|
157
158
|
nextBtn: 'Next \u2192',
|
|
158
159
|
replacePlaceholder: 'Replace with\u2026',
|
|
@@ -160,9 +161,17 @@ export const en = {
|
|
|
160
161
|
replaceBtn: 'Replace',
|
|
161
162
|
replaceAllBtn: 'Replace All',
|
|
162
163
|
noResults: 'No results',
|
|
164
|
+
useRegex: 'Use Regular Expression',
|
|
163
165
|
close: '\u00d7',
|
|
164
166
|
},
|
|
165
167
|
|
|
168
|
+
autoSaveRestore: {
|
|
169
|
+
found: 'Draft found. Restore?',
|
|
170
|
+
foundAt: 'Draft from {date}. Restore?',
|
|
171
|
+
restore: 'Restore',
|
|
172
|
+
discard: 'Discard',
|
|
173
|
+
},
|
|
174
|
+
|
|
166
175
|
shortcutsDialog: {
|
|
167
176
|
title: 'Keyboard Shortcuts',
|
|
168
177
|
ariaLabel: 'Keyboard Shortcuts',
|
|
@@ -281,6 +290,7 @@ export const en = {
|
|
|
281
290
|
disableWordWrap: 'Disable Word Wrap',
|
|
282
291
|
convertToParagraph: 'Convert to Paragraph',
|
|
283
292
|
deleteCodeBlock: 'Delete Code Block',
|
|
293
|
+
lineNumbers: 'Toggle Line Numbers',
|
|
284
294
|
},
|
|
285
295
|
table: {
|
|
286
296
|
ariaLabel: 'Table actions',
|
|
@@ -297,14 +307,26 @@ export const en = {
|
|
|
297
307
|
columnWidth: 'Column Width',
|
|
298
308
|
rowHeight: 'Row Height',
|
|
299
309
|
tableBorderWidth: 'Table Border Width',
|
|
310
|
+
tableBorderColor: 'Table Border Color',
|
|
300
311
|
deleteTable: 'Delete Table',
|
|
312
|
+
cellAlignLeft: 'Align Left',
|
|
313
|
+
cellAlignCenter: 'Align Center',
|
|
314
|
+
cellAlignRight: 'Align Right',
|
|
315
|
+
cellAlignJustify: 'Align Justify',
|
|
316
|
+
toggleHeaderRow: 'Toggle Header Row',
|
|
301
317
|
cellBackground: 'Cell Background',
|
|
302
318
|
noShading: 'No Shading',
|
|
319
|
+
noBorderColor: 'No Border Color',
|
|
303
320
|
columnWidthPx: 'Column Width (px)',
|
|
304
321
|
rowHeightPx: 'Row Height (px)',
|
|
305
322
|
tableBorderWidthPx: 'Table Border Width (px)',
|
|
306
323
|
cancelBtn: 'Cancel',
|
|
307
324
|
applyBtn: 'Apply',
|
|
325
|
+
sortAsc: 'Sort Ascending',
|
|
326
|
+
sortDesc: 'Sort Descending',
|
|
327
|
+
exportCSV: 'Export as CSV',
|
|
328
|
+
cellPadding: 'Cell Padding',
|
|
329
|
+
cellPaddingPx: 'Cell Padding (px)',
|
|
308
330
|
},
|
|
309
331
|
video: {
|
|
310
332
|
ariaLabel: 'Video actions',
|
package/src/js/i18n/es.js
CHANGED
|
@@ -157,6 +157,7 @@ export const es = {
|
|
|
157
157
|
replaceAriaLabel: 'Reemplazar con',
|
|
158
158
|
replaceBtn: 'Reemplazar',
|
|
159
159
|
noResults: 'Sin resultados',
|
|
160
|
+
useRegex: 'Usar expresión regular',
|
|
160
161
|
replaceAllBtn: 'Reemplazar todo',
|
|
161
162
|
close: '×',
|
|
162
163
|
},
|
|
@@ -275,6 +276,7 @@ export const es = {
|
|
|
275
276
|
disableWordWrap: 'Desactivar ajuste de línea',
|
|
276
277
|
convertToParagraph: 'Convertir en párrafo',
|
|
277
278
|
deleteCodeBlock: 'Eliminar bloque de código',
|
|
279
|
+
lineNumbers: 'Alternar números de línea',
|
|
278
280
|
},
|
|
279
281
|
table: {
|
|
280
282
|
ariaLabel: 'Acciones de tabla',
|
|
@@ -297,6 +299,11 @@ export const es = {
|
|
|
297
299
|
tableBorderWidthPx: 'Grosor del borde (px)',
|
|
298
300
|
cancelBtn: 'Cancelar',
|
|
299
301
|
applyBtn: 'Aplicar',
|
|
302
|
+
sortAsc: 'Ordenar ascendente',
|
|
303
|
+
sortDesc: 'Ordenar descendente',
|
|
304
|
+
exportCSV: 'Exportar como CSV',
|
|
305
|
+
cellPadding: 'Relleno de celda',
|
|
306
|
+
cellPaddingPx: 'Relleno de celda (px)',
|
|
300
307
|
},
|
|
301
308
|
video: {
|
|
302
309
|
ariaLabel: 'Acciones de vídeo',
|
|
@@ -318,4 +325,11 @@ export const es = {
|
|
|
318
325
|
imageSize: (maxSize) =>
|
|
319
326
|
`El archivo de imagen es demasiado grande. El tamaño máximo permitido es ${maxSize} MB.`,
|
|
320
327
|
},
|
|
328
|
+
|
|
329
|
+
autoSaveRestore: {
|
|
330
|
+
found: 'Borrador encontrado. ¿Restaurar?',
|
|
331
|
+
foundAt: 'Borrador del {date}. ¿Restaurar?',
|
|
332
|
+
restore: 'Restaurar',
|
|
333
|
+
discard: 'Descartar',
|
|
334
|
+
},
|
|
321
335
|
};
|
package/src/js/i18n/fr.js
CHANGED
|
@@ -158,6 +158,7 @@ export const fr = {
|
|
|
158
158
|
replaceAriaLabel: 'Remplacer par',
|
|
159
159
|
replaceBtn: 'Remplacer',
|
|
160
160
|
noResults: 'Aucun résultat',
|
|
161
|
+
useRegex: 'Utiliser une expression régulière',
|
|
161
162
|
replaceAllBtn: 'Tout remplacer',
|
|
162
163
|
close: '\u00d7',
|
|
163
164
|
},
|
|
@@ -276,6 +277,7 @@ export const fr = {
|
|
|
276
277
|
disableWordWrap: 'Désactiver le retour à la ligne',
|
|
277
278
|
convertToParagraph: 'Convertir en paragraphe',
|
|
278
279
|
deleteCodeBlock: 'Supprimer le bloc de code',
|
|
280
|
+
lineNumbers: 'Activer/désactiver les numéros de ligne',
|
|
279
281
|
},
|
|
280
282
|
table: {
|
|
281
283
|
ariaLabel: 'Actions du tableau',
|
|
@@ -298,6 +300,11 @@ export const fr = {
|
|
|
298
300
|
tableBorderWidthPx: 'Épaisseur des bordures (px)',
|
|
299
301
|
cancelBtn: 'Annuler',
|
|
300
302
|
applyBtn: 'Appliquer',
|
|
303
|
+
sortAsc: 'Trier par ordre croissant',
|
|
304
|
+
sortDesc: 'Trier par ordre décroissant',
|
|
305
|
+
exportCSV: 'Exporter en CSV',
|
|
306
|
+
cellPadding: 'Rembourrage des cellules',
|
|
307
|
+
cellPaddingPx: 'Rembourrage des cellules (px)',
|
|
301
308
|
},
|
|
302
309
|
video: {
|
|
303
310
|
ariaLabel: 'Actions de la vidéo',
|
|
@@ -319,4 +326,11 @@ export const fr = {
|
|
|
319
326
|
imageSize: (maxSize) =>
|
|
320
327
|
`Le fichier image est trop volumineux. La taille maximale autorisée est de ${maxSize}\u00a0Mo.`,
|
|
321
328
|
},
|
|
322
|
-
|
|
329
|
+
|
|
330
|
+
autoSaveRestore: {
|
|
331
|
+
found: 'Brouillon trouvé. Restaurer ?',
|
|
332
|
+
foundAt: 'Brouillon du {date}. Restaurer ?',
|
|
333
|
+
restore: 'Restaurer',
|
|
334
|
+
discard: 'Ignorer',
|
|
335
|
+
},
|
|
336
|
+
};
|
package/src/js/i18n/ja.js
CHANGED
|
@@ -158,6 +158,7 @@ export const ja = {
|
|
|
158
158
|
replaceAriaLabel: '置換後のテキスト',
|
|
159
159
|
replaceBtn: '置換',
|
|
160
160
|
noResults: '結果なし',
|
|
161
|
+
useRegex: '正規表現を使用',
|
|
161
162
|
replaceAllBtn: 'すべて置換',
|
|
162
163
|
close: '\u00d7',
|
|
163
164
|
},
|
|
@@ -276,6 +277,7 @@ export const ja = {
|
|
|
276
277
|
disableWordWrap: '折り返しを無効にする',
|
|
277
278
|
convertToParagraph: '段落に変換',
|
|
278
279
|
deleteCodeBlock: 'コードブロックを削除',
|
|
280
|
+
lineNumbers: '行番号を切り替え',
|
|
279
281
|
},
|
|
280
282
|
table: {
|
|
281
283
|
ariaLabel: 'テーブル操作',
|
|
@@ -298,6 +300,11 @@ export const ja = {
|
|
|
298
300
|
tableBorderWidthPx: 'テーブルの枠幅 (px)',
|
|
299
301
|
cancelBtn: 'キャンセル',
|
|
300
302
|
applyBtn: '適用',
|
|
303
|
+
sortAsc: '昇順で並べ替え',
|
|
304
|
+
sortDesc: '降順で並べ替え',
|
|
305
|
+
exportCSV: 'CSVとしてエクスポート',
|
|
306
|
+
cellPadding: 'セルの余白',
|
|
307
|
+
cellPaddingPx: 'セルの余白 (px)',
|
|
301
308
|
},
|
|
302
309
|
video: {
|
|
303
310
|
ariaLabel: '動画操作',
|
|
@@ -319,4 +326,11 @@ export const ja = {
|
|
|
319
326
|
imageSize: (maxSize) =>
|
|
320
327
|
`画像ファイルが大きすぎます。最大許容サイズは ${maxSize} MB です。`,
|
|
321
328
|
},
|
|
329
|
+
|
|
330
|
+
autoSaveRestore: {
|
|
331
|
+
found: '下書きが見つかりました。復元しますか?',
|
|
332
|
+
foundAt: '{date} の下書きが見つかりました。復元しますか?',
|
|
333
|
+
restore: '復元',
|
|
334
|
+
discard: '破棄',
|
|
335
|
+
},
|
|
322
336
|
};
|
package/src/js/i18n/ko.js
CHANGED
|
@@ -157,6 +157,7 @@ export const ko = {
|
|
|
157
157
|
replaceAriaLabel: '바꿀 내용',
|
|
158
158
|
replaceBtn: '바꾸기',
|
|
159
159
|
noResults: '결과 없음',
|
|
160
|
+
useRegex: '정규식 사용',
|
|
160
161
|
replaceAllBtn: '모두 바꾸기',
|
|
161
162
|
close: '×',
|
|
162
163
|
},
|
|
@@ -275,6 +276,7 @@ export const ko = {
|
|
|
275
276
|
disableWordWrap: '줄 바꿈 해제',
|
|
276
277
|
convertToParagraph: '단락으로 변환',
|
|
277
278
|
deleteCodeBlock: '코드 블록 삭제',
|
|
279
|
+
lineNumbers: '줄 번호 전환',
|
|
278
280
|
},
|
|
279
281
|
table: {
|
|
280
282
|
ariaLabel: '표 작업',
|
|
@@ -297,6 +299,11 @@ export const ko = {
|
|
|
297
299
|
tableBorderWidthPx: '표 테두리 너비 (px)',
|
|
298
300
|
cancelBtn: '취소',
|
|
299
301
|
applyBtn: '적용',
|
|
302
|
+
sortAsc: '오름차순 정렬',
|
|
303
|
+
sortDesc: '내림차순 정렬',
|
|
304
|
+
exportCSV: 'CSV로 내보내기',
|
|
305
|
+
cellPadding: '셀 패딩',
|
|
306
|
+
cellPaddingPx: '셀 패딩 (px)',
|
|
300
307
|
},
|
|
301
308
|
video: {
|
|
302
309
|
ariaLabel: '동영상 작업',
|
|
@@ -318,4 +325,11 @@ export const ko = {
|
|
|
318
325
|
imageSize: (maxSize) =>
|
|
319
326
|
`이미지 파일이 너무 큽니다. 최대 허용 크기는 ${maxSize} MB입니다.`,
|
|
320
327
|
},
|
|
328
|
+
|
|
329
|
+
autoSaveRestore: {
|
|
330
|
+
found: '초안을 찾았습니다. 복원하시겠습니까?',
|
|
331
|
+
foundAt: '{date}의 초안을 찾았습니다. 복원하시겠습니까?',
|
|
332
|
+
restore: '복원',
|
|
333
|
+
discard: '삭제',
|
|
334
|
+
},
|
|
321
335
|
};
|
package/src/js/i18n/vi.js
CHANGED
|
@@ -159,6 +159,7 @@ export const vi = {
|
|
|
159
159
|
replaceBtn: 'Thay thế',
|
|
160
160
|
replaceAllBtn: 'Thay thế tất cả',
|
|
161
161
|
noResults: 'Không có kết quả',
|
|
162
|
+
useRegex: 'Dùng biểu thức chính quy',
|
|
162
163
|
close: '\u00d7',
|
|
163
164
|
},
|
|
164
165
|
|
|
@@ -276,6 +277,7 @@ export const vi = {
|
|
|
276
277
|
disableWordWrap: 'Tắt xuống dòng',
|
|
277
278
|
convertToParagraph: 'Chuyển thành đoạn văn',
|
|
278
279
|
deleteCodeBlock: 'Xóa khối mã',
|
|
280
|
+
lineNumbers: 'Bật/Tắt số dòng',
|
|
279
281
|
},
|
|
280
282
|
table: {
|
|
281
283
|
ariaLabel: 'Hành động bảng',
|
|
@@ -300,6 +302,11 @@ export const vi = {
|
|
|
300
302
|
tableBorderWidthPx: 'Độ rộng viền bảng (px)',
|
|
301
303
|
cancelBtn: 'Hủy',
|
|
302
304
|
applyBtn: 'Áp dụng',
|
|
305
|
+
sortAsc: 'Sắp xếp tăng dần',
|
|
306
|
+
sortDesc: 'Sắp xếp giảm dần',
|
|
307
|
+
exportCSV: 'Xuất CSV',
|
|
308
|
+
cellPadding: 'Khoảng đệm ô',
|
|
309
|
+
cellPaddingPx: 'Khoảng đệm ô (px)',
|
|
303
310
|
},
|
|
304
311
|
video: {
|
|
305
312
|
ariaLabel: 'Hành động video',
|
|
@@ -321,4 +328,11 @@ export const vi = {
|
|
|
321
328
|
imageSize: (maxSize) =>
|
|
322
329
|
`Tệp hình ảnh quá lớn. Kích thước tối đa cho phép là ${maxSize} MB.`,
|
|
323
330
|
},
|
|
331
|
+
|
|
332
|
+
autoSaveRestore: {
|
|
333
|
+
found: 'Tìm thấy bản nháp. Khôi phục?',
|
|
334
|
+
foundAt: 'Bản nháp từ {date}. Khôi phục?',
|
|
335
|
+
restore: 'Khôi phục',
|
|
336
|
+
discard: 'Bỏ qua',
|
|
337
|
+
},
|
|
324
338
|
};
|
package/src/js/i18n/zh.js
CHANGED
|
@@ -158,6 +158,7 @@ export const zh = {
|
|
|
158
158
|
replaceAriaLabel: '替换为',
|
|
159
159
|
replaceBtn: '替换',
|
|
160
160
|
noResults: '没有结果',
|
|
161
|
+
useRegex: '使用正则表达式',
|
|
161
162
|
replaceAllBtn: '全部替换',
|
|
162
163
|
close: '\u00d7',
|
|
163
164
|
},
|
|
@@ -276,6 +277,7 @@ export const zh = {
|
|
|
276
277
|
disableWordWrap: '禁用自动换行',
|
|
277
278
|
convertToParagraph: '转换为段落',
|
|
278
279
|
deleteCodeBlock: '删除代码块',
|
|
280
|
+
lineNumbers: '切换行号',
|
|
279
281
|
},
|
|
280
282
|
table: {
|
|
281
283
|
ariaLabel: '表格操作',
|
|
@@ -298,6 +300,11 @@ export const zh = {
|
|
|
298
300
|
tableBorderWidthPx: '表格边框宽度 (px)',
|
|
299
301
|
cancelBtn: '取消',
|
|
300
302
|
applyBtn: '应用',
|
|
303
|
+
sortAsc: '升序排列',
|
|
304
|
+
sortDesc: '降序排列',
|
|
305
|
+
exportCSV: '导出为 CSV',
|
|
306
|
+
cellPadding: '单元格内边距',
|
|
307
|
+
cellPaddingPx: '单元格内边距 (px)',
|
|
301
308
|
},
|
|
302
309
|
video: {
|
|
303
310
|
ariaLabel: '视频操作',
|
|
@@ -319,4 +326,11 @@ export const zh = {
|
|
|
319
326
|
imageSize: (maxSize) =>
|
|
320
327
|
`图片文件过大。最大允许大小为 ${maxSize} MB。`,
|
|
321
328
|
},
|
|
329
|
+
|
|
330
|
+
autoSaveRestore: {
|
|
331
|
+
found: '找到草稿。是否恢复?',
|
|
332
|
+
foundAt: '发现 {date} 的草稿。是否恢复?',
|
|
333
|
+
restore: '恢复',
|
|
334
|
+
discard: '放弃',
|
|
335
|
+
},
|
|
322
336
|
};
|
package/src/js/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// @ts-ignore
|
|
13
13
|
import '../styles/autumnnote.scss';
|
|
14
14
|
import { Context, _customModules, _globalPlugins } from './Context.js';
|
|
15
|
-
import { registerButton } from './module/Buttons.js';
|
|
15
|
+
import { registerButton, buttons } from './module/Buttons.js';
|
|
16
16
|
import { defaultOptions } from './settings.js';
|
|
17
17
|
|
|
18
18
|
// Snapshot of factory defaults taken at module-load time (before any setDefaults() calls)
|
|
@@ -140,8 +140,11 @@ const AutumnNote = {
|
|
|
140
140
|
*/
|
|
141
141
|
registerButton(btnDef) { registerButton(btnDef); return this; },
|
|
142
142
|
|
|
143
|
+
/** All pre-built button definitions — accessible in every module format including UMD/CJS. */
|
|
144
|
+
buttons,
|
|
145
|
+
|
|
143
146
|
/** Library version */
|
|
144
|
-
version: '1.
|
|
147
|
+
version: '1.8.0',
|
|
145
148
|
};
|
|
146
149
|
|
|
147
150
|
// ---------------------------------------------------------------------------
|
|
@@ -19,6 +19,13 @@ export class BaseDialog {
|
|
|
19
19
|
this._removeTrap = null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Abstract — subclasses must override
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
/** @returns {HTMLElement} */
|
|
27
|
+
_buildDialog() { throw new Error('_buildDialog() must be implemented by subclass'); }
|
|
28
|
+
|
|
22
29
|
// ---------------------------------------------------------------------------
|
|
23
30
|
// Lifecycle (shared)
|
|
24
31
|
// ---------------------------------------------------------------------------
|
package/src/js/module/Buttons.js
CHANGED
|
@@ -348,3 +348,52 @@ export const defaultToolbar = [
|
|
|
348
348
|
[hrBtn, linkBtn, imageBtn, videoBtn, tableBtn, emojiBtn, iconBtn],
|
|
349
349
|
[removeFormatBtn, codeviewBtn, fullscreenBtn, findBtn, printBtn, shortcutsBtn],
|
|
350
350
|
];
|
|
351
|
+
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
// Buttons namespace — all pre-built button definitions in a single object.
|
|
354
|
+
// Exposed as AutumnNote.buttons so UMD / CJS consumers can access them
|
|
355
|
+
// without named imports: AutumnNote.buttons.boldBtn, etc.
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
357
|
+
|
|
358
|
+
export const buttons = {
|
|
359
|
+
boldBtn,
|
|
360
|
+
italicBtn,
|
|
361
|
+
underlineBtn,
|
|
362
|
+
strikeBtn,
|
|
363
|
+
superscriptBtn,
|
|
364
|
+
subscriptBtn,
|
|
365
|
+
alignLeftBtn,
|
|
366
|
+
alignCenterBtn,
|
|
367
|
+
alignRightBtn,
|
|
368
|
+
alignJustifyBtn,
|
|
369
|
+
ulBtn,
|
|
370
|
+
olBtn,
|
|
371
|
+
indentBtn,
|
|
372
|
+
outdentBtn,
|
|
373
|
+
undoBtn,
|
|
374
|
+
redoBtn,
|
|
375
|
+
hrBtn,
|
|
376
|
+
linkBtn,
|
|
377
|
+
imageBtn,
|
|
378
|
+
videoBtn,
|
|
379
|
+
emojiBtn,
|
|
380
|
+
iconBtn,
|
|
381
|
+
tableBtn,
|
|
382
|
+
fontSizeBtn,
|
|
383
|
+
removeFormatBtn,
|
|
384
|
+
directionBtn,
|
|
385
|
+
fontFamilyBtn,
|
|
386
|
+
paragraphStyleBtn,
|
|
387
|
+
lineHeightBtn,
|
|
388
|
+
codeviewBtn,
|
|
389
|
+
fullscreenBtn,
|
|
390
|
+
shortcutsBtn,
|
|
391
|
+
findBtn,
|
|
392
|
+
findReplaceBtn,
|
|
393
|
+
inlineCodeBtn,
|
|
394
|
+
checklistBtn,
|
|
395
|
+
printBtn,
|
|
396
|
+
foreColorBtn,
|
|
397
|
+
backColorBtn,
|
|
398
|
+
defaultToolbar,
|
|
399
|
+
};
|
|
@@ -187,6 +187,18 @@ export class Clipboard {
|
|
|
187
187
|
const forcePlain = this._forcePlain;
|
|
188
188
|
this._forcePlain = false;
|
|
189
189
|
|
|
190
|
+
// Enforce maxPasteSize limit (default 5 MB)
|
|
191
|
+
const maxBytes = (this.options.maxPasteSize ?? 5) * 1024 * 1024;
|
|
192
|
+
if (maxBytes > 0) {
|
|
193
|
+
const text = clipboardData.getData('text/plain') || '';
|
|
194
|
+
const html = clipboardData.getData('text/html') || '';
|
|
195
|
+
const size = Math.max(text.length, html.length);
|
|
196
|
+
if (size > maxBytes) {
|
|
197
|
+
event.preventDefault();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
190
202
|
// 1. Image file in clipboard (screenshot, copy-image-from-browser, etc.)
|
|
191
203
|
if (clipboardData.items) {
|
|
192
204
|
const imageItems = Array.from(clipboardData.items).filter(
|
|
@@ -14,6 +14,7 @@ const ICONS = {
|
|
|
14
14
|
wrapOn: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="6" x2="21" y2="6"/><path d="M3 12h15a3 3 0 0 1 0 6H3"/><polyline points="6 15 3 18 6 21"/></svg>`,
|
|
15
15
|
toParagraph:`<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 4v16"/><path d="M17 4v16"/><path d="M9 4h8a4 4 0 0 1 0 8H9V4z"/></svg>`,
|
|
16
16
|
deleteCode: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg>`,
|
|
17
|
+
lineNumbers: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-2-2-2"/></svg>`,
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
export class CodeTooltip {
|
|
@@ -26,6 +27,8 @@ export class CodeTooltip {
|
|
|
26
27
|
this._hideTimer = null;
|
|
27
28
|
this._disposers = [];
|
|
28
29
|
this._copyBtn = null;
|
|
30
|
+
this._wrapBtn = null;
|
|
31
|
+
this._lineNumbersBtn = null;
|
|
29
32
|
this._langSelect = null;
|
|
30
33
|
this._prismScript = null; // script element while Prism is loading
|
|
31
34
|
}
|
|
@@ -127,6 +130,10 @@ export class CodeTooltip {
|
|
|
127
130
|
this._wrapBtn = this._makeBtn(ICONS.wrapOn, L.toggleWordWrap, () => this._toggleWrap());
|
|
128
131
|
el.appendChild(this._wrapBtn);
|
|
129
132
|
|
|
133
|
+
// Toggle line numbers
|
|
134
|
+
this._lineNumbersBtn = this._makeBtn(ICONS.lineNumbers, L.lineNumbers, () => this._toggleLineNumbers());
|
|
135
|
+
el.appendChild(this._lineNumbersBtn);
|
|
136
|
+
|
|
130
137
|
el.appendChild(this._sep());
|
|
131
138
|
|
|
132
139
|
// Convert to normal paragraph
|
|
@@ -183,6 +190,7 @@ export class CodeTooltip {
|
|
|
183
190
|
this._showTimer = setTimeout(() => {
|
|
184
191
|
this._activePre = pre;
|
|
185
192
|
this._syncWrapBtn();
|
|
193
|
+
this._syncLineNumbersBtn();
|
|
186
194
|
this._syncLangSelect();
|
|
187
195
|
this._show(pre);
|
|
188
196
|
}, SHOW_DELAY);
|
|
@@ -248,6 +256,13 @@ export class CodeTooltip {
|
|
|
248
256
|
: this.context.locale.tooltips.code.enableWordWrap;
|
|
249
257
|
}
|
|
250
258
|
|
|
259
|
+
_syncLineNumbersBtn() {
|
|
260
|
+
if (!this._activePre || !this._lineNumbersBtn) return;
|
|
261
|
+
const on = this._activePre.classList.contains('an-code-line-numbers');
|
|
262
|
+
this._lineNumbersBtn.classList.toggle('active', on);
|
|
263
|
+
this._lineNumbersBtn.title = this.context.locale.tooltips.code.lineNumbers;
|
|
264
|
+
}
|
|
265
|
+
|
|
251
266
|
_syncLangSelect() {
|
|
252
267
|
if (!this._activePre || !this._langSelect) return;
|
|
253
268
|
const codeEl = this._activePre.querySelector('code');
|
|
@@ -301,6 +316,14 @@ export class CodeTooltip {
|
|
|
301
316
|
this._positionNear(pre);
|
|
302
317
|
}
|
|
303
318
|
|
|
319
|
+
_toggleLineNumbers() {
|
|
320
|
+
const pre = this._activePre;
|
|
321
|
+
if (!pre) return;
|
|
322
|
+
pre.classList.toggle('an-code-line-numbers');
|
|
323
|
+
this._syncLineNumbersBtn();
|
|
324
|
+
this.context.invoke('editor.afterCommand');
|
|
325
|
+
}
|
|
326
|
+
|
|
304
327
|
/**
|
|
305
328
|
* Applies a language to a given <pre> element: sets classes, data-language,
|
|
306
329
|
* and triggers Prism highlighting. Called by the auto-detect flow.
|
package/src/js/module/Editor.js
CHANGED
|
@@ -525,6 +525,14 @@ export class Editor {
|
|
|
525
525
|
return this._history ? this._history.canRedo() : false;
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
+
getUndoCount() {
|
|
529
|
+
return this._history ? this._history.getUndoCount() : 0;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
getRedoCount() {
|
|
533
|
+
return this._history ? this._history.getRedoCount() : 0;
|
|
534
|
+
}
|
|
535
|
+
|
|
528
536
|
// ---------------------------------------------------------------------------
|
|
529
537
|
// Style commands (delegated to Style module)
|
|
530
538
|
// ---------------------------------------------------------------------------
|