autumnnote 1.8.0 → 1.8.2

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.
@@ -807,13 +807,74 @@ function _checklistItemToP(checkLi) {
807
807
  } catch {}
808
808
  }
809
809
  /**
810
- * Inserts an unordered list or converts selection.
810
+ * Inserts an unordered (bulleted) list, or converts the current list to `<ul>`.
811
+ *
812
+ * When the cursor is already inside a list, direct DOM manipulation is used to
813
+ * transition between list types — `execCommand` alone cannot handle checklist →
814
+ * UL/OL conversions because it has no awareness of the `an-checklist` class or
815
+ * the checkbox `<input>` elements.
816
+ *
817
+ * Transition paths:
818
+ * - **Checklist → UL**: strips `an-checklist` class and all checkbox inputs;
819
+ * converts `<ol>` container to `<ul>` via `changeTagName()` if needed.
820
+ * - **OL → UL**: swaps the container tag via `changeTagName()`.
821
+ * - **UL → paragraphs**: falls back to `execCommand('insertUnorderedList')`
822
+ * which toggles the list off (browser-native behaviour).
823
+ * - **No list → UL**: falls back to `execCommand('insertUnorderedList')`.
811
824
  */
812
- var insertUnorderedList = () => execCommand("insertUnorderedList");
813
825
  /**
814
- * Inserts an ordered list or converts selection.
826
+ * Helper to get the closest ul/ol element containing the current selection.
827
+ * @returns {Element|null}
815
828
  */
816
- var insertOrderedList = () => execCommand("insertOrderedList");
829
+ function getSelectedList() {
830
+ const sel = globalThis.getSelection();
831
+ if (!sel?.rangeCount) return null;
832
+ let container = sel.getRangeAt(0).commonAncestorContainer;
833
+ if (container.nodeType === 3) container = container.parentElement;
834
+ return container?.closest("ul, ol") || null;
835
+ }
836
+ /**
837
+ * Strips the checklist class and checkbox inputs from a list element.
838
+ * @param {Element} listEl
839
+ */
840
+ function stripChecklist(listEl) {
841
+ listEl.classList.remove("an-checklist");
842
+ listEl.querySelectorAll("input[type=\"checkbox\"]").forEach((cb) => cb.remove());
843
+ }
844
+ function insertUnorderedList() {
845
+ const listEl = getSelectedList();
846
+ if (listEl) if (listEl.classList.contains("an-checklist")) {
847
+ stripChecklist(listEl);
848
+ if (listEl.tagName === "OL") changeTagName(listEl, "ul");
849
+ } else if (listEl.tagName === "OL") changeTagName(listEl, "ul");
850
+ else execCommand("insertUnorderedList");
851
+ else execCommand("insertUnorderedList");
852
+ }
853
+ /**
854
+ * Inserts an ordered (numbered) list, or converts the current list to `<ol>`.
855
+ *
856
+ * When the cursor is already inside a list, direct DOM manipulation is used to
857
+ * transition between list types — `execCommand` alone cannot handle checklist →
858
+ * UL/OL conversions because it has no awareness of the `an-checklist` class or
859
+ * the checkbox `<input>` elements.
860
+ *
861
+ * Transition paths:
862
+ * - **Checklist → OL**: strips `an-checklist` class and all checkbox inputs;
863
+ * converts container to `<ol>` via `changeTagName()`.
864
+ * - **UL → OL**: swaps the container tag via `changeTagName()`.
865
+ * - **OL → paragraphs**: falls back to `execCommand('insertOrderedList')`
866
+ * which toggles the list off (browser-native behaviour).
867
+ * - **No list → OL**: falls back to `execCommand('insertOrderedList')`.
868
+ */
869
+ function insertOrderedList() {
870
+ const listEl = getSelectedList();
871
+ if (listEl) if (listEl.classList.contains("an-checklist")) {
872
+ stripChecklist(listEl);
873
+ changeTagName(listEl, "ol");
874
+ } else if (listEl.tagName === "UL") changeTagName(listEl, "ol");
875
+ else execCommand("insertOrderedList");
876
+ else execCommand("insertOrderedList");
877
+ }
817
878
  /**
818
879
  * Set the line-height on every block-level element that intersects the current selection.
819
880
  *
@@ -939,18 +1000,34 @@ function isInlineCode() {
939
1000
  return !!(code && !code.closest("pre"));
940
1001
  }
941
1002
  /**
1003
+ * Changes the tag name of an element in the DOM while preserving attributes and children.
1004
+ * @param {Element} el
1005
+ * @param {string} newTagName
1006
+ * @returns {HTMLElement}
1007
+ */
1008
+ function changeTagName(el, newTagName) {
1009
+ const newEl = document.createElement(newTagName);
1010
+ for (const attr of el.attributes) newEl.setAttribute(attr.name, attr.value);
1011
+ while (el.firstChild) newEl.appendChild(el.firstChild);
1012
+ el.parentNode.replaceChild(newEl, el);
1013
+ return newEl;
1014
+ }
1015
+ /**
1016
+ * Ensures all list items under the list element have a checkbox.
1017
+ * @param {Element} listEl
1018
+ */
1019
+ function ensureCheckboxes(listEl) {
1020
+ listEl.querySelectorAll("li").forEach((li) => {
1021
+ if (!li.querySelector("input[type=\"checkbox\"]")) {
1022
+ const cb = document.createElement("input");
1023
+ cb.type = "checkbox";
1024
+ cb.contentEditable = "false";
1025
+ li.insertBefore(cb, li.firstChild);
1026
+ }
1027
+ });
1028
+ }
1029
+ /**
942
1030
  * Toggle a checklist at the current selection or caret.
943
- *
944
- * When the selection is inside an existing checklist `<ul class="an-checklist">`,
945
- * converts the selected `<li>` items back into `<p>` paragraphs and places the caret
946
- * at the start of the first converted paragraph. Otherwise creates a checklist:
947
- * - If the selection is collapsed, converts the nearest block-level ancestor (or inserts
948
- * a single checklist item at the editable root) into a checklist with one item containing
949
- * that block's text and places the caret inside the new item.
950
- * - If the selection is a range, converts each intersecting block element into one checklist
951
- * item (preserving textual content) and places the caret at the end of the last item.
952
- *
953
- * Empty or whitespace-only selections do not create a checklist.
954
1031
  */
