@kaitify/core 0.0.2 → 0.0.3-beta.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.
- package/lib/extensions/Extension.d.ts +4 -4
- package/lib/extensions/code-block/index.d.ts +1 -1
- package/lib/extensions/link/index.d.ts +1 -1
- package/lib/kaitify-core.es.js +66 -59
- package/lib/kaitify-core.umd.js +1 -1
- package/lib/model/Editor.d.ts +5 -6
- package/lib/model/KNode.d.ts +2 -2
- package/package.json +1 -1
|
@@ -60,7 +60,7 @@ export type ExtensionCreateOptionType = {
|
|
|
60
60
|
*/
|
|
61
61
|
onPasteKeepStyles?: (this: Editor, node: KNode) => KNodeStylesType;
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* 视图更新前回调
|
|
64
64
|
*/
|
|
65
65
|
onBeforeUpdateView?: (this: Editor) => void;
|
|
66
66
|
/**
|
|
@@ -68,7 +68,7 @@ export type ExtensionCreateOptionType = {
|
|
|
68
68
|
*/
|
|
69
69
|
onAfterUpdateView?: (this: Editor) => void;
|
|
70
70
|
/**
|
|
71
|
-
*
|
|
71
|
+
* 在删除和换行操作中块节点从其父节点中抽离出去成为与父节点同级的节点后触发,如果返回true则表示继续使用默认逻辑,会将该节点转为段落,返回false则不走默认逻辑,需要自定义处理
|
|
72
72
|
*/
|
|
73
73
|
onDetachMentBlockFromParent?: (this: Editor, node: KNode) => boolean;
|
|
74
74
|
/**
|
|
@@ -149,7 +149,7 @@ export declare class Extension {
|
|
|
149
149
|
*/
|
|
150
150
|
onPasteKeepStyles?: (this: Editor, node: KNode) => KNodeStylesType;
|
|
151
151
|
/**
|
|
152
|
-
*
|
|
152
|
+
* 视图更新前回调
|
|
153
153
|
*/
|
|
154
154
|
onBeforeUpdateView?: (this: Editor) => void;
|
|
155
155
|
/**
|
|
@@ -157,7 +157,7 @@ export declare class Extension {
|
|
|
157
157
|
*/
|
|
158
158
|
onAfterUpdateView?: (this: Editor) => void;
|
|
159
159
|
/**
|
|
160
|
-
*
|
|
160
|
+
* 在删除和换行操作中块节点从其父节点中抽离出去成为与父节点同级的节点后触发,如果返回true则表示继续使用默认逻辑,会将该节点转为段落,返回false则不走默认逻辑,需要自定义处理
|
|
161
161
|
*/
|
|
162
162
|
onDetachMentBlockFromParent?: (this: Editor, node: KNode) => boolean;
|
|
163
163
|
/**
|
|
@@ -26,7 +26,7 @@ declare module '../../model' {
|
|
|
26
26
|
/**
|
|
27
27
|
* 更新光标所在代码块的语言类型
|
|
28
28
|
*/
|
|
29
|
-
updateCodeBlockLanguage?: (language
|
|
29
|
+
updateCodeBlockLanguage?: (language?: HljsLanguageType) => Promise<void>;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
export type CodeBlockExtensionPropsType = {
|
package/lib/kaitify-core.es.js
CHANGED
|
@@ -1399,7 +1399,7 @@ const kebabToCamel = (val) => {
|
|
|
1399
1399
|
const getDomAttributes = (dom) => {
|
|
1400
1400
|
const attributes = Array.from(dom.attributes);
|
|
1401
1401
|
const length = attributes.length;
|
|
1402
|
-
const regExp = new RegExp(`(^on)|(^style$)|(^${NODE_MARK}$)
|
|
1402
|
+
const regExp = new RegExp(`(^on)|(^style$)|(^${NODE_MARK}$)`);
|
|
1403
1403
|
const result = {};
|
|
1404
1404
|
for (let i = 0; i < length; i++) {
|
|
1405
1405
|
const { nodeName, nodeValue } = attributes[i];
|
|
@@ -1564,22 +1564,6 @@ class KNode {
|
|
|
1564
1564
|
}
|
|
1565
1565
|
return newNode2;
|
|
1566
1566
|
});
|
|
1567
|
-
/**
|
|
1568
|
-
* 【API】如果当前节点是文本节点或者闭合节点,则判断是不是指定节点后代中所有文本节点和闭合节点中的第一个
|
|
1569
|
-
*/
|
|
1570
|
-
__publicField(this, "firstInTargetNode", (node) => {
|
|
1571
|
-
if (!this.isText() && !this.isClosed()) {
|
|
1572
|
-
return false;
|
|
1573
|
-
}
|
|
1574
|
-
if (this.isEqual(node)) {
|
|
1575
|
-
return true;
|
|
1576
|
-
}
|
|
1577
|
-
if (node.isContains(this) && node.hasChildren()) {
|
|
1578
|
-
const firstChild = node.children[0];
|
|
1579
|
-
return this.firstInTargetNode(firstChild);
|
|
1580
|
-
}
|
|
1581
|
-
return false;
|
|
1582
|
-
});
|
|
1583
1567
|
/**
|
|
1584
1568
|
* 【API】获取当前节点下的所有可聚焦的节点,如果自身符合也会包括在内
|
|
1585
1569
|
* 1. type 是 all 获取闭合节点和文本节点;
|
|
@@ -1835,6 +1819,22 @@ class KNode {
|
|
|
1835
1819
|
}
|
|
1836
1820
|
return newNode2;
|
|
1837
1821
|
}
|
|
1822
|
+
/**
|
|
1823
|
+
* 【API】如果当前节点是文本节点或者闭合节点,则判断是不是指定节点后代中所有文本节点和闭合节点中的第一个
|
|
1824
|
+
*/
|
|
1825
|
+
firstInTargetNode(node) {
|
|
1826
|
+
if (!this.isText() && !this.isClosed()) {
|
|
1827
|
+
return false;
|
|
1828
|
+
}
|
|
1829
|
+
if (this.isEqual(node)) {
|
|
1830
|
+
return true;
|
|
1831
|
+
}
|
|
1832
|
+
if (node.isContains(this) && node.hasChildren()) {
|
|
1833
|
+
const firstChild = node.children[0];
|
|
1834
|
+
return this.firstInTargetNode(firstChild);
|
|
1835
|
+
}
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
1838
|
/**
|
|
1839
1839
|
* 【API】如果当前节点是文本节点或者闭合节点,则判断是不是指定节点后代中所有文本节点和闭合节点中的最后一个
|
|
1840
1840
|
*/
|
|
@@ -2607,6 +2607,16 @@ const updateSelection$1 = function() {
|
|
|
2607
2607
|
const range = realSelection.getRangeAt(0);
|
|
2608
2608
|
if (isContains(this.$el, range.startContainer) && isContains(this.$el, range.endContainer)) {
|
|
2609
2609
|
const resolvePoint = (container, rangeOffset, type) => {
|
|
2610
|
+
if (container === this.$el) {
|
|
2611
|
+
const childDoms = Array.from(container.childNodes);
|
|
2612
|
+
if (childDoms.length) {
|
|
2613
|
+
const dom = childDoms[rangeOffset] ? childDoms[rangeOffset] : childDoms[rangeOffset - 1];
|
|
2614
|
+
if (dom.nodeType == 1) {
|
|
2615
|
+
childDoms[rangeOffset] ? this.setSelectionBefore(this.findNode(dom), type) : this.setSelectionAfter(this.findNode(dom), type);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
return;
|
|
2619
|
+
}
|
|
2610
2620
|
const containerNode = container.nodeType == 3 ? this.findNode(container.parentNode) : this.findNode(container);
|
|
2611
2621
|
if (containerNode.isClosed()) {
|
|
2612
2622
|
this.selection[type] = { node: containerNode, offset: type == "start" ? 0 : 1 };
|
|
@@ -2760,7 +2770,7 @@ const handlerForPasteDrop = async function(dataTransfer) {
|
|
|
2760
2770
|
fillPlaceholderToEmptyBlock.apply(this, [nodes]);
|
|
2761
2771
|
handlerForPasteKeepMarksAndStyles.apply(this, [nodes]);
|
|
2762
2772
|
const useDefault = typeof this.onPasteHtml == "function" ? await this.onPasteHtml.apply(this, [nodes, html]) : true;
|
|
2763
|
-
if (useDefault) {
|
|
2773
|
+
if (useDefault && nodes.length > 0) {
|
|
2764
2774
|
this.insertNode(nodes[0]);
|
|
2765
2775
|
for (let i = nodes.length - 1; i >= 1; i--) {
|
|
2766
2776
|
this.addNodeAfter(nodes[i], nodes[0]);
|
|
@@ -2940,12 +2950,12 @@ const formatLineBreakSpaceText = ({ editor, node }) => {
|
|
|
2940
2950
|
endPrevNumber = (preText.match(regExp) || []).length;
|
|
2941
2951
|
}
|
|
2942
2952
|
}
|
|
2943
|
-
node.textContent = node.textContent.replace(/\n/g, (
|
|
2944
|
-
const
|
|
2945
|
-
if (!
|
|
2946
|
-
|
|
2953
|
+
node.textContent = node.textContent.replace(/\n/g, (char, index) => {
|
|
2954
|
+
const nextChar = node.textContent[index + 1];
|
|
2955
|
+
if (!nextChar || !isZeroWidthText(nextChar)) {
|
|
2956
|
+
char = char + getZeroWidthText();
|
|
2947
2957
|
}
|
|
2948
|
-
return
|
|
2958
|
+
return char;
|
|
2949
2959
|
});
|
|
2950
2960
|
if (startPrevNumber > 0) {
|
|
2951
2961
|
editor.selection.start.offset += startPrevNumber;
|
|
@@ -2960,8 +2970,8 @@ const formatZeroWidthTextMerge = ({ editor, node }) => {
|
|
|
2960
2970
|
let val = node.textContent;
|
|
2961
2971
|
let i = 0;
|
|
2962
2972
|
while (i < val.length) {
|
|
2963
|
-
const
|
|
2964
|
-
if (i > 0 && isZeroWidthText(
|
|
2973
|
+
const char = val.charAt(i);
|
|
2974
|
+
if (i > 0 && isZeroWidthText(char) && isZeroWidthText(val.charAt(i - 1))) {
|
|
2965
2975
|
if (editor.isSelectionInTargetNode(node, "start") && editor.selection.start.offset >= i + 1) {
|
|
2966
2976
|
editor.selection.start.offset -= 1;
|
|
2967
2977
|
}
|
|
@@ -3010,7 +3020,7 @@ const patchNodes$1 = (newNodes, oldNodes) => {
|
|
|
3010
3020
|
return [];
|
|
3011
3021
|
}
|
|
3012
3022
|
if (newNodes.length === 0) {
|
|
3013
|
-
return oldNodes.filter((node) =>
|
|
3023
|
+
return oldNodes.filter((node) => !!node).map((oldNode) => ({
|
|
3014
3024
|
oldNode,
|
|
3015
3025
|
newNode: null
|
|
3016
3026
|
}));
|
|
@@ -3351,7 +3361,7 @@ class Extension {
|
|
|
3351
3361
|
*/
|
|
3352
3362
|
__publicField(this, "onPasteKeepStyles");
|
|
3353
3363
|
/**
|
|
3354
|
-
*
|
|
3364
|
+
* 视图更新前回调
|
|
3355
3365
|
*/
|
|
3356
3366
|
__publicField(this, "onBeforeUpdateView");
|
|
3357
3367
|
/**
|
|
@@ -3359,7 +3369,7 @@ class Extension {
|
|
|
3359
3369
|
*/
|
|
3360
3370
|
__publicField(this, "onAfterUpdateView");
|
|
3361
3371
|
/**
|
|
3362
|
-
*
|
|
3372
|
+
* 在删除和换行操作中块节点从其父节点中抽离出去成为与父节点同级的节点后触发,如果返回true则表示继续使用默认逻辑,会将该节点转为段落,返回false则不走默认逻辑,需要自定义处理
|
|
3363
3373
|
*/
|
|
3364
3374
|
__publicField(this, "onDetachMentBlockFromParent");
|
|
3365
3375
|
/**
|
|
@@ -7000,10 +7010,10 @@ const CodeExtension = () => Extension.create({
|
|
|
7000
7010
|
const length = focusNodes.length;
|
|
7001
7011
|
for (let i = 0; i < length; i++) {
|
|
7002
7012
|
const node = focusNodes[i];
|
|
7003
|
-
const
|
|
7013
|
+
const isExistInCode = !!node.getMatchNode({
|
|
7004
7014
|
tag: "code"
|
|
7005
7015
|
});
|
|
7006
|
-
if (
|
|
7016
|
+
if (isExistInCode) {
|
|
7007
7017
|
continue;
|
|
7008
7018
|
}
|
|
7009
7019
|
const newNode2 = node.clone(true);
|
|
@@ -36039,7 +36049,7 @@ const AttachmentExtension = (props) => Extension.create({
|
|
|
36039
36049
|
if (node.isMatch({ tag: "span", marks: { [ATTACHMENT_NODE_TAG]: true } })) {
|
|
36040
36050
|
const url = node.marks[ATTACHMENT_NODE_TAG];
|
|
36041
36051
|
const text2 = KNode.flat(node.children ?? []).filter((n) => n.isText()).map((n) => n.textContent).join("");
|
|
36042
|
-
const icon = (_c = (_b = (_a = node.styles) == null ? void 0 : _a.backgroundImage) == null ? void 0 : _b.match(/url\(["']?(.*?)["']?\)/)) == null ? void 0 : _c[1];
|
|
36052
|
+
const icon = ((_c = (_b = (_a = node.styles) == null ? void 0 : _a.backgroundImage) == null ? void 0 : _b.match(/url\(["']?(.*?)["']?\)/)) == null ? void 0 : _c[1]) ?? "";
|
|
36043
36053
|
node.type = "closed";
|
|
36044
36054
|
node.tag = ATTACHMENT_NODE_TAG;
|
|
36045
36055
|
node.children = void 0;
|
|
@@ -36639,16 +36649,16 @@ const TableExtension = () => Extension.create({
|
|
|
36639
36649
|
//td内无段落则加入段落
|
|
36640
36650
|
({ node, editor }) => {
|
|
36641
36651
|
if (node.isMatch({ tag: "td" }) && !node.children.some((item) => item.isBlock())) {
|
|
36642
|
-
const
|
|
36652
|
+
const paragraph = KNode.create({
|
|
36643
36653
|
type: "block",
|
|
36644
36654
|
tag: editor.blockRenderTag
|
|
36645
36655
|
});
|
|
36646
|
-
|
|
36647
|
-
item.parent =
|
|
36656
|
+
paragraph.children = node.children.map((item) => {
|
|
36657
|
+
item.parent = paragraph;
|
|
36648
36658
|
return item;
|
|
36649
36659
|
});
|
|
36650
|
-
node.children = [
|
|
36651
|
-
|
|
36660
|
+
node.children = [paragraph];
|
|
36661
|
+
paragraph.parent = node;
|
|
36652
36662
|
}
|
|
36653
36663
|
},
|
|
36654
36664
|
//针对跨行跨列的单元格,增加隐藏单元格
|
|
@@ -36675,7 +36685,7 @@ const TableExtension = () => Extension.create({
|
|
|
36675
36685
|
if (this.isParagraph(blockNode) && blockNode.allIsPlaceholder() && pBlock && this.isParagraph(pBlock) && pBlock.allIsPlaceholder() && ppBlock) {
|
|
36676
36686
|
blockNode.toEmpty();
|
|
36677
36687
|
pBlock.toEmpty();
|
|
36678
|
-
const
|
|
36688
|
+
const paragraph = KNode.create({
|
|
36679
36689
|
type: "block",
|
|
36680
36690
|
tag: this.blockRenderTag,
|
|
36681
36691
|
children: [
|
|
@@ -36685,8 +36695,8 @@ const TableExtension = () => Extension.create({
|
|
|
36685
36695
|
}
|
|
36686
36696
|
]
|
|
36687
36697
|
});
|
|
36688
|
-
this.addNodeAfter(
|
|
36689
|
-
this.setSelectionBefore(
|
|
36698
|
+
this.addNodeAfter(paragraph, tableNode);
|
|
36699
|
+
this.setSelectionBefore(paragraph);
|
|
36690
36700
|
}
|
|
36691
36701
|
}
|
|
36692
36702
|
},
|
|
@@ -37136,7 +37146,7 @@ const patchNodes = (newNodes, oldNodes) => {
|
|
|
37136
37146
|
return [];
|
|
37137
37147
|
}
|
|
37138
37148
|
if (newNodes.length === 0) {
|
|
37139
|
-
return oldNodes.filter((node) =>
|
|
37149
|
+
return oldNodes.filter((node) => !!node).map((oldNode) => ({
|
|
37140
37150
|
type: "remove",
|
|
37141
37151
|
oldNode,
|
|
37142
37152
|
newNode: null
|
|
@@ -37334,9 +37344,9 @@ const insertDom = (editor, newNode2) => {
|
|
|
37334
37344
|
const previousDom = previousNode ? findDom(editor, previousNode) : null;
|
|
37335
37345
|
const nextNode = newNode2.getNext(parentNode ? parentNode.children : editor.stackNodes);
|
|
37336
37346
|
const nextDom = nextNode ? findDom(editor, nextNode) : null;
|
|
37337
|
-
if (previousDom &&
|
|
37347
|
+
if (previousDom && isContains(parentDom, previousDom)) {
|
|
37338
37348
|
previousDom.nextElementSibling ? parentDom.insertBefore(newDom, previousDom.nextElementSibling) : parentDom.appendChild(newDom);
|
|
37339
|
-
} else if (nextDom &&
|
|
37349
|
+
} else if (nextDom && isContains(parentDom, nextDom)) {
|
|
37340
37350
|
parentDom.insertBefore(newDom, nextDom);
|
|
37341
37351
|
} else {
|
|
37342
37352
|
const idx = (parentNode ? parentNode.children : editor.stackNodes).findIndex((item) => item.isEqual(newNode2));
|
|
@@ -37452,7 +37462,7 @@ class Editor {
|
|
|
37452
37462
|
*/
|
|
37453
37463
|
__publicField(this, "textRenderTag", "span");
|
|
37454
37464
|
/**
|
|
37455
|
-
*
|
|
37465
|
+
* 编辑器内渲染默认块级节点的真实标签,即段落标签【初始化后不建议修改】【open】
|
|
37456
37466
|
*/
|
|
37457
37467
|
__publicField(this, "blockRenderTag", "p");
|
|
37458
37468
|
/**
|
|
@@ -37548,7 +37558,7 @@ class Editor {
|
|
|
37548
37558
|
*/
|
|
37549
37559
|
__publicField(this, "onAfterUpdateView");
|
|
37550
37560
|
/**
|
|
37551
|
-
*
|
|
37561
|
+
* 在删除和换行操作中块节点从其父节点中抽离出去成为与父节点同级的节点后触发,如果返回true则表示继续使用默认逻辑,会将该节点转为段落,返回false则不走默认逻辑,需要自定义处理【初始化后不可修改】
|
|
37552
37562
|
*/
|
|
37553
37563
|
__publicField(this, "onDetachMentBlockFromParent");
|
|
37554
37564
|
/**
|
|
@@ -37593,7 +37603,7 @@ class Editor {
|
|
|
37593
37603
|
newHtml: void 0
|
|
37594
37604
|
});
|
|
37595
37605
|
/**
|
|
37596
|
-
* 是否编辑器内部渲染真实光标引起
|
|
37606
|
+
* 是否编辑器内部渲染真实光标引起selectionChange事件【不可修改】
|
|
37597
37607
|
*/
|
|
37598
37608
|
__publicField(this, "internalCauseSelectionChange", false);
|
|
37599
37609
|
/**
|
|
@@ -37611,12 +37621,11 @@ class Editor {
|
|
|
37611
37621
|
const scrollHeight = element.getScrollHeight(scrollEl);
|
|
37612
37622
|
const scrollWidth = element.getScrollWidth(scrollEl);
|
|
37613
37623
|
if (scrollEl.clientHeight < scrollHeight || scrollEl.clientWidth < scrollWidth) {
|
|
37614
|
-
|
|
37615
|
-
const
|
|
37616
|
-
const
|
|
37617
|
-
|
|
37618
|
-
|
|
37619
|
-
target = focusDom;
|
|
37624
|
+
let target = focusDom;
|
|
37625
|
+
const sel = window.getSelection();
|
|
37626
|
+
const range = sel && sel.rangeCount ? sel.getRangeAt(0) : null;
|
|
37627
|
+
if (range && range.getClientRects().length > 0) {
|
|
37628
|
+
target = range;
|
|
37620
37629
|
}
|
|
37621
37630
|
const childRect = target.getBoundingClientRect();
|
|
37622
37631
|
const parentRect = scrollEl.getBoundingClientRect();
|
|
@@ -38420,8 +38429,7 @@ class Editor {
|
|
|
38420
38429
|
}
|
|
38421
38430
|
/**
|
|
38422
38431
|
* 向选区进行换行
|
|
38423
|
-
* 1.
|
|
38424
|
-
* 2. 非代码块样式内换行是插入换行符\n
|
|
38432
|
+
* 1. 在代码块样式内换行是插入换行符\n
|
|
38425
38433
|
* 2. 光标所在块节点是固定块节点,则无法换行
|
|
38426
38434
|
* 3. 光标所在块节点只有占位符,并且其存在父节点,且父节点不是固定块节点,会从父节点抽离到与父节点同级
|
|
38427
38435
|
* 4. 光标所在块节点只有占位符,并且不存在父节点,且不是段落,则会转为段落
|
|
@@ -38856,12 +38864,11 @@ class Editor {
|
|
|
38856
38864
|
const scrollHeight = element.getScrollHeight(scrollElement);
|
|
38857
38865
|
const scrollWidth = element.getScrollWidth(scrollElement);
|
|
38858
38866
|
if (scrollElement.clientHeight < scrollHeight || scrollElement.clientWidth < scrollWidth) {
|
|
38859
|
-
|
|
38860
|
-
const
|
|
38861
|
-
const
|
|
38862
|
-
|
|
38863
|
-
|
|
38864
|
-
target = focusDom;
|
|
38867
|
+
let target = focusDom;
|
|
38868
|
+
const sel = window.getSelection();
|
|
38869
|
+
const range = sel && sel.rangeCount ? sel.getRangeAt(0) : null;
|
|
38870
|
+
if (range && range.getClientRects().length > 0) {
|
|
38871
|
+
target = range;
|
|
38865
38872
|
}
|
|
38866
38873
|
const childRect = target.getBoundingClientRect();
|
|
38867
38874
|
const parentRect = scrollElement.getBoundingClientRect();
|