autumnnote 1.7.0 → 1.8.1
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 +15 -3
- package/dist/autumnnote.css +24 -1
- package/dist/autumnnote.es.js +509 -134
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +587 -195
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/Context.js +26 -1
- package/src/js/core/markdown.js +32 -6
- package/src/js/editing/Style.js +288 -159
- package/src/js/editing/Table.js +10 -2
- package/src/js/editing/Typing.js +21 -4
- package/src/js/i18n/de.js +17 -0
- package/src/js/i18n/en.js +8 -0
- package/src/js/i18n/es.js +17 -0
- package/src/js/i18n/fr.js +18 -1
- package/src/js/i18n/ja.js +17 -0
- package/src/js/i18n/ko.js +17 -0
- package/src/js/i18n/vi.js +15 -0
- package/src/js/i18n/zh.js +17 -0
- package/src/js/index.js +5 -2
- package/src/js/module/Buttons.js +49 -0
- package/src/js/module/Clipboard.js +13 -1
- package/src/js/module/FindReplace.js +24 -5
- package/src/js/module/ImageDialog.js +1 -0
- package/src/js/module/ImageResizer.js +8 -7
- package/src/js/module/Mention.js +13 -2
- package/src/js/module/TableTooltip.js +21 -0
- package/src/styles/autumnnote.scss +23 -3
- package/types/index.d.ts +84 -3
package/dist/autumnnote.es.js
CHANGED
|
@@ -807,13 +807,74 @@ function _checklistItemToP(checkLi) {
|
|
|
807
807
|
} catch {}
|
|
808
808
|
}
|
|
809
809
|
/**
|
|
810
|
-
* Inserts an unordered list or converts
|
|
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')`.
|
|
824
|
+
*/
|
|
825
|
+
/**
|
|
826
|
+
* Helper to get the closest ul/ol element containing the current selection.
|
|
827
|
+
* @returns {Element|null}
|
|
828
|
+
*/
|
|
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
|
|
811
839
|
*/
|
|
812
|
-
|
|
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
|
+
}
|
|
813
853
|
/**
|
|
814
|
-
* Inserts an ordered list or converts
|
|
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')`.
|
|
815
868
|
*/
|
|
816
|
-
|
|
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
|
|
962
|
-
if (
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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
|
-
|
|
1054
|
+
listEl.before(p);
|
|
978
1055
|
if (!firstP) firstP = p;
|
|
979
|
-
li.remove();
|
|
980
1056
|
});
|
|
981
|
-
|
|
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
|
-
|
|
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
|
-
|
|
993
|
-
const
|
|
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
|
-
|
|
1006
|
-
|
|
1007
|
-
const
|
|
1008
|
-
const
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
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
|
-
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
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.
|
|
@@ -1458,6 +1550,48 @@ var defaultToolbar = [
|
|
|
1458
1550
|
shortcutsBtn
|
|
1459
1551
|
]
|
|
1460
1552
|
];
|
|
1553
|
+
var buttons = {
|
|
1554
|
+
boldBtn,
|
|
1555
|
+
italicBtn,
|
|
1556
|
+
underlineBtn,
|
|
1557
|
+
strikeBtn,
|
|
1558
|
+
superscriptBtn,
|
|
1559
|
+
subscriptBtn,
|
|
1560
|
+
alignLeftBtn,
|
|
1561
|
+
alignCenterBtn,
|
|
1562
|
+
alignRightBtn,
|
|
1563
|
+
alignJustifyBtn,
|
|
1564
|
+
ulBtn,
|
|
1565
|
+
olBtn,
|
|
1566
|
+
indentBtn,
|
|
1567
|
+
outdentBtn,
|
|
1568
|
+
undoBtn,
|
|
1569
|
+
redoBtn,
|
|
1570
|
+
hrBtn,
|
|
1571
|
+
linkBtn,
|
|
1572
|
+
imageBtn,
|
|
1573
|
+
videoBtn,
|
|
1574
|
+
emojiBtn,
|
|
1575
|
+
iconBtn,
|
|
1576
|
+
tableBtn,
|
|
1577
|
+
fontSizeBtn,
|
|
1578
|
+
removeFormatBtn,
|
|
1579
|
+
directionBtn,
|
|
1580
|
+
fontFamilyBtn,
|
|
1581
|
+
paragraphStyleBtn,
|
|
1582
|
+
lineHeightBtn,
|
|
1583
|
+
codeviewBtn,
|
|
1584
|
+
fullscreenBtn,
|
|
1585
|
+
shortcutsBtn,
|
|
1586
|
+
findBtn,
|
|
1587
|
+
findReplaceBtn,
|
|
1588
|
+
inlineCodeBtn,
|
|
1589
|
+
checklistBtn,
|
|
1590
|
+
printBtn,
|
|
1591
|
+
foreColorBtn,
|
|
1592
|
+
backColorBtn,
|
|
1593
|
+
defaultToolbar
|
|
1594
|
+
};
|
|
1461
1595
|
//#endregion
|
|
1462
1596
|
//#region src/js/settings.js
|
|
1463
1597
|
/**
|
|
@@ -1752,6 +1886,7 @@ var en = {
|
|
|
1752
1886
|
findPlaceholder: "Find…",
|
|
1753
1887
|
searchAriaLabel: "Search text",
|
|
1754
1888
|
caseSensitive: "\xA0Case sensitive",
|
|
1889
|
+
wholeWord: "Whole Word",
|
|
1755
1890
|
prevBtn: "← Prev",
|
|
1756
1891
|
nextBtn: "Next →",
|
|
1757
1892
|
replacePlaceholder: "Replace with…",
|
|
@@ -1762,6 +1897,12 @@ var en = {
|
|
|
1762
1897
|
useRegex: "Use Regular Expression",
|
|
1763
1898
|
close: "×"
|
|
1764
1899
|
},
|
|
1900
|
+
autoSaveRestore: {
|
|
1901
|
+
found: "Draft found. Restore?",
|
|
1902
|
+
foundAt: "Draft from {date}. Restore?",
|
|
1903
|
+
restore: "Restore",
|
|
1904
|
+
discard: "Discard"
|
|
1905
|
+
},
|
|
1765
1906
|
shortcutsDialog: {
|
|
1766
1907
|
title: "Keyboard Shortcuts",
|
|
1767
1908
|
ariaLabel: "Keyboard Shortcuts",
|
|
@@ -2127,6 +2268,7 @@ var locales = {
|
|
|
2127
2268
|
findPlaceholder: "Tìm…",
|
|
2128
2269
|
searchAriaLabel: "Văn bản tìm kiếm",
|
|
2129
2270
|
caseSensitive: "\xA0Phân biệt hoa thường",
|
|
2271
|
+
wholeWord: "Toàn bộ từ",
|
|
2130
2272
|
prevBtn: "← Trước",
|
|
2131
2273
|
nextBtn: "Tiếp →",
|
|
2132
2274
|
replacePlaceholder: "Thay thế bằng…",
|
|
@@ -2294,9 +2436,16 @@ var locales = {
|
|
|
2294
2436
|
columnWidth: "Chiều rộng cột",
|
|
2295
2437
|
rowHeight: "Chiều cao hàng",
|
|
2296
2438
|
tableBorderWidth: "Độ rộng viền bảng",
|
|
2439
|
+
tableBorderColor: "Màu viền bảng",
|
|
2297
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 đề",
|
|
2298
2446
|
cellBackground: "Màu Nền Ô",
|
|
2299
2447
|
noShading: "Xóa Màu Nền",
|
|
2448
|
+
noBorderColor: "Xóa màu viền",
|
|
2300
2449
|
columnWidthPx: "Chiều rộng cột (px)",
|
|
2301
2450
|
rowHeightPx: "Chiều cao hàng (px)",
|
|
2302
2451
|
tableBorderWidthPx: "Độ rộng viền bảng (px)",
|
|
@@ -2324,6 +2473,12 @@ var locales = {
|
|
|
2324
2473
|
errors: {
|
|
2325
2474
|
imageFormat: (type) => `Định dạng "${type}" không được hỗ trợ hiển thị trên trình duyệt. Vui lòng chuyển đổi sang JPEG, PNG hoặc WebP.`,
|
|
2326
2475
|
imageSize: (maxSize) => `Tệp hình ảnh quá lớn. Kích thước tối đa cho phép là ${maxSize} MB.`
|
|
2476
|
+
},
|
|
2477
|
+
autoSaveRestore: {
|
|
2478
|
+
found: "Tìm thấy bản nháp. Khôi phục?",
|
|
2479
|
+
foundAt: "Bản nháp từ {date}. Khôi phục?",
|
|
2480
|
+
restore: "Khôi phục",
|
|
2481
|
+
discard: "Bỏ qua"
|
|
2327
2482
|
}
|
|
2328
2483
|
},
|
|
2329
2484
|
ja: {
|
|
@@ -2467,6 +2622,7 @@ var locales = {
|
|
|
2467
2622
|
findPlaceholder: "検索…",
|
|
2468
2623
|
searchAriaLabel: "検索テキスト",
|
|
2469
2624
|
caseSensitive: "\xA0大文字/小文字を区別",
|
|
2625
|
+
wholeWord: "単語単位",
|
|
2470
2626
|
prevBtn: "← 前へ",
|
|
2471
2627
|
nextBtn: "次へ →",
|
|
2472
2628
|
replacePlaceholder: "置換後…",
|
|
@@ -2634,7 +2790,16 @@ var locales = {
|
|
|
2634
2790
|
columnWidth: "列幅",
|
|
2635
2791
|
rowHeight: "行の高さ",
|
|
2636
2792
|
tableBorderWidth: "テーブルの枠幅",
|
|
2793
|
+
tableBorderColor: "テーブルの枠線色",
|
|
2637
2794
|
deleteTable: "テーブルを削除",
|
|
2795
|
+
cellAlignLeft: "左揃え",
|
|
2796
|
+
cellAlignCenter: "中央揃え",
|
|
2797
|
+
cellAlignRight: "右揃え",
|
|
2798
|
+
cellAlignJustify: "両端揃え",
|
|
2799
|
+
toggleHeaderRow: "ヘッダー行の切り替え",
|
|
2800
|
+
cellBackground: "セル背景色",
|
|
2801
|
+
noShading: "背景色なし",
|
|
2802
|
+
noBorderColor: "枠線色なし",
|
|
2638
2803
|
columnWidthPx: "列幅 (px)",
|
|
2639
2804
|
rowHeightPx: "行の高さ (px)",
|
|
2640
2805
|
tableBorderWidthPx: "テーブルの枠幅 (px)",
|
|
@@ -2662,6 +2827,12 @@ var locales = {
|
|
|
2662
2827
|
errors: {
|
|
2663
2828
|
imageFormat: (type) => `形式 "${type}" はブラウザでの表示をサポートしていません。JPEG、PNG、または WebP に変換してください。`,
|
|
2664
2829
|
imageSize: (maxSize) => `画像ファイルが大きすぎます。最大許容サイズは ${maxSize} MB です。`
|
|
2830
|
+
},
|
|
2831
|
+
autoSaveRestore: {
|
|
2832
|
+
found: "下書きが見つかりました。復元しますか?",
|
|
2833
|
+
foundAt: "{date} の下書きが見つかりました。復元しますか?",
|
|
2834
|
+
restore: "復元",
|
|
2835
|
+
discard: "破棄"
|
|
2665
2836
|
}
|
|
2666
2837
|
},
|
|
2667
2838
|
zh: {
|
|
@@ -2805,6 +2976,7 @@ var locales = {
|
|
|
2805
2976
|
findPlaceholder: "查找…",
|
|
2806
2977
|
searchAriaLabel: "搜索文字",
|
|
2807
2978
|
caseSensitive: "\xA0区分大小写",
|
|
2979
|
+
wholeWord: "全字匹配",
|
|
2808
2980
|
prevBtn: "← 上一个",
|
|
2809
2981
|
nextBtn: "下一个 →",
|
|
2810
2982
|
replacePlaceholder: "替换为…",
|
|
@@ -2972,7 +3144,16 @@ var locales = {
|
|
|
2972
3144
|
columnWidth: "列宽",
|
|
2973
3145
|
rowHeight: "行高",
|
|
2974
3146
|
tableBorderWidth: "表格边框宽度",
|
|
3147
|
+
tableBorderColor: "表格边框颜色",
|
|
2975
3148
|
deleteTable: "删除表格",
|
|
3149
|
+
cellAlignLeft: "左对齐",
|
|
3150
|
+
cellAlignCenter: "居中对齐",
|
|
3151
|
+
cellAlignRight: "右对齐",
|
|
3152
|
+
cellAlignJustify: "两端对齐",
|
|
3153
|
+
toggleHeaderRow: "切换标题行",
|
|
3154
|
+
cellBackground: "单元格背景",
|
|
3155
|
+
noShading: "无底纹",
|
|
3156
|
+
noBorderColor: "无边框颜色",
|
|
2976
3157
|
columnWidthPx: "列宽 (px)",
|
|
2977
3158
|
rowHeightPx: "行高 (px)",
|
|
2978
3159
|
tableBorderWidthPx: "表格边框宽度 (px)",
|
|
@@ -3000,6 +3181,12 @@ var locales = {
|
|
|
3000
3181
|
errors: {
|
|
3001
3182
|
imageFormat: (type) => `格式 "${type}" 不支持在浏览器中显示。请转换为 JPEG、PNG 或 WebP。`,
|
|
3002
3183
|
imageSize: (maxSize) => `图片文件过大。最大允许大小为 ${maxSize} MB。`
|
|
3184
|
+
},
|
|
3185
|
+
autoSaveRestore: {
|
|
3186
|
+
found: "找到草稿。是否恢复?",
|
|
3187
|
+
foundAt: "发现 {date} 的草稿。是否恢复?",
|
|
3188
|
+
restore: "恢复",
|
|
3189
|
+
discard: "放弃"
|
|
3003
3190
|
}
|
|
3004
3191
|
},
|
|
3005
3192
|
fr: {
|
|
@@ -3143,6 +3330,7 @@ var locales = {
|
|
|
3143
3330
|
findPlaceholder: "Rechercher…",
|
|
3144
3331
|
searchAriaLabel: "Texte à rechercher",
|
|
3145
3332
|
caseSensitive: "\xA0Respecter la casse",
|
|
3333
|
+
wholeWord: "Mot entier",
|
|
3146
3334
|
prevBtn: "← Préc.",
|
|
3147
3335
|
nextBtn: "Suiv. →",
|
|
3148
3336
|
replacePlaceholder: "Remplacer par…",
|
|
@@ -3310,7 +3498,16 @@ var locales = {
|
|
|
3310
3498
|
columnWidth: "Largeur de colonne",
|
|
3311
3499
|
rowHeight: "Hauteur de ligne",
|
|
3312
3500
|
tableBorderWidth: "Épaisseur des bordures",
|
|
3501
|
+
tableBorderColor: "Couleur de bordure",
|
|
3313
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",
|
|
3314
3511
|
columnWidthPx: "Largeur de colonne (px)",
|
|
3315
3512
|
rowHeightPx: "Hauteur de ligne (px)",
|
|
3316
3513
|
tableBorderWidthPx: "Épaisseur des bordures (px)",
|
|
@@ -3338,6 +3535,12 @@ var locales = {
|
|
|
3338
3535
|
errors: {
|
|
3339
3536
|
imageFormat: (type) => `Le format "${type}" n'est pas pris en charge par le navigateur. Veuillez le convertir en JPEG, PNG ou WebP.`,
|
|
3340
3537
|
imageSize: (maxSize) => `Le fichier image est trop volumineux. La taille maximale autorisée est de ${maxSize}\u00a0Mo.`
|
|
3538
|
+
},
|
|
3539
|
+
autoSaveRestore: {
|
|
3540
|
+
found: "Brouillon trouvé. Restaurer ?",
|
|
3541
|
+
foundAt: "Brouillon du {date}. Restaurer ?",
|
|
3542
|
+
restore: "Restaurer",
|
|
3543
|
+
discard: "Ignorer"
|
|
3341
3544
|
}
|
|
3342
3545
|
},
|
|
3343
3546
|
de: {
|
|
@@ -3481,6 +3684,7 @@ var locales = {
|
|
|
3481
3684
|
findPlaceholder: "Suchen…",
|
|
3482
3685
|
searchAriaLabel: "Suchtext",
|
|
3483
3686
|
caseSensitive: "\xA0Groß-/Kleinschreibung",
|
|
3687
|
+
wholeWord: "Ganzes Wort",
|
|
3484
3688
|
prevBtn: "← Zurück",
|
|
3485
3689
|
nextBtn: "Weiter →",
|
|
3486
3690
|
replacePlaceholder: "Ersetzen durch…",
|
|
@@ -3648,7 +3852,16 @@ var locales = {
|
|
|
3648
3852
|
columnWidth: "Spaltenbreite",
|
|
3649
3853
|
rowHeight: "Zeilenhöhe",
|
|
3650
3854
|
tableBorderWidth: "Tabellenrahmenbreite",
|
|
3855
|
+
tableBorderColor: "Tabellenrahmenfarbe",
|
|
3651
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",
|
|
3652
3865
|
columnWidthPx: "Spaltenbreite (px)",
|
|
3653
3866
|
rowHeightPx: "Zeilenhöhe (px)",
|
|
3654
3867
|
tableBorderWidthPx: "Tabellenrahmenbreite (px)",
|
|
@@ -3676,6 +3889,12 @@ var locales = {
|
|
|
3676
3889
|
errors: {
|
|
3677
3890
|
imageFormat: (type) => `Das Format „${type}" wird in Webbrowsern nicht unterstützt. Bitte konvertieren Sie es zuerst in JPEG, PNG oder WebP.`,
|
|
3678
3891
|
imageSize: (maxSize) => `Die Bilddatei ist zu groß. Die maximal zulässige Größe beträgt ${maxSize} MB.`
|
|
3892
|
+
},
|
|
3893
|
+
autoSaveRestore: {
|
|
3894
|
+
found: "Entwurf gefunden. Wiederherstellen?",
|
|
3895
|
+
foundAt: "Entwurf vom {date}. Wiederherstellen?",
|
|
3896
|
+
restore: "Wiederherstellen",
|
|
3897
|
+
discard: "Verwerfen"
|
|
3679
3898
|
}
|
|
3680
3899
|
},
|
|
3681
3900
|
es: {
|
|
@@ -3819,6 +4038,7 @@ var locales = {
|
|
|
3819
4038
|
findPlaceholder: "Buscar…",
|
|
3820
4039
|
searchAriaLabel: "Texto de búsqueda",
|
|
3821
4040
|
caseSensitive: "\xA0Distinguir mayúsculas",
|
|
4041
|
+
wholeWord: "Palabra completa",
|
|
3822
4042
|
prevBtn: "← Anterior",
|
|
3823
4043
|
nextBtn: "Siguiente →",
|
|
3824
4044
|
replacePlaceholder: "Reemplazar con…",
|
|
@@ -3986,7 +4206,16 @@ var locales = {
|
|
|
3986
4206
|
columnWidth: "Ancho de columna",
|
|
3987
4207
|
rowHeight: "Alto de fila",
|
|
3988
4208
|
tableBorderWidth: "Grosor del borde de la tabla",
|
|
4209
|
+
tableBorderColor: "Color del borde de la tabla",
|
|
3989
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",
|
|
3990
4219
|
columnWidthPx: "Ancho de columna (px)",
|
|
3991
4220
|
rowHeightPx: "Alto de fila (px)",
|
|
3992
4221
|
tableBorderWidthPx: "Grosor del borde (px)",
|
|
@@ -4014,6 +4243,12 @@ var locales = {
|
|
|
4014
4243
|
errors: {
|
|
4015
4244
|
imageFormat: (type) => `El formato "${type}" no es compatible con los navegadores web. Por favor, conviértalo primero a JPEG, PNG o WebP.`,
|
|
4016
4245
|
imageSize: (maxSize) => `El archivo de imagen es demasiado grande. El tamaño máximo permitido es ${maxSize} MB.`
|
|
4246
|
+
},
|
|
4247
|
+
autoSaveRestore: {
|
|
4248
|
+
found: "Borrador encontrado. ¿Restaurar?",
|
|
4249
|
+
foundAt: "Borrador del {date}. ¿Restaurar?",
|
|
4250
|
+
restore: "Restaurar",
|
|
4251
|
+
discard: "Descartar"
|
|
4017
4252
|
}
|
|
4018
4253
|
},
|
|
4019
4254
|
ko: {
|
|
@@ -4157,6 +4392,7 @@ var locales = {
|
|
|
4157
4392
|
findPlaceholder: "찾기…",
|
|
4158
4393
|
searchAriaLabel: "검색 텍스트",
|
|
4159
4394
|
caseSensitive: "\xA0대소문자 구분",
|
|
4395
|
+
wholeWord: "전체 단어",
|
|
4160
4396
|
prevBtn: "← 이전",
|
|
4161
4397
|
nextBtn: "다음 →",
|
|
4162
4398
|
replacePlaceholder: "바꿀 내용…",
|
|
@@ -4324,7 +4560,16 @@ var locales = {
|
|
|
4324
4560
|
columnWidth: "열 너비",
|
|
4325
4561
|
rowHeight: "행 높이",
|
|
4326
4562
|
tableBorderWidth: "표 테두리 너비",
|
|
4563
|
+
tableBorderColor: "표 테두리 색상",
|
|
4327
4564
|
deleteTable: "표 삭제",
|
|
4565
|
+
cellAlignLeft: "왼쪽 정렬",
|
|
4566
|
+
cellAlignCenter: "가운데 정렬",
|
|
4567
|
+
cellAlignRight: "오른쪽 정렬",
|
|
4568
|
+
cellAlignJustify: "양쪽 정렬",
|
|
4569
|
+
toggleHeaderRow: "머리글 행 전환",
|
|
4570
|
+
cellBackground: "셀 배경색",
|
|
4571
|
+
noShading: "배경 없음",
|
|
4572
|
+
noBorderColor: "테두리 색 없음",
|
|
4328
4573
|
columnWidthPx: "열 너비 (px)",
|
|
4329
4574
|
rowHeightPx: "행 높이 (px)",
|
|
4330
4575
|
tableBorderWidthPx: "표 테두리 너비 (px)",
|
|
@@ -4352,6 +4597,12 @@ var locales = {
|
|
|
4352
4597
|
errors: {
|
|
4353
4598
|
imageFormat: (type) => `"${type}" 형식은 웹 브라우저에서 지원되지 않습니다. JPEG, PNG 또는 WebP로 변환해 주세요.`,
|
|
4354
4599
|
imageSize: (maxSize) => `이미지 파일이 너무 큽니다. 최대 허용 크기는 ${maxSize} MB입니다.`
|
|
4600
|
+
},
|
|
4601
|
+
autoSaveRestore: {
|
|
4602
|
+
found: "초안을 찾았습니다. 복원하시겠습니까?",
|
|
4603
|
+
foundAt: "{date}의 초안을 찾았습니다. 복원하시겠습니까?",
|
|
4604
|
+
restore: "복원",
|
|
4605
|
+
discard: "삭제"
|
|
4355
4606
|
}
|
|
4356
4607
|
}
|
|
4357
4608
|
};
|
|
@@ -4836,7 +5087,11 @@ function insertTable(cols, rows, opts = {}) {
|
|
|
4836
5087
|
const sel = globalThis.getSelection();
|
|
4837
5088
|
if (!sel || sel.rangeCount === 0) return;
|
|
4838
5089
|
const range = sel.getRangeAt(0);
|
|
4839
|
-
|
|
5090
|
+
try {
|
|
5091
|
+
range.deleteContents();
|
|
5092
|
+
} catch (_) {
|
|
5093
|
+
return;
|
|
5094
|
+
}
|
|
4840
5095
|
const BLOCK = new Set([
|
|
4841
5096
|
"P",
|
|
4842
5097
|
"DIV",
|
|
@@ -4861,7 +5116,11 @@ function insertTable(cols, rows, opts = {}) {
|
|
|
4861
5116
|
table.after(p);
|
|
4862
5117
|
}
|
|
4863
5118
|
if (!anchor.textContent.trim() && !anchor.querySelector("img, video, table")) anchor.remove();
|
|
4864
|
-
} else
|
|
5119
|
+
} else try {
|
|
5120
|
+
range.insertNode(table);
|
|
5121
|
+
} catch (_) {
|
|
5122
|
+
return;
|
|
5123
|
+
}
|
|
4865
5124
|
const firstCell = table.querySelector("td, th");
|
|
4866
5125
|
if (firstCell) {
|
|
4867
5126
|
const nr = document.createRange();
|
|
@@ -4944,6 +5203,23 @@ var _FA_PATTERN = /\bfa-/;
|
|
|
4944
5203
|
var isFAIcon = (n) => !!(n?.nodeName === "I" && _FA_PATTERN.test(n.className || ""));
|
|
4945
5204
|
var isZwsAnchor = (n) => !!(n?.nodeType === Node.TEXT_NODE && (n.textContent === "" || n.textContent === ""));
|
|
4946
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
|
+
/**
|
|
4947
5223
|
* Handles special keydown behaviour inside the editor.
|
|
4948
5224
|
* @param {KeyboardEvent} event
|
|
4949
5225
|
* @param {HTMLElement} editable
|
|
@@ -5151,12 +5427,10 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
5151
5427
|
}
|
|
5152
5428
|
if (!nativeRange.collapsed) {
|
|
5153
5429
|
nativeRange.deleteContents();
|
|
5430
|
+
if (sel.rangeCount === 0 || !checkLi.isConnected) return true;
|
|
5154
5431
|
nativeRange = sel.getRangeAt(0);
|
|
5155
5432
|
}
|
|
5156
|
-
const
|
|
5157
|
-
afterRange.setStart(nativeRange.startContainer, nativeRange.startOffset);
|
|
5158
|
-
afterRange.setEnd(checkLi, checkLi.childNodes.length);
|
|
5159
|
-
const afterFrag = afterRange.extractContents();
|
|
5433
|
+
const afterFrag = extractAfterContent(nativeRange, checkLi);
|
|
5160
5434
|
const newLi = document.createElement("li");
|
|
5161
5435
|
const cb = document.createElement("input");
|
|
5162
5436
|
cb.type = "checkbox";
|
|
@@ -5272,7 +5546,15 @@ function _domToMd(node, depth = 0) {
|
|
|
5272
5546
|
const items = Array.from(el.querySelectorAll(":scope > li"));
|
|
5273
5547
|
if (!items.length) return inner();
|
|
5274
5548
|
const indent = " ".repeat(depth);
|
|
5275
|
-
const
|
|
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");
|
|
5276
5558
|
return depth === 0 ? `\n\n${lines}\n\n` : `\n${lines}`;
|
|
5277
5559
|
}
|
|
5278
5560
|
case "ol": {
|
|
@@ -5312,7 +5594,7 @@ function _domToMd(node, depth = 0) {
|
|
|
5312
5594
|
* @returns {boolean} `true` if any Markdown-like pattern is present, `false` otherwise.
|
|
5313
5595
|
*/
|
|
5314
5596
|
function isMarkdown(text) {
|
|
5315
|
-
return /^#{1,6} \
|
|
5597
|
+
return /^#{1,6} [^\s]|^[ \t]*[-*+] [^\s]|^[ \t]*\d+\. [^\s]|^> [^\s]|^```|^\*{2}[^*\n]+\*{2}/m.test(text);
|
|
5316
5598
|
}
|
|
5317
5599
|
/**
|
|
5318
5600
|
* Converts a Markdown string to an HTML string.
|
|
@@ -5362,11 +5644,20 @@ function markdownToHTML(text) {
|
|
|
5362
5644
|
}
|
|
5363
5645
|
if (/^[-*+] /.test(line)) {
|
|
5364
5646
|
const items = [];
|
|
5647
|
+
const isChecklist = /^[-*+]\s+\[[ xX]\]\s+/.test(line);
|
|
5648
|
+
const listTag = isChecklist ? "ul class=\"an-checklist\"" : "ul";
|
|
5365
5649
|
while (i < lines.length && /^[-*+] /.test(lines[i])) {
|
|
5366
|
-
|
|
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>`);
|
|
5367
5658
|
i++;
|
|
5368
5659
|
}
|
|
5369
|
-
out.push(
|
|
5660
|
+
out.push(`<${listTag}>${items.join("")}</${listTag.split(" ")[0]}>`);
|
|
5370
5661
|
continue;
|
|
5371
5662
|
}
|
|
5372
5663
|
if (/^\d+\. /.test(line)) {
|
|
@@ -5423,7 +5714,7 @@ function _inline(text) {
|
|
|
5423
5714
|
text = text.replace(/_{2}([^_\n]+?)_{2}/g, (_, c) => `<strong>${_esc(c)}</strong>`);
|
|
5424
5715
|
text = text.replace(/\*([^*\n]+?)\*/g, (_, c) => `<em>${_esc(c)}</em>`);
|
|
5425
5716
|
text = text.replace(/_([^_\n]+?)_/g, (_, c) => `<em>${_esc(c)}</em>`);
|
|
5426
|
-
text = text.replace(/~~([
|
|
5717
|
+
text = text.replace(/~~([^~\n]+?)~~/g, (_, c) => `<del>${_esc(c)}</del>`);
|
|
5427
5718
|
text = text.replace(/`([^`]+)`/g, (_, c) => `<code>${_esc(c)}</code>`);
|
|
5428
5719
|
return text;
|
|
5429
5720
|
}
|
|
@@ -6977,6 +7268,15 @@ var Clipboard = class {
|
|
|
6977
7268
|
if (!clipboardData) return;
|
|
6978
7269
|
const forcePlain = this._forcePlain;
|
|
6979
7270
|
this._forcePlain = false;
|
|
7271
|
+
const maxBytes = (this.options.maxPasteSize ?? 5) * 1024 * 1024;
|
|
7272
|
+
if (maxBytes > 0) {
|
|
7273
|
+
const text = clipboardData.getData("text/plain") || "";
|
|
7274
|
+
const html = clipboardData.getData("text/html") || "";
|
|
7275
|
+
if (Math.max(text.length, html.length) > maxBytes) {
|
|
7276
|
+
event.preventDefault();
|
|
7277
|
+
return;
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
6980
7280
|
if (clipboardData.items) {
|
|
6981
7281
|
const imageItems = Array.from(clipboardData.items).filter((item) => item.kind === "file" && item.type.startsWith("image/"));
|
|
6982
7282
|
if (imageItems.length > 0) {
|
|
@@ -7113,7 +7413,7 @@ var Clipboard = class {
|
|
|
7113
7413
|
const mime = /:(.*?);/.exec(header)?.[1] ?? "image/png";
|
|
7114
7414
|
const binary = atob(b64);
|
|
7115
7415
|
const arr = new Uint8Array(binary.length);
|
|
7116
|
-
for (let i = 0; i < binary.length; i++) arr[i] = binary.
|
|
7416
|
+
for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);
|
|
7117
7417
|
return new Blob([arr], { type: mime });
|
|
7118
7418
|
}
|
|
7119
7419
|
/**
|
|
@@ -7719,6 +8019,7 @@ var ImageDialog = class extends BaseDialog {
|
|
|
7719
8019
|
return overlay;
|
|
7720
8020
|
}
|
|
7721
8021
|
_onFileChange() {
|
|
8022
|
+
if (this.context._alive === false) return;
|
|
7722
8023
|
const file = this._fileInput?.files?.[0];
|
|
7723
8024
|
if (!file?.type?.startsWith("image/")) return;
|
|
7724
8025
|
if (!new Set([
|
|
@@ -8099,6 +8400,7 @@ var ImageResizer = class {
|
|
|
8099
8400
|
const aspectRatio = startW / (startH || 1);
|
|
8100
8401
|
const isCorner = pos.length === 2;
|
|
8101
8402
|
const editable = this.context.layoutInfo.editable;
|
|
8403
|
+
const minSz = this.context.options?.minImageSize ?? 20;
|
|
8102
8404
|
let _raf = null;
|
|
8103
8405
|
const onMove = (me) => {
|
|
8104
8406
|
if (_raf !== null) return;
|
|
@@ -8111,15 +8413,15 @@ var ImageResizer = class {
|
|
|
8111
8413
|
const maxW = editable.clientWidth || Infinity;
|
|
8112
8414
|
let newW = startW;
|
|
8113
8415
|
let newH = startH;
|
|
8114
|
-
if (pos.includes("e")) newW = Math.max(
|
|
8115
|
-
if (pos.includes("w")) newW = Math.max(
|
|
8116
|
-
if (pos.includes("s")) newH = Math.max(
|
|
8117
|
-
if (pos.includes("n")) newH = Math.max(
|
|
8416
|
+
if (pos.includes("e")) newW = Math.max(minSz, startW + dx);
|
|
8417
|
+
if (pos.includes("w")) newW = Math.max(minSz, startW - dx);
|
|
8418
|
+
if (pos.includes("s")) newH = Math.max(minSz, startH + dy);
|
|
8419
|
+
if (pos.includes("n")) newH = Math.max(minSz, startH - dy);
|
|
8118
8420
|
newW = Math.min(newW, maxW);
|
|
8119
|
-
if (isCorner) if (Math.abs(dx) >= Math.abs(dy)) newH = Math.max(
|
|
8421
|
+
if (isCorner) if (Math.abs(dx) >= Math.abs(dy)) newH = Math.max(minSz, Math.round(newW / aspectRatio));
|
|
8120
8422
|
else {
|
|
8121
|
-
newW = Math.min(Math.max(
|
|
8122
|
-
newH = Math.max(
|
|
8423
|
+
newW = Math.min(Math.max(minSz, Math.round(newH * aspectRatio)), maxW);
|
|
8424
|
+
newH = Math.max(minSz, Math.round(newW / aspectRatio));
|
|
8123
8425
|
}
|
|
8124
8426
|
img.style.width = `${newW}px`;
|
|
8125
8427
|
img.style.height = `${newH}px`;
|
|
@@ -10283,8 +10585,28 @@ var TableTooltip = class {
|
|
|
10283
10585
|
return direction === "asc" ? aText.localeCompare(bText) : bText.localeCompare(aText);
|
|
10284
10586
|
});
|
|
10285
10587
|
rows.forEach((row) => tbody.appendChild(row));
|
|
10588
|
+
this._markSortIndicator(table, colIdx, direction);
|
|
10286
10589
|
this.context.invoke("editor.afterCommand");
|
|
10287
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
|
+
}
|
|
10288
10610
|
_exportTableCSV() {
|
|
10289
10611
|
const table = this._activeTable;
|
|
10290
10612
|
if (!table) return;
|
|
@@ -14562,6 +14884,7 @@ var FindReplace = class extends BaseDialog {
|
|
|
14562
14884
|
this._currentIndex = -1;
|
|
14563
14885
|
this._caseSensitive = false;
|
|
14564
14886
|
this._useRegex = false;
|
|
14887
|
+
this._wholeWord = false;
|
|
14565
14888
|
/** @type {'find'|'replace'} */
|
|
14566
14889
|
this._mode = "find";
|
|
14567
14890
|
/** Cached compiled regex — reused when query and case-sensitivity are unchanged */
|
|
@@ -14569,6 +14892,7 @@ var FindReplace = class extends BaseDialog {
|
|
|
14569
14892
|
this._lastQuery = null;
|
|
14570
14893
|
this._lastCaseSensitive = null;
|
|
14571
14894
|
this._lastUseRegex = null;
|
|
14895
|
+
this._lastWholeWord = null;
|
|
14572
14896
|
this._focusTimer = null;
|
|
14573
14897
|
}
|
|
14574
14898
|
destroy() {
|
|
@@ -14679,6 +15003,13 @@ var FindReplace = class extends BaseDialog {
|
|
|
14679
15003
|
"aria-label": L.useRegex
|
|
14680
15004
|
});
|
|
14681
15005
|
regexBtn.textContent = ".*";
|
|
15006
|
+
const wholeWordBtn = createElement("button", {
|
|
15007
|
+
type: "button",
|
|
15008
|
+
class: "an-fr-icon-btn",
|
|
15009
|
+
title: L.wholeWord,
|
|
15010
|
+
"aria-label": L.wholeWord
|
|
15011
|
+
});
|
|
15012
|
+
wholeWordBtn.innerHTML = `<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"><rect x="3" y="7" width="18" height="10" rx="2"/><line x1="7" y1="21" x2="7" y2="17"/><line x1="17" y1="21" x2="17" y2="17"/></svg>`;
|
|
14682
15013
|
const prevBtn = createElement("button", {
|
|
14683
15014
|
type: "button",
|
|
14684
15015
|
class: "an-fr-icon-btn",
|
|
@@ -14695,7 +15026,7 @@ var FindReplace = class extends BaseDialog {
|
|
|
14695
15026
|
nextBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>`;
|
|
14696
15027
|
const counter = createElement("span", { class: "an-fr-counter" });
|
|
14697
15028
|
this._counterEl = counter;
|
|
14698
|
-
searchBar.append(findInput, caseCheckbox, caseBtn, regexBtn, prevBtn, nextBtn, counter);
|
|
15029
|
+
searchBar.append(findInput, caseCheckbox, caseBtn, regexBtn, wholeWordBtn, prevBtn, nextBtn, counter);
|
|
14699
15030
|
box.appendChild(searchBar);
|
|
14700
15031
|
const replaceRow = createElement("div", { class: "an-fr-replace-row" });
|
|
14701
15032
|
replaceRow.style.display = "none";
|
|
@@ -14763,7 +15094,14 @@ var FindReplace = class extends BaseDialog {
|
|
|
14763
15094
|
this._lastQuery = null;
|
|
14764
15095
|
this._onSearch();
|
|
14765
15096
|
});
|
|
14766
|
-
|
|
15097
|
+
const dWholeWord = on(wholeWordBtn, "click", () => {
|
|
15098
|
+
this._wholeWord = !this._wholeWord;
|
|
15099
|
+
wholeWordBtn.classList.toggle("an-fr-icon-btn--active", this._wholeWord);
|
|
15100
|
+
this._queryRegex = null;
|
|
15101
|
+
this._lastQuery = null;
|
|
15102
|
+
this._onSearch();
|
|
15103
|
+
});
|
|
15104
|
+
this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, dRegex, dWholeWord);
|
|
14767
15105
|
return overlay;
|
|
14768
15106
|
}
|
|
14769
15107
|
_onSearch() {
|
|
@@ -14821,10 +15159,11 @@ var FindReplace = class extends BaseDialog {
|
|
|
14821
15159
|
*/
|
|
14822
15160
|
_findRawMatches(query, root) {
|
|
14823
15161
|
const results = [];
|
|
14824
|
-
if (this._lastQuery !== query || this._lastCaseSensitive !== this._caseSensitive || this._lastUseRegex !== this._useRegex) {
|
|
15162
|
+
if (this._lastQuery !== query || this._lastCaseSensitive !== this._caseSensitive || this._lastUseRegex !== this._useRegex || this._lastWholeWord !== this._wholeWord) {
|
|
14825
15163
|
const flags = this._caseSensitive ? "g" : "gi";
|
|
14826
15164
|
try {
|
|
14827
|
-
|
|
15165
|
+
let pattern = this._useRegex ? query : query.replace(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
15166
|
+
if (this._wholeWord) pattern = `\\b${pattern}\\b`;
|
|
14828
15167
|
this._queryRegex = new RegExp(pattern, flags);
|
|
14829
15168
|
} catch (_) {
|
|
14830
15169
|
this._queryRegex = null;
|
|
@@ -14832,6 +15171,7 @@ var FindReplace = class extends BaseDialog {
|
|
|
14832
15171
|
this._lastQuery = query;
|
|
14833
15172
|
this._lastCaseSensitive = this._caseSensitive;
|
|
14834
15173
|
this._lastUseRegex = this._useRegex;
|
|
15174
|
+
this._lastWholeWord = this._wholeWord;
|
|
14835
15175
|
}
|
|
14836
15176
|
if (!this._queryRegex) return results;
|
|
14837
15177
|
const re = this._queryRegex;
|
|
@@ -16185,6 +16525,7 @@ var BubbleToolbar = class {
|
|
|
16185
16525
|
* debounce: 200,
|
|
16186
16526
|
* onSearch: (query, callback) => void,
|
|
16187
16527
|
* onInsert: (item) => string | null,
|
|
16528
|
+
* onError: (err: Error) => void,
|
|
16188
16529
|
* mentionClass: 'an-mention',
|
|
16189
16530
|
* allowSpaces: false,
|
|
16190
16531
|
* }
|
|
@@ -16377,8 +16718,18 @@ var Mention = class {
|
|
|
16377
16718
|
this._renderItems(items);
|
|
16378
16719
|
this._showDropdown();
|
|
16379
16720
|
};
|
|
16380
|
-
|
|
16381
|
-
|
|
16721
|
+
let result;
|
|
16722
|
+
try {
|
|
16723
|
+
result = this._cfg.onSearch(this._query, cb);
|
|
16724
|
+
} catch (err) {
|
|
16725
|
+
this._hideDropdown();
|
|
16726
|
+
if (typeof this._cfg.onError === "function") this._cfg.onError(err);
|
|
16727
|
+
return;
|
|
16728
|
+
}
|
|
16729
|
+
if (result && typeof result.then === "function") result.then(cb).catch((err) => {
|
|
16730
|
+
this._hideDropdown();
|
|
16731
|
+
if (typeof this._cfg.onError === "function") this._cfg.onError(err);
|
|
16732
|
+
});
|
|
16382
16733
|
}, this._cfg.debounce);
|
|
16383
16734
|
}
|
|
16384
16735
|
_onKeydown(e) {
|
|
@@ -16646,10 +16997,13 @@ var Context = class {
|
|
|
16646
16997
|
}
|
|
16647
16998
|
/**
|
|
16648
16999
|
* Returns the current HTML content of the editor.
|
|
17000
|
+
* Zero-width spaces (U+200B) inserted by inline editing helpers are stripped
|
|
17001
|
+
* from the output so they don't leak into the consumer's HTML.
|
|
16649
17002
|
* @returns {string}
|
|
16650
17003
|
*/
|
|
16651
17004
|
getHTML() {
|
|
16652
|
-
|
|
17005
|
+
const html = this.invoke("editor.getHTML");
|
|
17006
|
+
return typeof html === "string" ? html.replace(//g, "") : html;
|
|
16653
17007
|
}
|
|
16654
17008
|
/**
|
|
16655
17009
|
* Sets the HTML content of the editor.
|
|
@@ -16820,6 +17174,25 @@ var Context = class {
|
|
|
16820
17174
|
}));
|
|
16821
17175
|
}
|
|
16822
17176
|
/**
|
|
17177
|
+
* Moves focus into the editable area.
|
|
17178
|
+
*/
|
|
17179
|
+
focus() {
|
|
17180
|
+
this.layoutInfo.editable.focus();
|
|
17181
|
+
}
|
|
17182
|
+
/**
|
|
17183
|
+
* Removes focus from the editable area.
|
|
17184
|
+
*/
|
|
17185
|
+
blur() {
|
|
17186
|
+
this.layoutInfo.editable.blur();
|
|
17187
|
+
}
|
|
17188
|
+
/**
|
|
17189
|
+
* Returns true when the editor is currently in fullscreen mode.
|
|
17190
|
+
* @returns {boolean}
|
|
17191
|
+
*/
|
|
17192
|
+
isFullscreen() {
|
|
17193
|
+
return this.invoke("fullscreen.isActive") === true;
|
|
17194
|
+
}
|
|
17195
|
+
/**
|
|
16823
17196
|
* Sets whether the editor is disabled (readonly).
|
|
16824
17197
|
* @param {boolean} disabled
|
|
16825
17198
|
*/
|
|
@@ -17115,8 +17488,10 @@ var AutumnNote = {
|
|
|
17115
17488
|
registerButton(btnDef);
|
|
17116
17489
|
return this;
|
|
17117
17490
|
},
|
|
17491
|
+
/** All pre-built button definitions — accessible in every module format including UMD/CJS. */
|
|
17492
|
+
buttons,
|
|
17118
17493
|
/** Library version */
|
|
17119
|
-
version: "1.
|
|
17494
|
+
version: "1.8.0"
|
|
17120
17495
|
};
|
|
17121
17496
|
/**
|
|
17122
17497
|
* @param {string|Element|NodeList|Element[]} selector
|
|
@@ -17129,6 +17504,6 @@ function resolveElements(selector) {
|
|
|
17129
17504
|
return [];
|
|
17130
17505
|
}
|
|
17131
17506
|
//#endregion
|
|
17132
|
-
export { Context, ELEMENT_NODE, TEXT_NODE, WrappedRange, _buttonRegistry, alignCenterBtn, alignJustifyBtn, alignLeftBtn, alignRightBtn, all, ancestors, any, backColorBtn, boldBtn, checklistBtn, children, chunk, clamp, closest, closestPara, codeviewBtn, collapsedRange, compose, createElement, currentRange, debounce, AutumnNote as default, defaultOptions, defaultToolbar, directionBtn, emojiBtn, env, findBtn, findReplaceBtn, first, flatten, fontFamilyBtn, fontSizeBtn, foreColorBtn, fromNativeRange, fullscreenBtn, getButton, groupBy, hrBtn, iconBtn, identity, imageBtn, indentBtn, initial, inlineCodeBtn, insertAfter, isAnchor, isEditable, isElement, isEmpty, isFunction, isImage, isInline, isInsideEditable, isKey, isLi, isList, isModifier, isNil, isPara, isPlainObject, isSelectionInside, isString, isTable, isText, isVoid, italicBtn, key, last, lineHeightBtn, linkBtn, locales, makeDraggable, mergeDeep, nextElement, nodeValue, olBtn, on, outdentBtn, outerHtml, paragraphStyleBtn, placeCaret, prevElement, printBtn, rangeFromElement, rect2bnd, redoBtn, registerButton, remove, removeFormatBtn, resolveLocale, sanitiseHTML, sanitiseUrl, shortcutsBtn, splitText, strikeBtn, subscriptBtn, superscriptBtn, tableBtn, tail, throttle, trapFocus, ulBtn, underlineBtn, undoBtn, unique, unwrap, videoBtn, withSavedRange, wrap };
|
|
17507
|
+
export { Context, ELEMENT_NODE, TEXT_NODE, WrappedRange, _buttonRegistry, alignCenterBtn, alignJustifyBtn, alignLeftBtn, alignRightBtn, all, ancestors, any, backColorBtn, boldBtn, buttons, checklistBtn, children, chunk, clamp, closest, closestPara, codeviewBtn, collapsedRange, compose, createElement, currentRange, debounce, AutumnNote as default, defaultOptions, defaultToolbar, directionBtn, emojiBtn, env, findBtn, findReplaceBtn, first, flatten, fontFamilyBtn, fontSizeBtn, foreColorBtn, fromNativeRange, fullscreenBtn, getButton, groupBy, hrBtn, iconBtn, identity, imageBtn, indentBtn, initial, inlineCodeBtn, insertAfter, isAnchor, isEditable, isElement, isEmpty, isFunction, isImage, isInline, isInsideEditable, isKey, isLi, isList, isModifier, isNil, isPara, isPlainObject, isSelectionInside, isString, isTable, isText, isVoid, italicBtn, key, last, lineHeightBtn, linkBtn, locales, makeDraggable, mergeDeep, nextElement, nodeValue, olBtn, on, outdentBtn, outerHtml, paragraphStyleBtn, placeCaret, prevElement, printBtn, rangeFromElement, rect2bnd, redoBtn, registerButton, remove, removeFormatBtn, resolveLocale, sanitiseHTML, sanitiseUrl, shortcutsBtn, splitText, strikeBtn, subscriptBtn, superscriptBtn, tableBtn, tail, throttle, trapFocus, ulBtn, underlineBtn, undoBtn, unique, unwrap, videoBtn, withSavedRange, wrap };
|
|
17133
17508
|
|
|
17134
17509
|
//# sourceMappingURL=autumnnote.es.js.map
|