955
1032
  function toggleChecklist() {
956
1033
  const sel = globalThis.getSelection();
@@ -958,27 +1035,26 @@ function toggleChecklist() {
958
1035
  const range = sel.getRangeAt(0);
959
1036
  let container = range.commonAncestorContainer;
960
1037
  if (container.nodeType === 3) container = container.parentElement;
961
- const ul = container?.closest(".an-checklist");
962
- if (ul) {
963
- const selectedLis = Array.from(ul.querySelectorAll("li")).filter((li) => sel.containsNode(li, true));
964
- if (selectedLis.length > 0) {
965
- /** @type {HTMLElement|null} */ let firstP = null;
966
- selectedLis.forEach((li) => {
1038
+ const listEl = container?.closest("ul, ol");
1039
+ if (listEl) if (listEl.classList.contains("an-checklist")) {
1040
+ if (listEl.parentNode) {
1041
+ const lis = Array.from(listEl.children);
1042
+ let firstP = null;
1043
+ lis.forEach((li) => {
967
1044
  const p = document.createElement("p");
968
1045
  for (const child of li.childNodes) {
969
1046
  if (child.nodeType === 1 && child.tagName === "INPUT") continue;
970
1047
  p.appendChild(child.cloneNode(true));
971
1048
  }
972
- p.innerHTML = p.innerHTML.replaceAll("​", "");
1049
+ p.innerHTML = p.innerHTML.replaceAll("​", "").replaceAll("​", "");
973
1050
  if (!p.hasChildNodes() || !p.textContent.trim()) {
974
1051
  p.innerHTML = "";
975
1052
  p.appendChild(document.createTextNode("\xA0"));
976
1053
  }
977
- ul.parentNode.insertBefore(p, ul);
1054
+ listEl.before(p);
978
1055
  if (!firstP) firstP = p;
979
- li.remove();
980
1056
  });
981
- if (ul.children.length === 0) ul.remove();
1057
+ listEl.remove();
982
1058
  if (firstP) {
983
1059
  const nr = document.createRange();
984
1060
  nr.setStart(firstP.firstChild || firstP, 0);
@@ -986,11 +1062,65 @@ function toggleChecklist() {
986
1062
  sel.removeAllRanges();
987
1063
  sel.addRange(nr);
988
1064
  }
989
- return;
1065
+ }
1066
+ } else {
1067
+ const targetUl = changeTagName(listEl, "ul");
1068
+ targetUl.classList.add("an-checklist");
1069
+ ensureCheckboxes(targetUl);
1070
+ const firstLi = targetUl.querySelector("li");
1071
+ if (firstLi) {
1072
+ const nr = document.createRange();
1073
+ nr.selectNodeContents(firstLi);
1074
+ nr.collapse(false);
1075
+ sel.removeAllRanges();
1076
+ sel.addRange(nr);
990
1077
  }
991
1078
  }
992
- if (range.collapsed) {
993
- const BLOCK_TAGS = new Set([
1079
+ else {
1080
+ const editableRoot = container?.closest("[contenteditable=\"true\"]");
1081
+ if (range.collapsed) {
1082
+ const BLOCK_TAGS = new Set([
1083
+ "P",
1084
+ "DIV",
1085
+ "H1",
1086
+ "H2",
1087
+ "H3",
1088
+ "H4",
1089
+ "H5",
1090
+ "H6",
1091
+ "BLOCKQUOTE",
1092
+ "LI"
1093
+ ]);
1094
+ let block = container;
1095
+ while (block?.parentNode && block !== editableRoot && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
1096
+ if (block === editableRoot) block = null;
1097
+ const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replaceAll("\xA0", " ") : "";
1098
+ const newUl = document.createElement("ul");
1099
+ newUl.className = "an-checklist";
1100
+ const li = document.createElement("li");
1101
+ const checkbox = document.createElement("input");
1102
+ checkbox.type = "checkbox";
1103
+ checkbox.contentEditable = "false";
1104
+ li.appendChild(checkbox);
1105
+ li.appendChild(document.createTextNode(itemText || "​"));
1106
+ newUl.appendChild(li);
1107
+ if (block && BLOCK_TAGS.has(block.tagName)) block.parentNode.replaceChild(newUl, block);
1108
+ else {
1109
+ const nativeRange = sel.getRangeAt(0);
1110
+ nativeRange.deleteContents();
1111
+ nativeRange.insertNode(newUl);
1112
+ }
1113
+ const textNode = li.lastChild;
1114
+ const nr = document.createRange();
1115
+ const offset = textNode.nodeType === Node.TEXT_NODE ? textNode.textContent.length : 0;
1116
+ nr.setStart(textNode, offset);
1117
+ nr.collapse(true);
1118
+ sel.removeAllRanges();
1119
+ sel.addRange(nr);
1120
+ return;
1121
+ }
1122
+ if (!sel.toString().replace(/[\u00a0\u200B]/g, " ").trim()) return;
1123
+ const BLOCK_TAGS_MULTI = new Set([
994
1124
  "P",
995
1125
  "DIV",
996
1126
  "H1",
@@ -1000,89 +1130,51 @@ function toggleChecklist() {
1000
1130
  "H5",
1001
1131
  "H6",
1002
1132
  "BLOCKQUOTE",
1133
+ "PRE",
1003
1134
  "LI"
1004
1135
  ]);
1005
- let block = container;
1006
- while (block?.parentNode && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
1007
- const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replaceAll("\xA0", " ") : "";
1008
- const ul = document.createElement("ul");
1009
- ul.className = "an-checklist";
1010
- const li = document.createElement("li");
1011
- const checkbox = document.createElement("input");
1012
- checkbox.type = "checkbox";
1013
- checkbox.contentEditable = "false";
1014
- li.appendChild(checkbox);
1015
- li.appendChild(document.createTextNode(itemText || "​"));
1016
- ul.appendChild(li);
1017
- if (block && BLOCK_TAGS.has(block.tagName)) block.parentNode.replaceChild(ul, block);
1018
- else {
1019
- const nativeRange = sel.getRangeAt(0);
1020
- nativeRange.deleteContents();
1021
- nativeRange.insertNode(ul);
1136
+ const blocks = [];
1137
+ const seenBlocks = /* @__PURE__ */ new Set();
1138
+ const commonAncestor = range.commonAncestorContainer;
1139
+ const iter = document.createNodeIterator(commonAncestor.nodeType === Node.TEXT_NODE ? commonAncestor.parentNode : commonAncestor, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null);
1140
+ let node;
1141
+ while (node = iter.nextNode()) {
1142
+ if (!range.intersectsNode(node)) continue;
1143
+ let blockEl = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
1144
+ while (blockEl && blockEl !== editableRoot && !BLOCK_TAGS_MULTI.has(blockEl.tagName)) blockEl = blockEl.parentElement;
1145
+ if (blockEl === editableRoot) blockEl = null;
1146
+ if (blockEl && !seenBlocks.has(blockEl)) {
1147
+ seenBlocks.add(blockEl);
1148
+ blocks.push(blockEl);
1149
+ }
1022
1150
  }
1023
- const textNode = li.lastChild;
1024
- const nr = document.createRange();
1025
- const offset = textNode.nodeType === Node.TEXT_NODE ? textNode.textContent.length : 0;
1026
- nr.setStart(textNode, offset);
1027
- nr.collapse(true);
1028
- sel.removeAllRanges();
1029
- sel.addRange(nr);
1030
- return;
1031
- }
1032
- if (!sel.toString().replace(/[\u00a0\u200B]/g, " ").trim()) return;
1033
- const BLOCK_TAGS_MULTI = new Set([
1034
- "P",
1035
- "DIV",
1036
- "H1",
1037
- "H2",
1038
- "H3",
1039
- "H4",
1040
- "H5",
1041
- "H6",
1042
- "BLOCKQUOTE",
1043
- "PRE",
1044
- "LI"
1045
- ]);
1046
- const blocks = [];
1047
- const seenBlocks = /* @__PURE__ */ new Set();
1048
- const commonAncestor = range.commonAncestorContainer;
1049
- const iter = document.createNodeIterator(commonAncestor.nodeType === Node.TEXT_NODE ? commonAncestor.parentNode : commonAncestor, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null);
1050
- let node;
1051
- while (node = iter.nextNode()) {
1052
- if (!range.intersectsNode(node)) continue;
1053
- let block = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
1054
- while (block && !BLOCK_TAGS_MULTI.has(block.tagName)) block = block.parentElement;
1055
- if (block && !seenBlocks.has(block)) {
1056
- seenBlocks.add(block);
1057
- blocks.push(block);
1151
+ if (blocks.length === 0) return;
1152
+ const newUl = document.createElement("ul");
1153
+ newUl.className = "an-checklist";
1154
+ /** @type {Text|null} */ let lastTextNode = null;
1155
+ blocks.forEach((block) => {
1156
+ const li = document.createElement("li");
1157
+ const cb = document.createElement("input");
1158
+ cb.type = "checkbox";
1159
+ cb.contentEditable = "false";
1160
+ li.appendChild(cb);
1161
+ const blockText = Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/[\u00a0\u200B]/g, " ").trim();
1162
+ const tn = document.createTextNode(blockText || "");
1163
+ li.appendChild(tn);
1164
+ newUl.appendChild(li);
1165
+ lastTextNode = tn;
1166
+ });
1167
+ const firstBlock = blocks[0];
1168
+ firstBlock.parentNode.insertBefore(newUl, firstBlock);
1169
+ blocks.forEach((block) => block.remove());
1170
+ if (lastTextNode) {
1171
+ const nr = document.createRange();
1172
+ nr.setStart(lastTextNode, lastTextNode.textContent.length);
1173
+ nr.collapse(true);
1174
+ sel.removeAllRanges();
1175
+ sel.addRange(nr);
1058
1176
  }
1059
1177
  }
1060
- if (blocks.length === 0) return;
1061
- const newUl = document.createElement("ul");
1062
- newUl.className = "an-checklist";
1063
- /** @type {Text|null} */ let lastTextNode = null;
1064
- blocks.forEach((block) => {
1065
- const li = document.createElement("li");
1066
- const cb = document.createElement("input");
1067
- cb.type = "checkbox";
1068
- cb.setAttribute("contenteditable", "false");
1069
- li.appendChild(cb);
1070
- const blockText = Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/[\u00a0\u200B]/g, " ").trim();
1071
- const tn = document.createTextNode(blockText || "​");
1072
- li.appendChild(tn);
1073
- newUl.appendChild(li);
1074
- lastTextNode = tn;
1075
- });
1076
- const firstBlock = blocks[0];
1077
- firstBlock.parentNode.insertBefore(newUl, firstBlock);
1078
- blocks.forEach((block) => block.remove());
1079
- if (lastTextNode) {
1080
- const nr = document.createRange();
1081
- nr.setStart(lastTextNode, lastTextNode.textContent.length);
1082
- nr.collapse(true);
1083
- sel.removeAllRanges();
1084
- sel.addRange(nr);
1085
- }
1086
1178
  }
1087
1179
  /**
1088
1180
  * Returns true when the cursor is inside a checklist item.
@@ -2176,6 +2268,7 @@ var locales = {
2176
2268
  findPlaceholder: "Tìm…",
2177
2269
  searchAriaLabel: "Văn bản tìm kiếm",
2178
2270
  caseSensitive: "\xA0Phân biệt hoa thường",
2271
+ wholeWord: "Toàn bộ từ",
2179
2272
  prevBtn: "← Trước",
2180
2273
  nextBtn: "Tiếp →",
2181
2274
  replacePlaceholder: "Thay thế bằng…",
@@ -2343,9 +2436,16 @@ var locales = {
2343
2436
  columnWidth: "Chiều rộng cột",
2344
2437
  rowHeight: "Chiều cao hàng",
2345
2438
  tableBorderWidth: "Độ rộng viền bảng",
2439
+ tableBorderColor: "Màu viền bảng",
2346
2440
  deleteTable: "Xóa bảng",
2441
+ cellAlignLeft: "Căn trái",
2442
+ cellAlignCenter: "Căn giữa",
2443
+ cellAlignRight: "Căn phải",
2444
+ cellAlignJustify: "Căn đều",
2445
+ toggleHeaderRow: "Bật/tắt hàng tiêu đề",
2347
2446
  cellBackground: "Màu Nền Ô",
2348
2447
  noShading: "Xóa Màu Nền",
2448
+ noBorderColor: "Xóa màu viền",
2349
2449
  columnWidthPx: "Chiều rộng cột (px)",
2350
2450
  rowHeightPx: "Chiều cao hàng (px)",
2351
2451
  tableBorderWidthPx: "Độ rộng viền bảng (px)",
@@ -2522,6 +2622,7 @@ var locales = {
2522
2622
  findPlaceholder: "検索…",
2523
2623
  searchAriaLabel: "検索テキスト",
2524
2624
  caseSensitive: "\xA0大文字/小文字を区別",
2625
+ wholeWord: "単語単位",
2525
2626
  prevBtn: "← 前へ",
2526
2627
  nextBtn: "次へ →",
2527
2628
  replacePlaceholder: "置換後…",
@@ -2689,7 +2790,16 @@ var locales = {
2689
2790
  columnWidth: "列幅",
2690
2791
  rowHeight: "行の高さ",
2691
2792
  tableBorderWidth: "テーブルの枠幅",
2793
+ tableBorderColor: "テーブルの枠線色",
2692
2794
  deleteTable: "テーブルを削除",
2795
+ cellAlignLeft: "左揃え",
2796
+ cellAlignCenter: "中央揃え",
2797
+ cellAlignRight: "右揃え",
2798
+ cellAlignJustify: "両端揃え",
2799
+ toggleHeaderRow: "ヘッダー行の切り替え",
2800
+ cellBackground: "セル背景色",
2801
+ noShading: "背景色なし",
2802
+ noBorderColor: "枠線色なし",
2693
2803
  columnWidthPx: "列幅 (px)",
2694
2804
  rowHeightPx: "行の高さ (px)",
2695
2805
  tableBorderWidthPx: "テーブルの枠幅 (px)",
@@ -2866,6 +2976,7 @@ var locales = {
2866
2976
  findPlaceholder: "查找…",
2867
2977
  searchAriaLabel: "搜索文字",
2868
2978
  caseSensitive: "\xA0区分大小写",
2979
+ wholeWord: "全字匹配",
2869
2980
  prevBtn: "← 上一个",
2870
2981
  nextBtn: "下一个 →",
2871
2982
  replacePlaceholder: "替换为…",
@@ -3033,7 +3144,16 @@ var locales = {
3033
3144
  columnWidth: "列宽",
3034
3145
  rowHeight: "行高",
3035
3146
  tableBorderWidth: "表格边框宽度",
3147
+ tableBorderColor: "表格边框颜色",
3036
3148
  deleteTable: "删除表格",
3149
+ cellAlignLeft: "左对齐",
3150
+ cellAlignCenter: "居中对齐",
3151
+ cellAlignRight: "右对齐",
3152
+ cellAlignJustify: "两端对齐",
3153
+ toggleHeaderRow: "切换标题行",
3154
+ cellBackground: "单元格背景",
3155
+ noShading: "无底纹",
3156
+ noBorderColor: "无边框颜色",
3037
3157
  columnWidthPx: "列宽 (px)",
3038
3158
  rowHeightPx: "行高 (px)",
3039
3159
  tableBorderWidthPx: "表格边框宽度 (px)",
@@ -3210,6 +3330,7 @@ var locales = {
3210
3330
  findPlaceholder: "Rechercher…",
3211
3331
  searchAriaLabel: "Texte à rechercher",
3212
3332
  caseSensitive: "\xA0Respecter la casse",
3333
+ wholeWord: "Mot entier",
3213
3334
  prevBtn: "← Préc.",
3214
3335
  nextBtn: "Suiv. →",
3215
3336
  replacePlaceholder: "Remplacer par…",
@@ -3377,7 +3498,16 @@ var locales = {
3377
3498
  columnWidth: "Largeur de colonne",
3378
3499
  rowHeight: "Hauteur de ligne",
3379
3500
  tableBorderWidth: "Épaisseur des bordures",
3501
+ tableBorderColor: "Couleur de bordure",
3380
3502
  deleteTable: "Supprimer le tableau",
3503
+ cellAlignLeft: "Aligner à gauche",
3504
+ cellAlignCenter: "Centrer",
3505
+ cellAlignRight: "Aligner à droite",
3506
+ cellAlignJustify: "Justifier",
3507
+ toggleHeaderRow: "Ligne d'en-tête",
3508
+ cellBackground: "Couleur de fond",
3509
+ noShading: "Aucun fond",
3510
+ noBorderColor: "Aucune bordure",
3381
3511
  columnWidthPx: "Largeur de colonne (px)",
3382
3512
  rowHeightPx: "Hauteur de ligne (px)",
3383
3513
  tableBorderWidthPx: "Épaisseur des bordures (px)",
@@ -3554,6 +3684,7 @@ var locales = {
3554
3684
  findPlaceholder: "Suchen…",
3555
3685
  searchAriaLabel: "Suchtext",
3556
3686
  caseSensitive: "\xA0Groß-/Kleinschreibung",
3687
+ wholeWord: "Ganzes Wort",
3557
3688
  prevBtn: "← Zurück",
3558
3689
  nextBtn: "Weiter →",
3559
3690
  replacePlaceholder: "Ersetzen durch…",
@@ -3721,7 +3852,16 @@ var locales = {
3721
3852
  columnWidth: "Spaltenbreite",
3722
3853
  rowHeight: "Zeilenhöhe",
3723
3854
  tableBorderWidth: "Tabellenrahmenbreite",
3855
+ tableBorderColor: "Tabellenrahmenfarbe",
3724
3856
  deleteTable: "Tabelle löschen",
3857
+ cellAlignLeft: "Linksbündig",
3858
+ cellAlignCenter: "Zentrieren",
3859
+ cellAlignRight: "Rechtsbündig",
3860
+ cellAlignJustify: "Blocksatz",
3861
+ toggleHeaderRow: "Kopfzeile umschalten",
3862
+ cellBackground: "Zellhintergrund",
3863
+ noShading: "Kein Hintergrund",
3864
+ noBorderColor: "Keine Rahmenfarbe",
3725
3865
  columnWidthPx: "Spaltenbreite (px)",
3726
3866
  rowHeightPx: "Zeilenhöhe (px)",
3727
3867
  tableBorderWidthPx: "Tabellenrahmenbreite (px)",
@@ -3898,6 +4038,7 @@ var locales = {
3898
4038
  findPlaceholder: "Buscar…",
3899
4039
  searchAriaLabel: "Texto de búsqueda",
3900
4040
  caseSensitive: "\xA0Distinguir mayúsculas",
4041
+ wholeWord: "Palabra completa",
3901
4042
  prevBtn: "← Anterior",
3902
4043
  nextBtn: "Siguiente →",
3903
4044
  replacePlaceholder: "Reemplazar con…",
@@ -4065,7 +4206,16 @@ var locales = {
4065
4206
  columnWidth: "Ancho de columna",
4066
4207
  rowHeight: "Alto de fila",
4067
4208
  tableBorderWidth: "Grosor del borde de la tabla",
4209
+ tableBorderColor: "Color del borde de la tabla",
4068
4210
  deleteTable: "Eliminar tabla",
4211
+ cellAlignLeft: "Alinear a la izquierda",
4212
+ cellAlignCenter: "Centrar",
4213
+ cellAlignRight: "Alinear a la derecha",
4214
+ cellAlignJustify: "Justificar",
4215
+ toggleHeaderRow: "Activar fila de encabezado",
4216
+ cellBackground: "Fondo de celda",
4217
+ noShading: "Sin fondo",
4218
+ noBorderColor: "Sin color de borde",
4069
4219
  columnWidthPx: "Ancho de columna (px)",
4070
4220
  rowHeightPx: "Alto de fila (px)",
4071
4221
  tableBorderWidthPx: "Grosor del borde (px)",
@@ -4242,6 +4392,7 @@ var locales = {
4242
4392
  findPlaceholder: "찾기…",
4243
4393
  searchAriaLabel: "검색 텍스트",
4244
4394
  caseSensitive: "\xA0대소문자 구분",
4395
+ wholeWord: "전체 단어",
4245
4396
  prevBtn: "← 이전",
4246
4397
  nextBtn: "다음 →",
4247
4398
  replacePlaceholder: "바꿀 내용…",
@@ -4409,7 +4560,16 @@ var locales = {
4409
4560
  columnWidth: "열 너비",
4410
4561
  rowHeight: "행 높이",
4411
4562
  tableBorderWidth: "표 테두리 너비",
4563
+ tableBorderColor: "표 테두리 색상",
4412
4564
  deleteTable: "표 삭제",
4565
+ cellAlignLeft: "왼쪽 정렬",
4566
+ cellAlignCenter: "가운데 정렬",
4567
+ cellAlignRight: "오른쪽 정렬",
4568
+ cellAlignJustify: "양쪽 정렬",
4569
+ toggleHeaderRow: "머리글 행 전환",
4570
+ cellBackground: "셀 배경색",
4571
+ noShading: "배경 없음",
4572
+ noBorderColor: "테두리 색 없음",
4413
4573
  columnWidthPx: "열 너비 (px)",
4414
4574
  rowHeightPx: "행 높이 (px)",
4415
4575
  tableBorderWidthPx: "표 테두리 너비 (px)",
@@ -4927,7 +5087,11 @@ function insertTable(cols, rows, opts = {}) {
4927
5087
  const sel = globalThis.getSelection();
4928
5088
  if (!sel || sel.rangeCount === 0) return;
4929
5089
  const range = sel.getRangeAt(0);
4930
- range.deleteContents();
5090
+ try {
5091
+ range.deleteContents();
5092
+ } catch (_) {
5093
+ return;
5094
+ }
4931
5095
  const BLOCK = new Set([
4932
5096
  "P",
4933
5097
  "DIV",
@@ -4952,7 +5116,11 @@ function insertTable(cols, rows, opts = {}) {
4952
5116
  table.after(p);
4953
5117
  }
4954
5118
  if (!anchor.textContent.trim() && !anchor.querySelector("img, video, table")) anchor.remove();
4955
- } else range.insertNode(table);
5119
+ } else try {
5120
+ range.insertNode(table);
5121
+ } catch (_) {
5122
+ return;
5123
+ }
4956
5124
  const firstCell = table.querySelector("td, th");
4957
5125
  if (firstCell) {
4958
5126
  const nr = document.createRange();
@@ -5035,6 +5203,23 @@ var _FA_PATTERN = /\bfa-/;
5035
5203
  var isFAIcon = (n) => !!(n?.nodeName === "I" && _FA_PATTERN.test(n.className || ""));
5036
5204
  var isZwsAnchor = (n) => !!(n?.nodeType === Node.TEXT_NODE && (n.textContent === "​" || n.textContent === ""));
5037
5205
  /**
5206
+ * Extracts the content from `startContainer:startOffset` to the end of `li`.
5207
+ * Returns an empty fragment if the range is invalid (e.g. detached node).
5208
+ * @param {Range} nativeRange
5209
+ * @param {Element} li
5210
+ * @returns {DocumentFragment}
5211
+ */
5212
+ function extractAfterContent(nativeRange, li) {
5213
+ try {
5214
+ const r = document.createRange();
5215
+ r.setStart(nativeRange.startContainer, nativeRange.startOffset);
5216
+ r.setEnd(li, li.childNodes.length);
5217
+ return r.extractContents();
5218
+ } catch (_) {
5219
+ return document.createDocumentFragment();
5220
+ }
5221
+ }
5222
+ /**
5038
5223
  * Handles special keydown behaviour inside the editor.
5039
5224
  * @param {KeyboardEvent} event
5040
5225
  * @param {HTMLElement} editable
@@ -5242,12 +5427,10 @@ function handleKeydown(event, editable, options = {}) {
5242
5427
  }
5243
5428
  if (!nativeRange.collapsed) {
5244
5429
  nativeRange.deleteContents();
5430
+ if (sel.rangeCount === 0 || !checkLi.isConnected) return true;
5245
5431
  nativeRange = sel.getRangeAt(0);
5246
5432
  }
5247
- const afterRange = document.createRange();
5248
- afterRange.setStart(nativeRange.startContainer, nativeRange.startOffset);
5249
- afterRange.setEnd(checkLi, checkLi.childNodes.length);
5250
- const afterFrag = afterRange.extractContents();
5433
+ const afterFrag = extractAfterContent(nativeRange, checkLi);
5251
5434
  const newLi = document.createElement("li");
5252
5435
  const cb = document.createElement("input");
5253
5436
  cb.type = "checkbox";
@@ -5363,7 +5546,15 @@ function _domToMd(node, depth = 0) {
5363
5546
  const items = Array.from(el.querySelectorAll(":scope > li"));
5364
5547
  if (!items.length) return inner();
5365
5548
  const indent = " ".repeat(depth);
5366
- const lines = items.map((li) => `${indent}- ${_domToMd(li, depth + 1).trim()}`).join("\n");
5549
+ const isChecklist = el.classList.contains("an-checklist");
5550
+ const lines = items.map((li) => {
5551
+ let prefix = "- ";
5552
+ if (isChecklist) {
5553
+ const cb = li.querySelector("input[type=\"checkbox\"]");
5554
+ prefix = (cb ? cb.checked : false) ? "- [x] " : "- [ ] ";
5555
+ }
5556
+ return `${indent}${prefix}${_domToMd(li, depth + 1).trim()}`;
5557
+ }).join("\n");
5367
5558
  return depth === 0 ? `\n\n${lines}\n\n` : `\n${lines}`;
5368
5559
  }
5369
5560
  case "ol": {
@@ -5403,7 +5594,7 @@ function _domToMd(node, depth = 0) {
5403
5594
  * @returns {boolean} `true` if any Markdown-like pattern is present, `false` otherwise.
5404
5595
  */
5405
5596
  function isMarkdown(text) {
5406
- return /^#{1,6} \S|^\s*[-*+] \S|^\s*\d+\. \S|^> \S|^```|^\*{2}.+?\*{2}/m.test(text);
5597
+ return /^#{1,6} [^\s]|^[ \t]*[-*+] [^\s]|^[ \t]*\d+\. [^\s]|^> [^\s]|^```|^\*{2}[^*\n]+\*{2}/m.test(text);
5407
5598
  }
5408
5599
  /**
5409
5600
  * Converts a Markdown string to an HTML string.
@@ -5453,11 +5644,20 @@ function markdownToHTML(text) {
5453
5644
  }
5454
5645
  if (/^[-*+] /.test(line)) {
5455
5646
  const items = [];
5647
+ const isChecklist = /^[-*+]\s+\[[ xX]\]\s+/.test(line);
5648
+ const listTag = isChecklist ? "ul class=\"an-checklist\"" : "ul";
5456
5649
  while (i < lines.length && /^[-*+] /.test(lines[i])) {
5457
- items.push(`<li>${_inline(lines[i].slice(2))}</li>`);
5650
+ if (/^[-*+]\s+\[[ xX]\]\s+/.test(lines[i]) !== isChecklist) break;
5651
+ const content = lines[i].slice(2);
5652
+ if (isChecklist) {
5653
+ const cbMatch = /^\[([ xX])\][ \t]+/.exec(content);
5654
+ const cbHtml = `<input type="checkbox" contenteditable="false"${cbMatch?.[1]?.toLowerCase() === "x" ? " checked" : ""}>`;
5655
+ const textContent = cbMatch ? content.slice(cbMatch[0].length) : content;
5656
+ items.push(`<li>${cbHtml}${_inline(textContent)}</li>`);
5657
+ } else items.push(`<li>${_inline(content)}</li>`);
5458
5658
  i++;
5459
5659
  }
5460
- out.push(`<ul>${items.join("")}</ul>`);
5660
+ out.push(`<${listTag}>${items.join("")}</${listTag.split(" ")[0]}>`);
5461
5661
  continue;
5462
5662
  }
5463
5663
  if (/^\d+\. /.test(line)) {
@@ -5514,7 +5714,7 @@ function _inline(text) {
5514
5714
  text = text.replace(/_{2}([^_\n]+?)_{2}/g, (_, c) => `<strong>${_esc(c)}</strong>`);
5515
5715
  text = text.replace(/\*([^*\n]+?)\*/g, (_, c) => `<em>${_esc(c)}</em>`);
5516
5716
  text = text.replace(/_([^_\n]+?)_/g, (_, c) => `<em>${_esc(c)}</em>`);
5517
- text = text.replace(/~~([^\n]+?)~~/g, (_, c) => `<del>${_esc(c)}</del>`);
5717
+ text = text.replace(/~~([^~\n]+?)~~/g, (_, c) => `<del>${_esc(c)}</del>`);
5518
5718
  text = text.replace(/`([^`]+)`/g, (_, c) => `<code>${_esc(c)}</code>`);
5519
5719
  return text;
5520
5720
  }
@@ -7213,7 +7413,7 @@ var Clipboard = class {
7213
7413
  const mime = /:(.*?);/.exec(header)?.[1] ?? "image/png";
7214
7414
  const binary = atob(b64);
7215
7415
  const arr = new Uint8Array(binary.length);
7216
- for (let i = 0; i < binary.length; i++) arr[i] = binary.codePointAt(i);
7416
+ for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);
7217
7417
  return new Blob([arr], { type: mime });
7218
7418
  }
7219
7419
  /**
@@ -7819,6 +8019,7 @@ var ImageDialog = class extends BaseDialog {
7819
8019
  return overlay;
7820
8020
  }
7821
8021
  _onFileChange() {
8022
+ if (this.context._alive === false) return;
7822
8023
  const file = this._fileInput?.files?.[0];
7823
8024
  if (!file?.type?.startsWith("image/")) return;
7824
8025
  if (!new Set([
@@ -10384,8 +10585,28 @@ var TableTooltip = class {
10384
10585
  return direction === "asc" ? aText.localeCompare(bText) : bText.localeCompare(aText);
10385
10586
  });
10386
10587
  rows.forEach((row) => tbody.appendChild(row));
10588
+ this._markSortIndicator(table, colIdx, direction);
10387
10589
  this.context.invoke("editor.afterCommand");
10388
10590
  }
10591
+ /**
10592
+ * Marks the header cell of the sorted column with `an-sort-asc`/`an-sort-desc`
10593
+ * so the active sort column and direction are visible, and clears any previous
10594
+ * indicator. No-op for tables without a `<thead>` (no header row to mark).
10595
+ * @param {HTMLTableElement} table
10596
+ * @param {number} colIdx
10597
+ * @param {'asc'|'desc'} direction
10598
+ */
10599
+ _markSortIndicator(table, colIdx, direction) {
10600
+ const thead = table.querySelector("thead");
10601
+ if (!thead) return;
10602
+ thead.querySelectorAll(".an-sort-asc, .an-sort-desc").forEach((el) => {
10603
+ el.classList.remove("an-sort-asc", "an-sort-desc");
10604
+ });
10605
+ const headerRow = thead.querySelector("tr");
10606
+ if (!headerRow) return;
10607
+ const headerCell = getCellAtVisualCol(headerRow, colIdx);
10608
+ if (headerCell) headerCell.classList.add(direction === "asc" ? "an-sort-asc" : "an-sort-desc");
10609
+ }
10389
10610
  _exportTableCSV() {
10390
10611
  const table = this._activeTable;
10391
10612
  if (!table) return;
@@ -16304,6 +16525,7 @@ var BubbleToolbar = class {
16304
16525
  * debounce: 200,
16305
16526
  * onSearch: (query, callback) => void,
16306
16527
  * onInsert: (item) => string | null,
16528
+ * onError: (err: Error) => void,
16307
16529
  * mentionClass: 'an-mention',
16308
16530
  * allowSpaces: false,
16309
16531
  * }
@@ -16341,6 +16563,7 @@ var Mention = class {
16341
16563
  debounce: cfg.debounce ?? 200,
16342
16564
  onSearch: cfg.onSearch,
16343
16565
  onInsert: cfg.onInsert || null,
16566
+ onError: cfg.onError || null,
16344
16567
  mentionClass: cfg.mentionClass || "an-mention",
16345
16568
  allowSpaces: cfg.allowSpaces || false
16346
16569
  };
@@ -16496,7 +16719,14 @@ var Mention = class {
16496
16719
  this._renderItems(items);
16497
16720
  this._showDropdown();
16498
16721
  };
16499
- const result = this._cfg.onSearch(this._query, cb);
16722
+ let result;
16723
+ try {
16724
+ result = this._cfg.onSearch(this._query, cb);
16725
+ } catch (err) {
16726
+ this._hideDropdown();
16727
+ if (typeof this._cfg.onError === "function") this._cfg.onError(err);
16728
+ return;
16729
+ }
16500
16730
  if (result && typeof result.then === "function") result.then(cb).catch((err) => {
16501
16731
  this._hideDropdown();
16502
16732
  if (typeof this._cfg.onError === "function") this._cfg.onError(err);
@@ -17262,7 +17492,7 @@ var AutumnNote = {
17262
17492
  /** All pre-built button definitions — accessible in every module format including UMD/CJS. */
17263
17493
  buttons,
17264
17494
  /** Library version */
17265
- version: "1.8.0"
17495
+ version: "1.8.2"
17266
17496
  };
17267
17497
  /**
17268
17498
  * @param {string|Element|NodeList|Element[]} selector