neiki-editor 3.0.3 → 3.2.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 +387 -515
- package/dist/neiki-editor.css +110 -4
- package/dist/neiki-editor.js +393 -19
- package/dist/neiki-editor.min.css +1 -1
- package/dist/neiki-editor.min.js +1 -1
- package/package.json +1 -1
package/dist/neiki-editor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NeikiEditor - A Modern WYSIWYG Editor
|
|
3
|
-
* Version: 3.0
|
|
3
|
+
* Version: 3.2.0
|
|
4
4
|
*
|
|
5
5
|
* A lightweight, feature-rich text editor with support for:
|
|
6
6
|
* - Rich text formatting (bold, italic, underline, etc.)
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
|
|
22
22
|
let EDITOR_INSTANCE_COUNTER = 0;
|
|
23
23
|
|
|
24
|
+
// ============================================
|
|
25
|
+
// CSS_INJECT_POINT
|
|
26
|
+
// ============================================
|
|
27
|
+
|
|
24
28
|
// ============================================
|
|
25
29
|
// TRANSLATIONS / i18n
|
|
26
30
|
// ============================================
|
|
@@ -107,6 +111,8 @@
|
|
|
107
111
|
'theme.dark': 'Dark',
|
|
108
112
|
'theme.blue': 'Blue',
|
|
109
113
|
'theme.darkBlue': 'Dark Blue',
|
|
114
|
+
'theme.midnight': 'Midnight',
|
|
115
|
+
'theme.void': 'Void',
|
|
110
116
|
|
|
111
117
|
// Help modal
|
|
112
118
|
'help.author': 'Author',
|
|
@@ -200,6 +206,25 @@
|
|
|
200
206
|
'blockToolbar.moveDown': 'Move block down',
|
|
201
207
|
'blockToolbar.dragToReorder': 'Drag to reorder',
|
|
202
208
|
|
|
209
|
+
// Context menu
|
|
210
|
+
'contextMenu.undo': 'Undo',
|
|
211
|
+
'contextMenu.redo': 'Redo',
|
|
212
|
+
'contextMenu.cut': 'Cut',
|
|
213
|
+
'contextMenu.copy': 'Copy',
|
|
214
|
+
'contextMenu.paste': 'Paste',
|
|
215
|
+
'contextMenu.pasteAsPlainText': 'Paste as Plain Text',
|
|
216
|
+
'contextMenu.selectAll': 'Select All',
|
|
217
|
+
'contextMenu.removeFormat': 'Remove Formatting',
|
|
218
|
+
'tableContextMenu.insertRowAbove': 'Insert Row Above',
|
|
219
|
+
'tableContextMenu.insertRowBelow': 'Insert Row Below',
|
|
220
|
+
'tableContextMenu.insertColLeft': 'Insert Column Left',
|
|
221
|
+
'tableContextMenu.insertColRight': 'Insert Column Right',
|
|
222
|
+
'tableContextMenu.deleteRow': 'Delete Row',
|
|
223
|
+
'tableContextMenu.deleteCol': 'Delete Column',
|
|
224
|
+
'tableContextMenu.deleteTable': 'Delete Table',
|
|
225
|
+
'tableContextMenu.mergeCells': 'Merge Cells',
|
|
226
|
+
'tableContextMenu.splitCell': 'Split Cell',
|
|
227
|
+
|
|
203
228
|
// Placeholder
|
|
204
229
|
'placeholder': 'Start typing...'
|
|
205
230
|
},
|
|
@@ -284,6 +309,8 @@
|
|
|
284
309
|
'theme.dark': 'Tmavý',
|
|
285
310
|
'theme.blue': 'Modrý',
|
|
286
311
|
'theme.darkBlue': 'Tmavě modrý',
|
|
312
|
+
'theme.midnight': 'Půlnoc',
|
|
313
|
+
'theme.void': 'Prázdnota',
|
|
287
314
|
'help.author': 'Autor',
|
|
288
315
|
'help.version': 'Verze',
|
|
289
316
|
'help.github': 'GitHub',
|
|
@@ -372,6 +399,24 @@
|
|
|
372
399
|
'blockToolbar.moveDown': 'Přesunout blok dolů',
|
|
373
400
|
'blockToolbar.dragToReorder': 'Přetažením změnit pořadí',
|
|
374
401
|
|
|
402
|
+
'contextMenu.undo': 'Zpět',
|
|
403
|
+
'contextMenu.redo': 'Znovu',
|
|
404
|
+
'contextMenu.cut': 'Vyjmout',
|
|
405
|
+
'contextMenu.copy': 'Kopírovat',
|
|
406
|
+
'contextMenu.paste': 'Vložit',
|
|
407
|
+
'contextMenu.pasteAsPlainText': 'Vložit jako čistý text',
|
|
408
|
+
'contextMenu.selectAll': 'Vybrat vše',
|
|
409
|
+
'contextMenu.removeFormat': 'Odstranit formátování',
|
|
410
|
+
'tableContextMenu.insertRowAbove': 'Vložit řádek nad',
|
|
411
|
+
'tableContextMenu.insertRowBelow': 'Vložit řádek pod',
|
|
412
|
+
'tableContextMenu.insertColLeft': 'Vložit sloupec vlevo',
|
|
413
|
+
'tableContextMenu.insertColRight': 'Vložit sloupec vpravo',
|
|
414
|
+
'tableContextMenu.deleteRow': 'Smazat řádek',
|
|
415
|
+
'tableContextMenu.deleteCol': 'Smazat sloupec',
|
|
416
|
+
'tableContextMenu.deleteTable': 'Smazat tabulku',
|
|
417
|
+
'tableContextMenu.mergeCells': 'Sloučit buňky',
|
|
418
|
+
'tableContextMenu.splitCell': 'Rozdělit buňku',
|
|
419
|
+
|
|
375
420
|
'placeholder': 'Začněte psát...'
|
|
376
421
|
},
|
|
377
422
|
zh: {
|
|
@@ -447,6 +492,8 @@
|
|
|
447
492
|
'theme.dark': '深色',
|
|
448
493
|
'theme.blue': '蓝色',
|
|
449
494
|
'theme.darkBlue': '深蓝色',
|
|
495
|
+
'theme.midnight': '午夜',
|
|
496
|
+
'theme.void': '虚空',
|
|
450
497
|
'help.author': '作者',
|
|
451
498
|
'help.version': '版本',
|
|
452
499
|
'help.github': 'GitHub',
|
|
@@ -519,6 +566,24 @@
|
|
|
519
566
|
'blockToolbar.moveDown': '向下移动块',
|
|
520
567
|
'blockToolbar.dragToReorder': '拖动以重新排序',
|
|
521
568
|
|
|
569
|
+
'contextMenu.undo': '撤销',
|
|
570
|
+
'contextMenu.redo': '重做',
|
|
571
|
+
'contextMenu.cut': '剪切',
|
|
572
|
+
'contextMenu.copy': '复制',
|
|
573
|
+
'contextMenu.paste': '粘贴',
|
|
574
|
+
'contextMenu.pasteAsPlainText': '粘贴为纯文本',
|
|
575
|
+
'contextMenu.selectAll': '全选',
|
|
576
|
+
'contextMenu.removeFormat': '清除格式',
|
|
577
|
+
'tableContextMenu.insertRowAbove': '在上方插入行',
|
|
578
|
+
'tableContextMenu.insertRowBelow': '在下方插入行',
|
|
579
|
+
'tableContextMenu.insertColLeft': '在左侧插入列',
|
|
580
|
+
'tableContextMenu.insertColRight': '在右侧插入列',
|
|
581
|
+
'tableContextMenu.deleteRow': '删除行',
|
|
582
|
+
'tableContextMenu.deleteCol': '删除列',
|
|
583
|
+
'tableContextMenu.deleteTable': '删除表格',
|
|
584
|
+
'tableContextMenu.mergeCells': '合并单元格',
|
|
585
|
+
'tableContextMenu.splitCell': '拆分单元格',
|
|
586
|
+
|
|
522
587
|
'placeholder': '开始输入...'
|
|
523
588
|
},
|
|
524
589
|
es: {
|
|
@@ -593,6 +658,8 @@
|
|
|
593
658
|
'theme.dark': 'Oscuro',
|
|
594
659
|
'theme.blue': 'Azul',
|
|
595
660
|
'theme.darkBlue': 'Azul oscuro',
|
|
661
|
+
'theme.midnight': 'Medianoche',
|
|
662
|
+
'theme.void': 'Vacío',
|
|
596
663
|
'help.author': 'Autor',
|
|
597
664
|
'help.version': 'Versión',
|
|
598
665
|
'help.github': 'GitHub',
|
|
@@ -665,6 +732,24 @@
|
|
|
665
732
|
'blockToolbar.moveDown': 'Mover bloque abajo',
|
|
666
733
|
'blockToolbar.dragToReorder': 'Arrastrar para reordenar',
|
|
667
734
|
|
|
735
|
+
'contextMenu.undo': 'Deshacer',
|
|
736
|
+
'contextMenu.redo': 'Rehacer',
|
|
737
|
+
'contextMenu.cut': 'Cortar',
|
|
738
|
+
'contextMenu.copy': 'Copiar',
|
|
739
|
+
'contextMenu.paste': 'Pegar',
|
|
740
|
+
'contextMenu.pasteAsPlainText': 'Pegar como texto sin formato',
|
|
741
|
+
'contextMenu.selectAll': 'Seleccionar todo',
|
|
742
|
+
'contextMenu.removeFormat': 'Quitar formato',
|
|
743
|
+
'tableContextMenu.insertRowAbove': 'Insertar fila arriba',
|
|
744
|
+
'tableContextMenu.insertRowBelow': 'Insertar fila abajo',
|
|
745
|
+
'tableContextMenu.insertColLeft': 'Insertar columna a la izquierda',
|
|
746
|
+
'tableContextMenu.insertColRight': 'Insertar columna a la derecha',
|
|
747
|
+
'tableContextMenu.deleteRow': 'Eliminar fila',
|
|
748
|
+
'tableContextMenu.deleteCol': 'Eliminar columna',
|
|
749
|
+
'tableContextMenu.deleteTable': 'Eliminar tabla',
|
|
750
|
+
'tableContextMenu.mergeCells': 'Combinar celdas',
|
|
751
|
+
'tableContextMenu.splitCell': 'Dividir celda',
|
|
752
|
+
|
|
668
753
|
'placeholder': 'Empiece a escribir...'
|
|
669
754
|
},
|
|
670
755
|
de: {
|
|
@@ -739,6 +824,8 @@
|
|
|
739
824
|
'theme.dark': 'Dunkel',
|
|
740
825
|
'theme.blue': 'Blau',
|
|
741
826
|
'theme.darkBlue': 'Dunkelblau',
|
|
827
|
+
'theme.midnight': 'Mitternacht',
|
|
828
|
+
'theme.void': 'Leere',
|
|
742
829
|
'help.author': 'Autor',
|
|
743
830
|
'help.version': 'Version',
|
|
744
831
|
'help.github': 'GitHub',
|
|
@@ -811,6 +898,24 @@
|
|
|
811
898
|
'blockToolbar.moveDown': 'Block nach unten verschieben',
|
|
812
899
|
'blockToolbar.dragToReorder': 'Zum Neuordnen ziehen',
|
|
813
900
|
|
|
901
|
+
'contextMenu.undo': 'Rückgängig',
|
|
902
|
+
'contextMenu.redo': 'Wiederholen',
|
|
903
|
+
'contextMenu.cut': 'Ausschneiden',
|
|
904
|
+
'contextMenu.copy': 'Kopieren',
|
|
905
|
+
'contextMenu.paste': 'Einfügen',
|
|
906
|
+
'contextMenu.pasteAsPlainText': 'Als reinen Text einfügen',
|
|
907
|
+
'contextMenu.selectAll': 'Alles auswählen',
|
|
908
|
+
'contextMenu.removeFormat': 'Formatierung entfernen',
|
|
909
|
+
'tableContextMenu.insertRowAbove': 'Zeile oberhalb einfügen',
|
|
910
|
+
'tableContextMenu.insertRowBelow': 'Zeile unterhalb einfügen',
|
|
911
|
+
'tableContextMenu.insertColLeft': 'Spalte links einfügen',
|
|
912
|
+
'tableContextMenu.insertColRight': 'Spalte rechts einfügen',
|
|
913
|
+
'tableContextMenu.deleteRow': 'Zeile löschen',
|
|
914
|
+
'tableContextMenu.deleteCol': 'Spalte löschen',
|
|
915
|
+
'tableContextMenu.deleteTable': 'Tabelle löschen',
|
|
916
|
+
'tableContextMenu.mergeCells': 'Zellen verbinden',
|
|
917
|
+
'tableContextMenu.splitCell': 'Zelle teilen',
|
|
918
|
+
|
|
814
919
|
'placeholder': 'Hier schreiben...'
|
|
815
920
|
},
|
|
816
921
|
fr: {
|
|
@@ -885,6 +990,8 @@
|
|
|
885
990
|
'theme.dark': 'Sombre',
|
|
886
991
|
'theme.blue': 'Bleu',
|
|
887
992
|
'theme.darkBlue': 'Bleu foncé',
|
|
993
|
+
'theme.midnight': 'Minuit',
|
|
994
|
+
'theme.void': 'Néant',
|
|
888
995
|
'help.author': 'Auteur',
|
|
889
996
|
'help.version': 'Version',
|
|
890
997
|
'help.github': 'GitHub',
|
|
@@ -957,6 +1064,24 @@
|
|
|
957
1064
|
'blockToolbar.moveDown': 'Déplacer le bloc vers le bas',
|
|
958
1065
|
'blockToolbar.dragToReorder': 'Glisser pour réorganiser',
|
|
959
1066
|
|
|
1067
|
+
'contextMenu.undo': 'Annuler',
|
|
1068
|
+
'contextMenu.redo': 'Rétablir',
|
|
1069
|
+
'contextMenu.cut': 'Couper',
|
|
1070
|
+
'contextMenu.copy': 'Copier',
|
|
1071
|
+
'contextMenu.paste': 'Coller',
|
|
1072
|
+
'contextMenu.pasteAsPlainText': 'Coller comme texte brut',
|
|
1073
|
+
'contextMenu.selectAll': 'Tout sélectionner',
|
|
1074
|
+
'contextMenu.removeFormat': 'Effacer la mise en forme',
|
|
1075
|
+
'tableContextMenu.insertRowAbove': 'Insérer une ligne au-dessus',
|
|
1076
|
+
'tableContextMenu.insertRowBelow': 'Insérer une ligne en dessous',
|
|
1077
|
+
'tableContextMenu.insertColLeft': 'Insérer une colonne à gauche',
|
|
1078
|
+
'tableContextMenu.insertColRight': 'Insérer une colonne à droite',
|
|
1079
|
+
'tableContextMenu.deleteRow': 'Supprimer la ligne',
|
|
1080
|
+
'tableContextMenu.deleteCol': 'Supprimer la colonne',
|
|
1081
|
+
'tableContextMenu.deleteTable': 'Supprimer le tableau',
|
|
1082
|
+
'tableContextMenu.mergeCells': 'Fusionner les cellules',
|
|
1083
|
+
'tableContextMenu.splitCell': 'Diviser la cellule',
|
|
1084
|
+
|
|
960
1085
|
'placeholder': 'Commencez à écrire...'
|
|
961
1086
|
},
|
|
962
1087
|
pt: {
|
|
@@ -1031,6 +1156,8 @@
|
|
|
1031
1156
|
'theme.dark': 'Escuro',
|
|
1032
1157
|
'theme.blue': 'Azul',
|
|
1033
1158
|
'theme.darkBlue': 'Azul escuro',
|
|
1159
|
+
'theme.midnight': 'Meia-noite',
|
|
1160
|
+
'theme.void': 'Vazio',
|
|
1034
1161
|
'help.author': 'Autor',
|
|
1035
1162
|
'help.version': 'Versão',
|
|
1036
1163
|
'help.github': 'GitHub',
|
|
@@ -1103,6 +1230,24 @@
|
|
|
1103
1230
|
'blockToolbar.moveDown': 'Mover bloco para baixo',
|
|
1104
1231
|
'blockToolbar.dragToReorder': 'Arraste para reordenar',
|
|
1105
1232
|
|
|
1233
|
+
'contextMenu.undo': 'Desfazer',
|
|
1234
|
+
'contextMenu.redo': 'Refazer',
|
|
1235
|
+
'contextMenu.cut': 'Recortar',
|
|
1236
|
+
'contextMenu.copy': 'Copiar',
|
|
1237
|
+
'contextMenu.paste': 'Colar',
|
|
1238
|
+
'contextMenu.pasteAsPlainText': 'Colar como texto simples',
|
|
1239
|
+
'contextMenu.selectAll': 'Selecionar tudo',
|
|
1240
|
+
'contextMenu.removeFormat': 'Remover formatação',
|
|
1241
|
+
'tableContextMenu.insertRowAbove': 'Inserir linha acima',
|
|
1242
|
+
'tableContextMenu.insertRowBelow': 'Inserir linha abaixo',
|
|
1243
|
+
'tableContextMenu.insertColLeft': 'Inserir coluna à esquerda',
|
|
1244
|
+
'tableContextMenu.insertColRight': 'Inserir coluna à direita',
|
|
1245
|
+
'tableContextMenu.deleteRow': 'Excluir linha',
|
|
1246
|
+
'tableContextMenu.deleteCol': 'Excluir coluna',
|
|
1247
|
+
'tableContextMenu.deleteTable': 'Excluir tabela',
|
|
1248
|
+
'tableContextMenu.mergeCells': 'Mesclar células',
|
|
1249
|
+
'tableContextMenu.splitCell': 'Dividir célula',
|
|
1250
|
+
|
|
1106
1251
|
'placeholder': 'Comece a digitar...'
|
|
1107
1252
|
},
|
|
1108
1253
|
ja: {
|
|
@@ -1177,6 +1322,8 @@
|
|
|
1177
1322
|
'theme.dark': 'ダーク',
|
|
1178
1323
|
'theme.blue': 'ブルー',
|
|
1179
1324
|
'theme.darkBlue': 'ダークブルー',
|
|
1325
|
+
'theme.midnight': 'ミッドナイト',
|
|
1326
|
+
'theme.void': 'ヴォイド',
|
|
1180
1327
|
'help.author': '作成者',
|
|
1181
1328
|
'help.version': 'バージョン',
|
|
1182
1329
|
'help.github': 'GitHub',
|
|
@@ -1249,6 +1396,24 @@
|
|
|
1249
1396
|
'blockToolbar.moveDown': 'ブロックを下へ移動',
|
|
1250
1397
|
'blockToolbar.dragToReorder': 'ドラッグして並べ替え',
|
|
1251
1398
|
|
|
1399
|
+
'contextMenu.undo': '元に戻す',
|
|
1400
|
+
'contextMenu.redo': 'やり直す',
|
|
1401
|
+
'contextMenu.cut': '切り取り',
|
|
1402
|
+
'contextMenu.copy': 'コピー',
|
|
1403
|
+
'contextMenu.paste': '貼り付け',
|
|
1404
|
+
'contextMenu.pasteAsPlainText': 'プレーンテキストとして貼り付け',
|
|
1405
|
+
'contextMenu.selectAll': 'すべて選択',
|
|
1406
|
+
'contextMenu.removeFormat': '書式をクリア',
|
|
1407
|
+
'tableContextMenu.insertRowAbove': '上に行を挿入',
|
|
1408
|
+
'tableContextMenu.insertRowBelow': '下に行を挿入',
|
|
1409
|
+
'tableContextMenu.insertColLeft': '左に列を挿入',
|
|
1410
|
+
'tableContextMenu.insertColRight': '右に列を挿入',
|
|
1411
|
+
'tableContextMenu.deleteRow': '行を削除',
|
|
1412
|
+
'tableContextMenu.deleteCol': '列を削除',
|
|
1413
|
+
'tableContextMenu.deleteTable': 'テーブルを削除',
|
|
1414
|
+
'tableContextMenu.mergeCells': 'セルを結合',
|
|
1415
|
+
'tableContextMenu.splitCell': 'セルを分割',
|
|
1416
|
+
|
|
1252
1417
|
'placeholder': '入力してください...'
|
|
1253
1418
|
}
|
|
1254
1419
|
};
|
|
@@ -1277,12 +1442,14 @@
|
|
|
1277
1442
|
return text;
|
|
1278
1443
|
}
|
|
1279
1444
|
|
|
1280
|
-
const THEMES = ['light', 'dark', 'blue', 'dark-blue'];
|
|
1445
|
+
const THEMES = ['light', 'dark', 'blue', 'dark-blue', 'midnight', 'void'];
|
|
1281
1446
|
const THEME_OPTIONS = [
|
|
1282
1447
|
{ value: 'light', labelKey: 'theme.light' },
|
|
1283
1448
|
{ value: 'dark', labelKey: 'theme.dark' },
|
|
1284
1449
|
{ value: 'blue', labelKey: 'theme.blue' },
|
|
1285
|
-
{ value: 'dark-blue', labelKey: 'theme.darkBlue' }
|
|
1450
|
+
{ value: 'dark-blue', labelKey: 'theme.darkBlue' },
|
|
1451
|
+
{ value: 'midnight', labelKey: 'theme.midnight' },
|
|
1452
|
+
{ value: 'void', labelKey: 'theme.void' }
|
|
1286
1453
|
];
|
|
1287
1454
|
|
|
1288
1455
|
const DEFAULT_CONFIG = {
|
|
@@ -1306,6 +1473,7 @@
|
|
|
1306
1473
|
theme: 'light',
|
|
1307
1474
|
language: 'en',
|
|
1308
1475
|
translations: null,
|
|
1476
|
+
contextMenu: true,
|
|
1309
1477
|
autosaveKey: null,
|
|
1310
1478
|
plugins: [],
|
|
1311
1479
|
onChange: null,
|
|
@@ -1934,7 +2102,12 @@
|
|
|
1934
2102
|
grip: '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path fill="none" stroke="currentColor" stroke-linecap="square" stroke-width="2" d="m15 5l-3-3l-3 3m0 14l3 3l3-3m4-4l3-3l-3-3M5 9l-3 3l3 3m7-12v9m0 0v9m0-9h9m-9 0H3"/></svg>',
|
|
1935
2103
|
moveUp: '<svg viewBox="0 0 24 24"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z"/></svg>',
|
|
1936
2104
|
moveDown: '<svg viewBox="0 0 24 24"><path d="M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z"/></svg>',
|
|
1937
|
-
replaceImage: '<svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/><path d="M19.35 10.04A7.49 7.49 0 0012 4C9.11 4 6.6 5.64 5.35 8.04" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>'
|
|
2105
|
+
replaceImage: '<svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/><path d="M19.35 10.04A7.49 7.49 0 0012 4C9.11 4 6.6 5.64 5.35 8.04" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>',
|
|
2106
|
+
cut: '<svg viewBox="0 0 24 24"><path d="M9.64 7.64c.23-.5.36-1.05.36-1.64 0-2.21-1.79-4-4-4S2 3.79 2 6s1.79 4 4 4c.59 0 1.14-.13 1.64-.36L10 12l-2.36 2.36C7.14 14.13 6.59 14 6 14c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4c0-.59-.13-1.14-.36-1.64L12 14l7 7h3v-1L9.64 7.64zM6 8c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm0 12c-1.1 0-2-.89-2-2s.9-2 2-2 2 .89 2 2-.9 2-2 2zm6-7.5c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5-.22.5-.5.5zM19 3l-6 6 2 2 7-7V3z"/></svg>',
|
|
2107
|
+
copy: '<svg viewBox="0 0 24 24"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>',
|
|
2108
|
+
paste: '<svg viewBox="0 0 24 24"><path d="M19 2h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/></svg>',
|
|
2109
|
+
pasteText: '<svg viewBox="0 0 24 24"><path d="M19 2h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm5 16H7v-2h10v2zm0-4H7v-2h10v2zm-3-4H7V8h7v2z"/></svg>',
|
|
2110
|
+
selectAll: '<svg viewBox="0 0 24 24"><path d="M3 3v6h2V5h4V3H3zm16 0h-4v2h4v4h2V3h-2zM5 15H3v6h6v-2H5v-4zm14 4h-4v2h6v-6h-2v4zM9 9h6v6H9V9z"/></svg>'
|
|
1938
2111
|
};
|
|
1939
2112
|
|
|
1940
2113
|
// ============================================
|
|
@@ -2109,7 +2282,7 @@
|
|
|
2109
2282
|
|
|
2110
2283
|
syncThemeClasses() {
|
|
2111
2284
|
if (!this.overlay || !this.editor.getThemeClasses) return;
|
|
2112
|
-
this.overlay.classList.remove('neiki-dark', 'neiki-theme-blue', 'neiki-theme-dark-blue');
|
|
2285
|
+
this.overlay.classList.remove('neiki-dark', 'neiki-theme-blue', 'neiki-theme-dark-blue', 'neiki-theme-midnight', 'neiki-theme-void');
|
|
2113
2286
|
this.editor.getThemeClasses(this.editor.config.theme).split(' ').filter(Boolean).forEach(className => {
|
|
2114
2287
|
this.overlay.classList.add(className);
|
|
2115
2288
|
});
|
|
@@ -2891,7 +3064,7 @@
|
|
|
2891
3064
|
<img src="https://github.com/neikiri/neiki-editor/raw/main/assets/logo.png" alt="Neiki's Editor" style="width: 240px; height: auto; margin: 0 auto 16px; display: block;">
|
|
2892
3065
|
<div style="font-size: 14px; line-height: 2; color: var(--neiki-text-primary);">
|
|
2893
3066
|
<div><strong>${Utils.escapeHTML(t('help.author'))}:</strong> neikiri (Jindřich Stoklasa)</div>
|
|
2894
|
-
<div><strong>${Utils.escapeHTML(t('help.version'))}:</strong> 3.0
|
|
3067
|
+
<div><strong>${Utils.escapeHTML(t('help.version'))}:</strong> 3.2.0</div>
|
|
2895
3068
|
<div><strong>${Utils.escapeHTML(t('help.github'))}:</strong> <a href="https://github.com/neikiri/neiki-editor" target="_blank" rel="noopener noreferrer" style="color: var(--neiki-accent);">github.com/neikiri/neiki-editor</a></div>
|
|
2896
3069
|
<div><strong>${Utils.escapeHTML(t('help.documentation'))}:</strong> <a href="https://github.com/neikiri/neiki-editor/wiki" target="_blank" rel="noopener noreferrer" style="color: var(--neiki-accent);">Wiki</a></div>
|
|
2897
3070
|
</div>
|
|
@@ -3834,7 +4007,10 @@
|
|
|
3834
4007
|
this.emojiPicker = new EmojiPicker(this);
|
|
3835
4008
|
this.specialCharsPicker = new SpecialCharsPicker(this);
|
|
3836
4009
|
this.commands = new Commands(this);
|
|
3837
|
-
this.
|
|
4010
|
+
if (this.config.contextMenu !== false) {
|
|
4011
|
+
this.tableContextMenu = new TableContextMenu(this);
|
|
4012
|
+
this.editorContextMenu = new EditorContextMenu(this);
|
|
4013
|
+
}
|
|
3838
4014
|
this.floatingToolbar = new FloatingToolbar(this);
|
|
3839
4015
|
this.imageResizer = new ImageResizer(this);
|
|
3840
4016
|
this.tableColumnResizer = new TableColumnResizer(this);
|
|
@@ -3884,7 +4060,7 @@
|
|
|
3884
4060
|
const normalizedTheme = THEMES.includes(theme) ? theme : 'light';
|
|
3885
4061
|
const classes = [];
|
|
3886
4062
|
|
|
3887
|
-
if (normalizedTheme === 'dark' || normalizedTheme === 'dark-blue') {
|
|
4063
|
+
if (normalizedTheme === 'dark' || normalizedTheme === 'dark-blue' || normalizedTheme === 'midnight' || normalizedTheme === 'void') {
|
|
3888
4064
|
classes.push('neiki-dark');
|
|
3889
4065
|
}
|
|
3890
4066
|
|
|
@@ -3898,7 +4074,7 @@
|
|
|
3898
4074
|
applyTheme(theme) {
|
|
3899
4075
|
const normalizedTheme = THEMES.includes(theme) ? theme : 'light';
|
|
3900
4076
|
this.config.theme = normalizedTheme;
|
|
3901
|
-
this.container.classList.remove('neiki-dark', 'neiki-theme-blue', 'neiki-theme-dark-blue');
|
|
4077
|
+
this.container.classList.remove('neiki-dark', 'neiki-theme-blue', 'neiki-theme-dark-blue', 'neiki-theme-midnight', 'neiki-theme-void');
|
|
3902
4078
|
this.getThemeClasses(normalizedTheme).split(' ').filter(Boolean).forEach(className => {
|
|
3903
4079
|
this.container.classList.add(className);
|
|
3904
4080
|
});
|
|
@@ -4873,7 +5049,7 @@
|
|
|
4873
5049
|
}
|
|
4874
5050
|
break;
|
|
4875
5051
|
case 'themeToggle':
|
|
4876
|
-
isActive = this.config.theme === 'dark' || this.config.theme === 'dark-blue';
|
|
5052
|
+
isActive = this.config.theme === 'dark' || this.config.theme === 'dark-blue' || this.config.theme === 'midnight' || this.config.theme === 'void';
|
|
4877
5053
|
break;
|
|
4878
5054
|
}
|
|
4879
5055
|
} catch (e) {
|
|
@@ -7079,17 +7255,17 @@
|
|
|
7079
7255
|
createMenu() {
|
|
7080
7256
|
this.menu = Utils.createElement('div', { className: 'neiki-context-menu' });
|
|
7081
7257
|
this.menu.innerHTML = `
|
|
7082
|
-
<div class="neiki-context-item" data-action="insertRowAbove">${Icons.table}
|
|
7083
|
-
<div class="neiki-context-item" data-action="insertRowBelow">${Icons.table}
|
|
7084
|
-
<div class="neiki-context-item" data-action="insertColLeft">${Icons.table}
|
|
7085
|
-
<div class="neiki-context-item" data-action="insertColRight">${Icons.table}
|
|
7258
|
+
<div class="neiki-context-item" data-action="insertRowAbove">${Icons.table} ${Utils.escapeHTML(t('tableContextMenu.insertRowAbove'))}</div>
|
|
7259
|
+
<div class="neiki-context-item" data-action="insertRowBelow">${Icons.table} ${Utils.escapeHTML(t('tableContextMenu.insertRowBelow'))}</div>
|
|
7260
|
+
<div class="neiki-context-item" data-action="insertColLeft">${Icons.table} ${Utils.escapeHTML(t('tableContextMenu.insertColLeft'))}</div>
|
|
7261
|
+
<div class="neiki-context-item" data-action="insertColRight">${Icons.table} ${Utils.escapeHTML(t('tableContextMenu.insertColRight'))}</div>
|
|
7086
7262
|
<div class="neiki-context-divider"></div>
|
|
7087
|
-
<div class="neiki-context-item" data-action="deleteRow">${Icons.eraser}
|
|
7088
|
-
<div class="neiki-context-item" data-action="deleteCol">${Icons.eraser}
|
|
7089
|
-
<div class="neiki-context-item neiki-context-danger" data-action="deleteTable">${Icons.eraser}
|
|
7263
|
+
<div class="neiki-context-item" data-action="deleteRow">${Icons.eraser} ${Utils.escapeHTML(t('tableContextMenu.deleteRow'))}</div>
|
|
7264
|
+
<div class="neiki-context-item" data-action="deleteCol">${Icons.eraser} ${Utils.escapeHTML(t('tableContextMenu.deleteCol'))}</div>
|
|
7265
|
+
<div class="neiki-context-item neiki-context-danger" data-action="deleteTable">${Icons.eraser} ${Utils.escapeHTML(t('tableContextMenu.deleteTable'))}</div>
|
|
7090
7266
|
<div class="neiki-context-divider"></div>
|
|
7091
|
-
<div class="neiki-context-item" data-action="mergeCells">${Icons.table}
|
|
7092
|
-
<div class="neiki-context-item" data-action="splitCell">${Icons.table}
|
|
7267
|
+
<div class="neiki-context-item" data-action="mergeCells">${Icons.table} ${Utils.escapeHTML(t('tableContextMenu.mergeCells'))}</div>
|
|
7268
|
+
<div class="neiki-context-item" data-action="splitCell">${Icons.table} ${Utils.escapeHTML(t('tableContextMenu.splitCell'))}</div>
|
|
7093
7269
|
`;
|
|
7094
7270
|
document.body.appendChild(this.menu);
|
|
7095
7271
|
|
|
@@ -7123,7 +7299,16 @@
|
|
|
7123
7299
|
});
|
|
7124
7300
|
}
|
|
7125
7301
|
|
|
7302
|
+
syncThemeClasses() {
|
|
7303
|
+
if (!this.editor.getThemeClasses) return;
|
|
7304
|
+
this.menu.classList.remove('neiki-dark', 'neiki-theme-blue', 'neiki-theme-dark-blue', 'neiki-theme-midnight', 'neiki-theme-void');
|
|
7305
|
+
this.editor.getThemeClasses(this.editor.config.theme).split(' ').filter(Boolean).forEach(className => {
|
|
7306
|
+
this.menu.classList.add(className);
|
|
7307
|
+
});
|
|
7308
|
+
}
|
|
7309
|
+
|
|
7126
7310
|
show(x, y) {
|
|
7311
|
+
this.syncThemeClasses();
|
|
7127
7312
|
this.menu.style.display = 'block';
|
|
7128
7313
|
|
|
7129
7314
|
// Adjust position to stay within viewport
|
|
@@ -7262,6 +7447,195 @@
|
|
|
7262
7447
|
}
|
|
7263
7448
|
}
|
|
7264
7449
|
|
|
7450
|
+
// ============================================
|
|
7451
|
+
// EDITOR CONTEXT MENU (general right-click menu)
|
|
7452
|
+
// ============================================
|
|
7453
|
+
|
|
7454
|
+
class EditorContextMenu {
|
|
7455
|
+
constructor(editor) {
|
|
7456
|
+
this.editor = editor;
|
|
7457
|
+
this.menu = null;
|
|
7458
|
+
|
|
7459
|
+
this.createMenu();
|
|
7460
|
+
this.bindEvents();
|
|
7461
|
+
}
|
|
7462
|
+
|
|
7463
|
+
createMenu() {
|
|
7464
|
+
this.menu = Utils.createElement('div', { className: 'neiki-context-menu' });
|
|
7465
|
+
this.menu.innerHTML = `
|
|
7466
|
+
<div class="neiki-context-item" data-action="undo">${Icons.undo} <span data-label="contextMenu.undo"></span></div>
|
|
7467
|
+
<div class="neiki-context-item" data-action="redo">${Icons.redo} <span data-label="contextMenu.redo"></span></div>
|
|
7468
|
+
<div class="neiki-context-divider"></div>
|
|
7469
|
+
<div class="neiki-context-item" data-action="cut">${Icons.cut} <span data-label="contextMenu.cut"></span></div>
|
|
7470
|
+
<div class="neiki-context-item" data-action="copy">${Icons.copy} <span data-label="contextMenu.copy"></span></div>
|
|
7471
|
+
<div class="neiki-context-item" data-action="paste">${Icons.paste} <span data-label="contextMenu.paste"></span></div>
|
|
7472
|
+
<div class="neiki-context-item" data-action="pasteAsPlainText">${Icons.pasteText} <span data-label="contextMenu.pasteAsPlainText"></span></div>
|
|
7473
|
+
<div class="neiki-context-divider"></div>
|
|
7474
|
+
<div class="neiki-context-item" data-action="selectAll">${Icons.selectAll} <span data-label="contextMenu.selectAll"></span></div>
|
|
7475
|
+
<div class="neiki-context-divider"></div>
|
|
7476
|
+
<div class="neiki-context-item" data-action="removeFormat">${Icons.eraser} <span data-label="contextMenu.removeFormat"></span></div>
|
|
7477
|
+
`;
|
|
7478
|
+
document.body.appendChild(this.menu);
|
|
7479
|
+
this.updateLabels();
|
|
7480
|
+
|
|
7481
|
+
this.menu.querySelectorAll('.neiki-context-item').forEach(item => {
|
|
7482
|
+
item.addEventListener('click', (e) => {
|
|
7483
|
+
if (item.classList.contains('neiki-context-disabled')) return;
|
|
7484
|
+
const action = item.dataset.action;
|
|
7485
|
+
this.executeAction(action);
|
|
7486
|
+
this.hide();
|
|
7487
|
+
});
|
|
7488
|
+
});
|
|
7489
|
+
}
|
|
7490
|
+
|
|
7491
|
+
updateLabels() {
|
|
7492
|
+
this.menu.querySelectorAll('[data-label]').forEach(span => {
|
|
7493
|
+
span.textContent = t(span.dataset.label);
|
|
7494
|
+
});
|
|
7495
|
+
}
|
|
7496
|
+
|
|
7497
|
+
syncThemeClasses() {
|
|
7498
|
+
if (!this.editor.getThemeClasses) return;
|
|
7499
|
+
this.menu.classList.remove('neiki-dark', 'neiki-theme-blue', 'neiki-theme-dark-blue', 'neiki-theme-midnight', 'neiki-theme-void');
|
|
7500
|
+
this.editor.getThemeClasses(this.editor.config.theme).split(' ').filter(Boolean).forEach(className => {
|
|
7501
|
+
this.menu.classList.add(className);
|
|
7502
|
+
});
|
|
7503
|
+
}
|
|
7504
|
+
|
|
7505
|
+
updateItemStates() {
|
|
7506
|
+
const sel = window.getSelection();
|
|
7507
|
+
const hasSelection = !!(sel && sel.rangeCount && !sel.isCollapsed && this.editor.contentArea.contains(sel.anchorNode));
|
|
7508
|
+
|
|
7509
|
+
['cut', 'copy'].forEach(action => {
|
|
7510
|
+
const item = this.menu.querySelector(`[data-action="${action}"]`);
|
|
7511
|
+
if (item) item.classList.toggle('neiki-context-disabled', !hasSelection);
|
|
7512
|
+
});
|
|
7513
|
+
}
|
|
7514
|
+
|
|
7515
|
+
bindEvents() {
|
|
7516
|
+
this.editor.contentArea.addEventListener('contextmenu', (e) => {
|
|
7517
|
+
if (e.target.closest('td, th')) return; // handled by TableContextMenu
|
|
7518
|
+
|
|
7519
|
+
e.preventDefault();
|
|
7520
|
+
this.editor.saveCurrentSelection();
|
|
7521
|
+
this.updateLabels();
|
|
7522
|
+
this.updateItemStates();
|
|
7523
|
+
this.show(e.clientX, e.clientY);
|
|
7524
|
+
});
|
|
7525
|
+
|
|
7526
|
+
document.addEventListener('click', (e) => {
|
|
7527
|
+
if (!this.menu.contains(e.target)) {
|
|
7528
|
+
this.hide();
|
|
7529
|
+
}
|
|
7530
|
+
});
|
|
7531
|
+
|
|
7532
|
+
document.addEventListener('keydown', (e) => {
|
|
7533
|
+
if (e.key === 'Escape') this.hide();
|
|
7534
|
+
});
|
|
7535
|
+
}
|
|
7536
|
+
|
|
7537
|
+
show(x, y) {
|
|
7538
|
+
this.syncThemeClasses();
|
|
7539
|
+
this.menu.style.display = 'block';
|
|
7540
|
+
|
|
7541
|
+
const rect = this.menu.getBoundingClientRect();
|
|
7542
|
+
const viewportWidth = window.innerWidth;
|
|
7543
|
+
const viewportHeight = window.innerHeight;
|
|
7544
|
+
|
|
7545
|
+
if (x + rect.width > viewportWidth) {
|
|
7546
|
+
x = viewportWidth - rect.width - 10;
|
|
7547
|
+
}
|
|
7548
|
+
if (y + rect.height > viewportHeight) {
|
|
7549
|
+
y = viewportHeight - rect.height - 10;
|
|
7550
|
+
}
|
|
7551
|
+
|
|
7552
|
+
this.menu.style.left = x + 'px';
|
|
7553
|
+
this.menu.style.top = y + 'px';
|
|
7554
|
+
}
|
|
7555
|
+
|
|
7556
|
+
hide() {
|
|
7557
|
+
this.menu.style.display = 'none';
|
|
7558
|
+
}
|
|
7559
|
+
|
|
7560
|
+
async executeAction(action) {
|
|
7561
|
+
this.editor.restoreSavedSelection();
|
|
7562
|
+
|
|
7563
|
+
switch (action) {
|
|
7564
|
+
case 'undo':
|
|
7565
|
+
this.editor.commands.undo();
|
|
7566
|
+
break;
|
|
7567
|
+
case 'redo':
|
|
7568
|
+
this.editor.commands.redo();
|
|
7569
|
+
break;
|
|
7570
|
+
case 'cut':
|
|
7571
|
+
document.execCommand('cut');
|
|
7572
|
+
this.editor.history.record();
|
|
7573
|
+
this.editor.triggerChange();
|
|
7574
|
+
break;
|
|
7575
|
+
case 'copy':
|
|
7576
|
+
document.execCommand('copy');
|
|
7577
|
+
break;
|
|
7578
|
+
case 'paste':
|
|
7579
|
+
await this.pasteWithFormatting();
|
|
7580
|
+
break;
|
|
7581
|
+
case 'pasteAsPlainText':
|
|
7582
|
+
await this.pasteAsPlainText();
|
|
7583
|
+
break;
|
|
7584
|
+
case 'selectAll':
|
|
7585
|
+
document.execCommand('selectAll');
|
|
7586
|
+
break;
|
|
7587
|
+
case 'removeFormat':
|
|
7588
|
+
this.editor.commands.removeFormat();
|
|
7589
|
+
break;
|
|
7590
|
+
}
|
|
7591
|
+
}
|
|
7592
|
+
|
|
7593
|
+
async pasteWithFormatting() {
|
|
7594
|
+
try {
|
|
7595
|
+
if (navigator.clipboard && navigator.clipboard.read) {
|
|
7596
|
+
const items = await navigator.clipboard.read();
|
|
7597
|
+
for (const item of items) {
|
|
7598
|
+
if (item.types.includes('text/html')) {
|
|
7599
|
+
const blob = await item.getType('text/html');
|
|
7600
|
+
const html = await blob.text();
|
|
7601
|
+
document.execCommand('insertHTML', false, Utils.sanitizeHTML(html));
|
|
7602
|
+
this.editor.history.record();
|
|
7603
|
+
this.editor.triggerChange();
|
|
7604
|
+
return;
|
|
7605
|
+
}
|
|
7606
|
+
}
|
|
7607
|
+
for (const item of items) {
|
|
7608
|
+
if (item.types.includes('text/plain')) {
|
|
7609
|
+
const blob = await item.getType('text/plain');
|
|
7610
|
+
const text = await blob.text();
|
|
7611
|
+
document.execCommand('insertHTML', false, Utils.escapeHTML(text).replace(/\n/g, '<br>'));
|
|
7612
|
+
this.editor.history.record();
|
|
7613
|
+
this.editor.triggerChange();
|
|
7614
|
+
return;
|
|
7615
|
+
}
|
|
7616
|
+
}
|
|
7617
|
+
} else if (document.execCommand('paste')) {
|
|
7618
|
+
this.editor.history.record();
|
|
7619
|
+
this.editor.triggerChange();
|
|
7620
|
+
}
|
|
7621
|
+
} catch (err) {
|
|
7622
|
+
console.error('NeikiEditor: Paste failed', err);
|
|
7623
|
+
}
|
|
7624
|
+
}
|
|
7625
|
+
|
|
7626
|
+
async pasteAsPlainText() {
|
|
7627
|
+
try {
|
|
7628
|
+
if (!navigator.clipboard || !navigator.clipboard.readText) return;
|
|
7629
|
+
const text = await navigator.clipboard.readText();
|
|
7630
|
+
document.execCommand('insertHTML', false, Utils.escapeHTML(text).replace(/\n/g, '<br>'));
|
|
7631
|
+
this.editor.history.record();
|
|
7632
|
+
this.editor.triggerChange();
|
|
7633
|
+
} catch (err) {
|
|
7634
|
+
console.error('NeikiEditor: Paste as plain text failed', err);
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
}
|
|
7638
|
+
|
|
7265
7639
|
// ============================================
|
|
7266
7640
|
// SECTION 12: EXPORT
|
|
7267
7641
|
// ============================================
|