vuewrite 0.0.18 → 0.0.20
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/dist/vuewrite.d.ts +5 -0
- package/dist/vuewrite.js +128 -24
- package/package.json +3 -2
package/dist/vuewrite.d.ts
CHANGED
|
@@ -213,6 +213,11 @@ declare class TextEditorStore {
|
|
|
213
213
|
removeNewLine(): void;
|
|
214
214
|
onInput(_e: Event): void;
|
|
215
215
|
addNewLine(): void;
|
|
216
|
+
addNewLineAfter(): {
|
|
217
|
+
id: string;
|
|
218
|
+
text: string;
|
|
219
|
+
styles: never[];
|
|
220
|
+
};
|
|
216
221
|
insertText(data: string): void;
|
|
217
222
|
insertBlock(blockData: Partial<Block>): void;
|
|
218
223
|
get startAndEnd(): [{
|
package/dist/vuewrite.js
CHANGED
|
@@ -366,6 +366,12 @@ class TextEditorStore {
|
|
|
366
366
|
this.selection.focus = { blockId: block.id, offset: 0 };
|
|
367
367
|
this.history.push("setText");
|
|
368
368
|
}
|
|
369
|
+
addNewLineAfter() {
|
|
370
|
+
const index = this.blocks.findIndex((item) => item.id === this.selection.anchor.blockId);
|
|
371
|
+
const block = { id: uid(), text: "", styles: [] };
|
|
372
|
+
this.blocks.splice(index + 1, 0, block);
|
|
373
|
+
return block;
|
|
374
|
+
}
|
|
369
375
|
insertText(data) {
|
|
370
376
|
const block = this.currentBlock;
|
|
371
377
|
if (!block)
|
|
@@ -388,7 +394,11 @@ class TextEditorStore {
|
|
|
388
394
|
}
|
|
389
395
|
Object.assign(this.currentBlock, blockData);
|
|
390
396
|
if (blockData.editable === false && this.currentBlock === this.blocks[this.blocks.length - 1]) {
|
|
391
|
-
this.
|
|
397
|
+
const newLine = this.addNewLineAfter();
|
|
398
|
+
this.selection.focus.blockId = newLine.id;
|
|
399
|
+
this.selection.focus.offset = 0;
|
|
400
|
+
this.selection.anchor.blockId = newLine.id;
|
|
401
|
+
this.selection.anchor.offset = 0;
|
|
392
402
|
}
|
|
393
403
|
this.history.push("setText");
|
|
394
404
|
}
|
|
@@ -606,12 +616,16 @@ const _sfc_main$2 = defineComponent({
|
|
|
606
616
|
const markers = [];
|
|
607
617
|
if (block.styles) {
|
|
608
618
|
for (let style of block.styles) {
|
|
619
|
+
if (style.end <= style.start)
|
|
620
|
+
continue;
|
|
609
621
|
markers.push([style.start, style]);
|
|
610
622
|
markers.push([style.end, style]);
|
|
611
623
|
}
|
|
612
624
|
}
|
|
613
625
|
if (props.parser) {
|
|
614
626
|
for (let style of props.parser(text)) {
|
|
627
|
+
if (style.end <= style.start)
|
|
628
|
+
continue;
|
|
615
629
|
markers.push([style.start, style]);
|
|
616
630
|
markers.push([style.end, style]);
|
|
617
631
|
}
|
|
@@ -676,6 +690,112 @@ const _sfc_main$2 = defineComponent({
|
|
|
676
690
|
};
|
|
677
691
|
}
|
|
678
692
|
});
|
|
693
|
+
const createClipboardEvents = (store, props) => {
|
|
694
|
+
const getSelected = () => {
|
|
695
|
+
const [start, end, startIndex, endIndex] = store.startAndEnd;
|
|
696
|
+
if (startIndex === endIndex) {
|
|
697
|
+
const text2 = store.blocks[startIndex].text.slice(start.offset, end.offset);
|
|
698
|
+
return [
|
|
699
|
+
new ClipboardItem({
|
|
700
|
+
"text/plain": new Blob([text2], { type: "text/plain" })
|
|
701
|
+
})
|
|
702
|
+
];
|
|
703
|
+
}
|
|
704
|
+
const startText = store.blocks[startIndex].text.slice(start.offset);
|
|
705
|
+
const endText = store.blocks[endIndex].text.slice(0, end.offset);
|
|
706
|
+
const arr = [
|
|
707
|
+
{ type: store.blocks[startIndex].type, text: startText },
|
|
708
|
+
...store.blocks.slice(startIndex + 1, endIndex),
|
|
709
|
+
{ type: store.blocks[endIndex].type, text: endText }
|
|
710
|
+
];
|
|
711
|
+
const html = arr.map((item) => `<div>${item.text}</div>`).join("\n");
|
|
712
|
+
const text = arr.map((item) => item.text).join("\n");
|
|
713
|
+
return [
|
|
714
|
+
new ClipboardItem({
|
|
715
|
+
"text/html": new Blob([html], { type: "text/html" }),
|
|
716
|
+
"text/plain": new Blob([text], { type: "text/plain" })
|
|
717
|
+
})
|
|
718
|
+
];
|
|
719
|
+
};
|
|
720
|
+
const onCopy = (e) => {
|
|
721
|
+
if (e.defaultPrevented)
|
|
722
|
+
return;
|
|
723
|
+
e.preventDefault();
|
|
724
|
+
navigator.clipboard.write(getSelected());
|
|
725
|
+
store.history.push("setText");
|
|
726
|
+
};
|
|
727
|
+
const onCut = (e) => {
|
|
728
|
+
if (e.defaultPrevented)
|
|
729
|
+
return;
|
|
730
|
+
e.preventDefault();
|
|
731
|
+
navigator.clipboard.write(getSelected());
|
|
732
|
+
store.deleteSelected();
|
|
733
|
+
store.history.push("setText");
|
|
734
|
+
};
|
|
735
|
+
const insertText = (text) => {
|
|
736
|
+
if (props.preventMultiline) {
|
|
737
|
+
const blocks = text.split("\n");
|
|
738
|
+
store.insertText(blocks[0]);
|
|
739
|
+
for (let i = 1; i < blocks.length; i++) {
|
|
740
|
+
store.addNewLine();
|
|
741
|
+
store.insertText(blocks[i]);
|
|
742
|
+
}
|
|
743
|
+
} else {
|
|
744
|
+
store.insertText(text);
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
const parseHtml = (node) => {
|
|
748
|
+
var _a;
|
|
749
|
+
let isTextNode = false;
|
|
750
|
+
for (let _node of node.childNodes) {
|
|
751
|
+
if (_node.nodeType === Node.TEXT_NODE && ((_a = _node.textContent) == null ? void 0 : _a.trim()) || _node.nodeType == Node.ELEMENT_NODE && _node.tagName === "SPAN") {
|
|
752
|
+
isTextNode = true;
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (isTextNode) {
|
|
757
|
+
const text = node.textContent;
|
|
758
|
+
if (!text)
|
|
759
|
+
return;
|
|
760
|
+
insertText(text);
|
|
761
|
+
store.addNewLine();
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
for (let child of node.children) {
|
|
765
|
+
if (child.tagName === "DIV") {
|
|
766
|
+
parseHtml(child);
|
|
767
|
+
} else {
|
|
768
|
+
insertText(child.textContent ?? "");
|
|
769
|
+
store.addNewLine();
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
const parser = new DOMParser();
|
|
774
|
+
const onPaste = (e) => {
|
|
775
|
+
var _a, _b;
|
|
776
|
+
if (e.defaultPrevented)
|
|
777
|
+
return;
|
|
778
|
+
e.preventDefault();
|
|
779
|
+
const html = (_a = e.clipboardData) == null ? void 0 : _a.getData("text/html");
|
|
780
|
+
if (html) {
|
|
781
|
+
store.deleteSelected();
|
|
782
|
+
const dom = parser.parseFromString(html, "text/html");
|
|
783
|
+
parseHtml(dom.body);
|
|
784
|
+
} else {
|
|
785
|
+
const text = (_b = e.clipboardData) == null ? void 0 : _b.getData("text");
|
|
786
|
+
if (!text)
|
|
787
|
+
return;
|
|
788
|
+
store.deleteSelected();
|
|
789
|
+
insertText(text);
|
|
790
|
+
}
|
|
791
|
+
store.history.push("setText");
|
|
792
|
+
};
|
|
793
|
+
return {
|
|
794
|
+
onCopy,
|
|
795
|
+
onCut,
|
|
796
|
+
onPaste
|
|
797
|
+
};
|
|
798
|
+
};
|
|
679
799
|
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
680
800
|
__name: "TextEditor",
|
|
681
801
|
props: {
|
|
@@ -842,26 +962,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
842
962
|
}
|
|
843
963
|
store.history.push("setText");
|
|
844
964
|
});
|
|
845
|
-
const onCopy = (
|
|
846
|
-
e.preventDefault();
|
|
847
|
-
navigator.clipboard.writeText(store.selectedText);
|
|
848
|
-
store.history.push("setText");
|
|
849
|
-
};
|
|
850
|
-
const onCut = (e) => {
|
|
851
|
-
e.preventDefault();
|
|
852
|
-
navigator.clipboard.writeText(store.selectedText);
|
|
853
|
-
store.deleteSelected();
|
|
854
|
-
store.history.push("setText");
|
|
855
|
-
};
|
|
856
|
-
const onPaste = (e) => {
|
|
857
|
-
var _a;
|
|
858
|
-
e.preventDefault();
|
|
859
|
-
const text = (_a = e.clipboardData) == null ? void 0 : _a.getData("Text");
|
|
860
|
-
if (!text)
|
|
861
|
-
return;
|
|
862
|
-
store.insertText(text);
|
|
863
|
-
store.history.push("setText");
|
|
864
|
-
};
|
|
965
|
+
const { onCut, onCopy, onPaste } = createClipboardEvents(store, props);
|
|
865
966
|
const getClientRects = (selection) => {
|
|
866
967
|
const anchor = getNode(selection.anchor.blockId);
|
|
867
968
|
const focus = getNode(selection.focus.blockId);
|
|
@@ -898,9 +999,12 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
898
999
|
onBeforeinput: _cache[0] || (_cache[0] = //@ts-ignore
|
|
899
1000
|
(...args) => unref(store).onInput && unref(store).onInput(...args)),
|
|
900
1001
|
onKeydown: onKeyDown,
|
|
901
|
-
onCopy
|
|
902
|
-
|
|
903
|
-
|
|
1002
|
+
onCopy: _cache[1] || (_cache[1] = //@ts-ignore
|
|
1003
|
+
(...args) => unref(onCopy) && unref(onCopy)(...args)),
|
|
1004
|
+
onPaste: _cache[2] || (_cache[2] = //@ts-ignore
|
|
1005
|
+
(...args) => unref(onPaste) && unref(onPaste)(...args)),
|
|
1006
|
+
onCut: _cache[3] || (_cache[3] = //@ts-ignore
|
|
1007
|
+
(...args) => unref(onCut) && unref(onCut)(...args))
|
|
904
1008
|
}, [
|
|
905
1009
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(store).blocks, (block) => {
|
|
906
1010
|
return openBlock(), createBlock(_sfc_main$2, {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "vuewrite",
|
|
3
3
|
"description": "Rich Text Editor based on Vue3 reactivity",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.20",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"author": "den59k",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"preview": "vite preview"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"vue": "^3"
|
|
22
|
+
"vue": "^3",
|
|
23
|
+
"vuewrite": "^0.0.19"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@vitejs/plugin-vue": "^5.0.4",
|