@milkdown/plugin-upload 6.5.3 → 7.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/default-uploader.d.ts +4 -0
- package/lib/default-uploader.d.ts.map +1 -1
- package/lib/index.d.ts +4 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.es.js +91 -90
- package/lib/index.es.js.map +1 -1
- package/lib/upload.d.ts +5 -4
- package/lib/upload.d.ts.map +1 -1
- package/package.json +14 -7
- package/src/default-uploader.ts +1 -1
- package/src/index.ts +5 -6
- package/src/upload.ts +102 -109
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-uploader.d.ts","sourceRoot":"","sources":["../src/default-uploader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"default-uploader.d.ts","sourceRoot":"","sources":["../src/default-uploader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,eAAO,MAAM,iBAAiB,SAAU,IAAI,KAAG,QAAQ;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAelF,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,QAqB7B,CAAA"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export declare const upload:
|
|
1
|
+
import type { MilkdownPlugin } from '@milkdown/ctx';
|
|
2
|
+
export * from './upload';
|
|
3
|
+
export * from './default-uploader';
|
|
4
|
+
export declare const upload: MilkdownPlugin[];
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnD,cAAc,UAAU,CAAA;AACxB,cAAc,oBAAoB,CAAA;AAElC,eAAO,MAAM,MAAM,EAAE,cAAc,EAAiC,CAAA"}
|
package/lib/index.es.js
CHANGED
|
@@ -1,102 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
1
|
+
import { schemaCtx as h } from "@milkdown/core";
|
|
2
|
+
import { PluginKey as y, Plugin as D } from "@milkdown/prose/state";
|
|
3
|
+
import { Decoration as P, DecorationSet as b } from "@milkdown/prose/view";
|
|
4
|
+
import { $ctx as U, $prose as C } from "@milkdown/utils";
|
|
5
|
+
import { missingNodeInSchema as F } from "@milkdown/exception";
|
|
6
|
+
const A = (a) => new Promise((i) => {
|
|
7
|
+
const r = new FileReader();
|
|
8
|
+
r.addEventListener(
|
|
9
9
|
"load",
|
|
10
10
|
() => {
|
|
11
|
-
|
|
12
|
-
alt:
|
|
13
|
-
src:
|
|
11
|
+
i({
|
|
12
|
+
alt: a.name,
|
|
13
|
+
src: r.result
|
|
14
14
|
});
|
|
15
15
|
},
|
|
16
16
|
!1
|
|
17
|
-
),
|
|
18
|
-
}),
|
|
19
|
-
const
|
|
20
|
-
for (let
|
|
21
|
-
const
|
|
22
|
-
!
|
|
17
|
+
), r.readAsDataURL(a);
|
|
18
|
+
}), E = async (a, i) => {
|
|
19
|
+
const r = [];
|
|
20
|
+
for (let t = 0; t < a.length; t++) {
|
|
21
|
+
const e = a.item(t);
|
|
22
|
+
!e || !e.type.includes("image") || r.push(e);
|
|
23
23
|
}
|
|
24
|
-
const { image:
|
|
25
|
-
if (!
|
|
26
|
-
throw
|
|
27
|
-
return (await Promise.all(
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
24
|
+
const { image: c } = i.nodes;
|
|
25
|
+
if (!c)
|
|
26
|
+
throw F("image");
|
|
27
|
+
return (await Promise.all(r.map((t) => A(t)))).map(({ alt: t, src: e }) => c.createAndFill({ src: e, alt: t }));
|
|
28
|
+
}, l = U({
|
|
29
|
+
uploader: E,
|
|
30
|
+
enableHtmlFileUploader: !1,
|
|
31
|
+
uploadWidgetFactory: (a, i) => {
|
|
32
|
+
const r = document.createElement("span");
|
|
33
|
+
return r.textContent = "Upload in progress...", P.widget(a, r, i);
|
|
34
|
+
}
|
|
35
|
+
}, "uploadConfig"), M = C((a) => {
|
|
36
|
+
const i = new y("MILKDOWN_UPLOAD"), r = (o, t) => {
|
|
37
|
+
var s;
|
|
38
|
+
const e = i.getState(o);
|
|
39
|
+
if (!e)
|
|
40
|
+
return -1;
|
|
41
|
+
const n = e.find(void 0, void 0, (d) => d.id === t);
|
|
42
|
+
return n.length ? ((s = n[0]) == null ? void 0 : s.from) ?? -1 : -1;
|
|
43
|
+
}, c = (o, t, e) => {
|
|
44
|
+
var m;
|
|
45
|
+
if (!e || e.length <= 0)
|
|
46
|
+
return !1;
|
|
47
|
+
const n = Symbol("upload symbol"), s = a.get(h), { tr: d } = o.state, f = t instanceof DragEvent ? ((m = o.posAtCoords({ left: t.clientX, top: t.clientY })) == null ? void 0 : m.pos) ?? d.selection.from : d.selection.from;
|
|
48
|
+
o.dispatch(d.setMeta(i, { add: { id: n, pos: f } }));
|
|
49
|
+
const { uploader: g } = a.get(l.key);
|
|
50
|
+
return g(e, s).then((p) => {
|
|
51
|
+
const u = r(o.state, n);
|
|
52
|
+
u < 0 || o.dispatch(
|
|
53
|
+
o.state.tr.replaceWith(u, u, p).setMeta(i, { remove: { id: n } })
|
|
54
|
+
);
|
|
55
|
+
}).catch((p) => {
|
|
56
|
+
console.error(p);
|
|
57
|
+
}), !0;
|
|
58
|
+
};
|
|
59
|
+
return new D({
|
|
60
|
+
key: i,
|
|
61
|
+
state: {
|
|
62
|
+
init() {
|
|
63
|
+
return b.empty;
|
|
64
|
+
},
|
|
65
|
+
apply(o, t) {
|
|
66
|
+
const e = t.map(o.mapping, o.doc), n = o.getMeta(this);
|
|
67
|
+
if (!n)
|
|
68
|
+
return e;
|
|
69
|
+
if (n.add) {
|
|
70
|
+
const { uploadWidgetFactory: s } = a.get(l.key), d = s(n.add.pos, { id: n.add.id });
|
|
71
|
+
return e.add(o.doc, [d]);
|
|
60
72
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!t)
|
|
65
|
-
return -1;
|
|
66
|
-
const a = t.find(void 0, void 0, (m) => m.id === r);
|
|
67
|
-
return a.length && (c = (n = a[0]) == null ? void 0 : n.from) != null ? c : -1;
|
|
68
|
-
}, h = (e, r, t) => {
|
|
69
|
-
var m, P;
|
|
70
|
-
if (!t || t.length <= 0)
|
|
71
|
-
return !1;
|
|
72
|
-
const a = Symbol("upload symbol"), { tr: n } = e.state, c = r instanceof DragEvent && (P = (m = e.posAtCoords({ left: r.clientX, top: r.clientY })) == null ? void 0 : m.pos) != null ? P : n.selection.from;
|
|
73
|
-
return e.dispatch(n.setMeta(p, { add: { id: a, pos: c } })), i(t, d).then((f) => {
|
|
74
|
-
const g = b(e.state, a);
|
|
75
|
-
g < 0 || e.dispatch(
|
|
76
|
-
e.state.tr.replaceWith(g, g, f).setMeta(p, { remove: { id: a } })
|
|
77
|
-
);
|
|
78
|
-
}).catch((f) => {
|
|
79
|
-
console.error(f);
|
|
80
|
-
}), !0;
|
|
81
|
-
}, A = new D({
|
|
82
|
-
props: {
|
|
83
|
-
handlePaste: (e, r) => {
|
|
84
|
-
var t, a;
|
|
85
|
-
return !(r instanceof ClipboardEvent) || !(o != null && o.enableHtmlFileUploader) && ((t = r.clipboardData) == null ? void 0 : t.getData("text/html")) ? !1 : h(e, r, (a = r.clipboardData) == null ? void 0 : a.files);
|
|
86
|
-
},
|
|
87
|
-
handleDrop: (e, r) => {
|
|
88
|
-
var t;
|
|
89
|
-
return r instanceof DragEvent ? h(e, r, (t = r.dataTransfer) == null ? void 0 : t.files) : !1;
|
|
90
|
-
}
|
|
73
|
+
if (n.remove) {
|
|
74
|
+
const s = e.find(void 0, void 0, (d) => d.id === n.remove.id);
|
|
75
|
+
return e.remove(s);
|
|
91
76
|
}
|
|
92
|
-
|
|
93
|
-
|
|
77
|
+
return e;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
props: {
|
|
81
|
+
decorations(o) {
|
|
82
|
+
return this.getState(o);
|
|
83
|
+
},
|
|
84
|
+
handlePaste: (o, t) => {
|
|
85
|
+
var n, s;
|
|
86
|
+
const { enableHtmlFileUploader: e } = a.get(l.key);
|
|
87
|
+
return !(t instanceof ClipboardEvent) || !e && ((n = t.clipboardData) == null ? void 0 : n.getData("text/html")) ? !1 : c(o, t, (s = t.clipboardData) == null ? void 0 : s.files);
|
|
88
|
+
},
|
|
89
|
+
handleDrop: (o, t) => {
|
|
90
|
+
var e;
|
|
91
|
+
return t instanceof DragEvent ? c(o, t, (e = t.dataTransfer) == null ? void 0 : e.files) : !1;
|
|
92
|
+
}
|
|
94
93
|
}
|
|
95
|
-
};
|
|
96
|
-
}),
|
|
94
|
+
});
|
|
95
|
+
}), I = [l, M];
|
|
97
96
|
export {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
E as defaultUploader,
|
|
98
|
+
A as readImageAsBase64,
|
|
99
|
+
M as updatePlugin,
|
|
100
|
+
I as upload,
|
|
101
|
+
l as uploadConfig
|
|
101
102
|
};
|
|
102
103
|
//# sourceMappingURL=index.es.js.map
|
package/lib/index.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.es.js","sources":["../src/default-uploader.ts","../src/upload.ts","../src/index.ts"],"sourcesContent":["/* Copyright 2021, Milkdown by Mirone. */\nimport { missingNodeInSchema } from '@milkdown/exception'\nimport type { Node } from '@milkdown/prose/model'\n\nimport type { Uploader } from './upload'\n\
|
|
1
|
+
{"version":3,"file":"index.es.js","sources":["../src/default-uploader.ts","../src/upload.ts","../src/index.ts"],"sourcesContent":["/* Copyright 2021, Milkdown by Mirone. */\nimport { missingNodeInSchema } from '@milkdown/exception'\nimport type { Node } from '@milkdown/prose/model'\n\nimport type { Uploader } from './upload'\n\nexport const readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {\n return new Promise((resolve) => {\n const reader = new FileReader()\n reader.addEventListener(\n 'load',\n () => {\n resolve({\n alt: file.name,\n src: reader.result as string,\n })\n },\n false,\n )\n reader.readAsDataURL(file)\n })\n}\n\nexport const defaultUploader: Uploader = async (files, schema) => {\n const imgs: File[] = []\n\n for (let i = 0; i < files.length; i++) {\n const file = files.item(i)\n if (!file)\n continue\n\n if (!file.type.includes('image'))\n continue\n\n imgs.push(file)\n }\n\n const { image } = schema.nodes\n if (!image)\n throw missingNodeInSchema('image')\n\n const data = await Promise.all(imgs.map(img => readImageAsBase64(img)))\n\n return data.map(({ alt, src }) => image.createAndFill({ src, alt }) as Node)\n}\n","/* Copyright 2021, Milkdown by Mirone. */\nimport { schemaCtx } from '@milkdown/core'\nimport type { Fragment, Node, Schema } from '@milkdown/prose/model'\nimport type { EditorState } from '@milkdown/prose/state'\nimport { Plugin, PluginKey } from '@milkdown/prose/state'\nimport type { EditorView } from '@milkdown/prose/view'\nimport { Decoration, DecorationSet } from '@milkdown/prose/view'\nimport { $ctx, $prose } from '@milkdown/utils'\n\nimport { defaultUploader } from './default-uploader'\n\nexport type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>\ninterface Spec { id: symbol; pos: number }\nexport interface UploadConfig {\n uploader: Uploader\n enableHtmlFileUploader: boolean\n uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration\n}\n\nexport const uploadConfig = $ctx<UploadConfig, 'uploadConfig'>({\n uploader: defaultUploader,\n enableHtmlFileUploader: false,\n uploadWidgetFactory: (pos, spec) => {\n const widgetDOM = document.createElement('span')\n widgetDOM.textContent = 'Upload in progress...'\n return Decoration.widget(pos, widgetDOM, spec)\n },\n}, 'uploadConfig')\n\nexport const updatePlugin = $prose((ctx) => {\n const pluginKey = new PluginKey('MILKDOWN_UPLOAD')\n\n const findPlaceholder = (state: EditorState, id: symbol): number => {\n const decorations = pluginKey.getState(state)\n if (!decorations)\n return -1\n const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)\n if (!found.length)\n return -1\n return found[0]?.from ?? -1\n }\n\n const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {\n if (!files || files.length <= 0)\n return false\n\n const id = Symbol('upload symbol')\n const schema = ctx.get(schemaCtx)\n const { tr } = view.state\n const insertPos = event instanceof DragEvent\n ? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from\n : tr.selection.from\n view.dispatch(tr.setMeta(pluginKey, { add: { id, pos: insertPos } }))\n\n const { uploader } = ctx.get(uploadConfig.key)\n uploader(files, schema)\n .then((fragment) => {\n const pos = findPlaceholder(view.state, id)\n if (pos < 0)\n return\n\n view.dispatch(\n view.state.tr\n .replaceWith(pos, pos, fragment)\n .setMeta(pluginKey, { remove: { id } }),\n )\n })\n .catch((e) => {\n console.error(e)\n })\n return true\n }\n\n return new Plugin({\n key: pluginKey,\n state: {\n init() {\n return DecorationSet.empty\n },\n apply(this: Plugin, tr, set) {\n const _set = set.map(tr.mapping, tr.doc)\n const action = tr.getMeta(this)\n if (!action)\n return _set\n\n if (action.add) {\n const { uploadWidgetFactory } = ctx.get(uploadConfig.key)\n\n const decoration = uploadWidgetFactory(action.add.pos, { id: action.add.id })\n return _set.add(tr.doc, [decoration])\n }\n if (action.remove) {\n const target = _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id)\n return _set.remove(target)\n }\n\n return _set\n },\n },\n props: {\n decorations(this: Plugin, state) {\n return this.getState(state)\n },\n handlePaste: (view, event) => {\n const { enableHtmlFileUploader } = ctx.get(uploadConfig.key)\n if (!(event instanceof ClipboardEvent))\n return false\n\n if (!enableHtmlFileUploader && event.clipboardData?.getData('text/html'))\n return false\n\n return handleUpload(view, event, event.clipboardData?.files)\n },\n handleDrop: (view, event) => {\n if (!(event instanceof DragEvent))\n return false\n\n return handleUpload(view, event, event.dataTransfer?.files)\n },\n },\n })\n})\n","/* Copyright 2021, Milkdown by Mirone. */\nimport type { MilkdownPlugin } from '@milkdown/ctx'\nimport { updatePlugin, uploadConfig } from './upload'\n\nexport * from './upload'\nexport * from './default-uploader'\n\nexport const upload: MilkdownPlugin[] = [uploadConfig, updatePlugin]\n"],"names":["readImageAsBase64","file","resolve","reader","defaultUploader","files","schema","imgs","i","image","missingNodeInSchema","img","alt","src","uploadConfig","$ctx","pos","spec","widgetDOM","Decoration","updatePlugin","$prose","ctx","pluginKey","PluginKey","findPlaceholder","state","id","decorations","found","_a","handleUpload","view","event","schemaCtx","tr","insertPos","uploader","fragment","e","Plugin","DecorationSet","set","_set","action","uploadWidgetFactory","decoration","target","enableHtmlFileUploader","_b","upload"],"mappings":"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"}
|
package/lib/upload.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Fragment, Node, Schema } from '@milkdown/prose/model';
|
|
2
|
-
import {
|
|
2
|
+
import { Decoration } from '@milkdown/prose/view';
|
|
3
3
|
export type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>;
|
|
4
|
-
export interface
|
|
4
|
+
export interface UploadConfig {
|
|
5
5
|
uploader: Uploader;
|
|
6
6
|
enableHtmlFileUploader: boolean;
|
|
7
|
+
uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration;
|
|
7
8
|
}
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
9
|
+
export declare const uploadConfig: import("@milkdown/utils").$Ctx<UploadConfig, "uploadConfig">;
|
|
10
|
+
export declare const updatePlugin: import("@milkdown/utils").$Prose;
|
|
10
11
|
//# sourceMappingURL=upload.d.ts.map
|
package/lib/upload.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../src/upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAInE,OAAO,EAAE,UAAU,EAAiB,MAAM,sBAAsB,CAAA;AAKhE,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAA;AAE7F,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,QAAQ,CAAA;IAClB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,mBAAmB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAA;CAChG;AAED,eAAO,MAAM,YAAY,8DAQP,CAAA;AAElB,eAAO,MAAM,YAAY,kCA4FvB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milkdown/plugin-upload",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "7.0.0-next.0",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Saul-Mirone/milkdown.git",
|
|
9
|
+
"directory": "packages/plugin-upload"
|
|
10
|
+
},
|
|
6
11
|
"keywords": [
|
|
7
12
|
"milkdown",
|
|
8
13
|
"milkdown plugin"
|
|
@@ -15,17 +20,19 @@
|
|
|
15
20
|
"src"
|
|
16
21
|
],
|
|
17
22
|
"peerDependencies": {
|
|
18
|
-
"@milkdown/core": "^
|
|
19
|
-
"@milkdown/
|
|
23
|
+
"@milkdown/core": "^7.0.0-next.0",
|
|
24
|
+
"@milkdown/ctx": "^7.0.0-next.0",
|
|
25
|
+
"@milkdown/prose": "^7.0.0-next.0"
|
|
20
26
|
},
|
|
21
27
|
"dependencies": {
|
|
22
28
|
"tslib": "^2.4.0",
|
|
23
|
-
"@milkdown/exception": "
|
|
24
|
-
"@milkdown/utils": "
|
|
29
|
+
"@milkdown/exception": "7.0.0-next.0",
|
|
30
|
+
"@milkdown/utils": "7.0.0-next.0"
|
|
25
31
|
},
|
|
26
32
|
"devDependencies": {
|
|
27
|
-
"@milkdown/core": "
|
|
28
|
-
"@milkdown/
|
|
33
|
+
"@milkdown/core": "7.0.0-next.0",
|
|
34
|
+
"@milkdown/ctx": "7.0.0-next.0",
|
|
35
|
+
"@milkdown/prose": "7.0.0-next.0"
|
|
29
36
|
},
|
|
30
37
|
"nx": {
|
|
31
38
|
"targets": {
|
package/src/default-uploader.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { Node } from '@milkdown/prose/model'
|
|
|
4
4
|
|
|
5
5
|
import type { Uploader } from './upload'
|
|
6
6
|
|
|
7
|
-
const readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {
|
|
7
|
+
export const readImageAsBase64 = (file: File): Promise<{ alt: string; src: string }> => {
|
|
8
8
|
return new Promise((resolve) => {
|
|
9
9
|
const reader = new FileReader()
|
|
10
10
|
reader.addEventListener(
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import {
|
|
2
|
+
import type { MilkdownPlugin } from '@milkdown/ctx'
|
|
3
|
+
import { updatePlugin, uploadConfig } from './upload'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
export * from './upload'
|
|
6
|
+
export * from './default-uploader'
|
|
5
7
|
|
|
6
|
-
export
|
|
7
|
-
export { key, uploadPlugin } from './upload'
|
|
8
|
-
|
|
9
|
-
export const upload = AtomList.create([uploadPlugin()])
|
|
8
|
+
export const upload: MilkdownPlugin[] = [uploadConfig, updatePlugin]
|
package/src/upload.ts
CHANGED
|
@@ -1,129 +1,122 @@
|
|
|
1
1
|
/* Copyright 2021, Milkdown by Mirone. */
|
|
2
|
-
import {
|
|
3
|
-
import { missingIcon } from '@milkdown/exception'
|
|
2
|
+
import { schemaCtx } from '@milkdown/core'
|
|
4
3
|
import type { Fragment, Node, Schema } from '@milkdown/prose/model'
|
|
5
4
|
import type { EditorState } from '@milkdown/prose/state'
|
|
6
5
|
import { Plugin, PluginKey } from '@milkdown/prose/state'
|
|
7
6
|
import type { EditorView } from '@milkdown/prose/view'
|
|
8
7
|
import { Decoration, DecorationSet } from '@milkdown/prose/view'
|
|
9
|
-
import {
|
|
8
|
+
import { $ctx, $prose } from '@milkdown/utils'
|
|
10
9
|
|
|
11
10
|
import { defaultUploader } from './default-uploader'
|
|
12
11
|
|
|
13
12
|
export type Uploader = (files: FileList, schema: Schema) => Promise<Fragment | Node | Node[]>
|
|
14
13
|
interface Spec { id: symbol; pos: number }
|
|
15
|
-
export interface
|
|
14
|
+
export interface UploadConfig {
|
|
16
15
|
uploader: Uploader
|
|
17
16
|
enableHtmlFileUploader: boolean
|
|
17
|
+
uploadWidgetFactory: (pos: number, spec: Parameters<typeof Decoration.widget>[2]) => Decoration
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
19
|
+
|
|
20
|
+
export const uploadConfig = $ctx<UploadConfig, 'uploadConfig'>({
|
|
21
|
+
uploader: defaultUploader,
|
|
22
|
+
enableHtmlFileUploader: false,
|
|
23
|
+
uploadWidgetFactory: (pos, spec) => {
|
|
24
|
+
const widgetDOM = document.createElement('span')
|
|
25
|
+
widgetDOM.textContent = 'Upload in progress...'
|
|
26
|
+
return Decoration.widget(pos, widgetDOM, spec)
|
|
27
|
+
},
|
|
28
|
+
}, 'uploadConfig')
|
|
29
|
+
|
|
30
|
+
export const updatePlugin = $prose((ctx) => {
|
|
31
|
+
const pluginKey = new PluginKey('MILKDOWN_UPLOAD')
|
|
32
|
+
|
|
33
|
+
const findPlaceholder = (state: EditorState, id: symbol): number => {
|
|
34
|
+
const decorations = pluginKey.getState(state)
|
|
35
|
+
if (!decorations)
|
|
36
|
+
return -1
|
|
37
|
+
const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)
|
|
38
|
+
if (!found.length)
|
|
39
|
+
return -1
|
|
40
|
+
return found[0]?.from ?? -1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {
|
|
44
|
+
if (!files || files.length <= 0)
|
|
45
|
+
return false
|
|
46
|
+
|
|
47
|
+
const id = Symbol('upload symbol')
|
|
48
|
+
const schema = ctx.get(schemaCtx)
|
|
49
|
+
const { tr } = view.state
|
|
50
|
+
const insertPos = event instanceof DragEvent
|
|
51
|
+
? view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? tr.selection.from
|
|
52
|
+
: tr.selection.from
|
|
53
|
+
view.dispatch(tr.setMeta(pluginKey, { add: { id, pos: insertPos } }))
|
|
54
|
+
|
|
55
|
+
const { uploader } = ctx.get(uploadConfig.key)
|
|
56
|
+
uploader(files, schema)
|
|
57
|
+
.then((fragment) => {
|
|
58
|
+
const pos = findPlaceholder(view.state, id)
|
|
59
|
+
if (pos < 0)
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
view.dispatch(
|
|
63
|
+
view.state.tr
|
|
64
|
+
.replaceWith(pos, pos, fragment)
|
|
65
|
+
.setMeta(pluginKey, { remove: { id } }),
|
|
66
|
+
)
|
|
65
67
|
})
|
|
68
|
+
.catch((e) => {
|
|
69
|
+
console.error(e)
|
|
70
|
+
})
|
|
71
|
+
return true
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return new Plugin({
|
|
75
|
+
key: pluginKey,
|
|
76
|
+
state: {
|
|
77
|
+
init() {
|
|
78
|
+
return DecorationSet.empty
|
|
79
|
+
},
|
|
80
|
+
apply(this: Plugin, tr, set) {
|
|
81
|
+
const _set = set.map(tr.mapping, tr.doc)
|
|
82
|
+
const action = tr.getMeta(this)
|
|
83
|
+
if (!action)
|
|
84
|
+
return _set
|
|
85
|
+
|
|
86
|
+
if (action.add) {
|
|
87
|
+
const { uploadWidgetFactory } = ctx.get(uploadConfig.key)
|
|
88
|
+
|
|
89
|
+
const decoration = uploadWidgetFactory(action.add.pos, { id: action.add.id })
|
|
90
|
+
return _set.add(tr.doc, [decoration])
|
|
91
|
+
}
|
|
92
|
+
if (action.remove) {
|
|
93
|
+
const target = _set.find(undefined, undefined, (spec: Spec) => spec.id === action.remove.id)
|
|
94
|
+
return _set.remove(target)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return _set
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
props: {
|
|
101
|
+
decorations(this: Plugin, state) {
|
|
102
|
+
return this.getState(state)
|
|
103
|
+
},
|
|
104
|
+
handlePaste: (view, event) => {
|
|
105
|
+
const { enableHtmlFileUploader } = ctx.get(uploadConfig.key)
|
|
106
|
+
if (!(event instanceof ClipboardEvent))
|
|
107
|
+
return false
|
|
66
108
|
|
|
67
|
-
|
|
68
|
-
const decorations = placeholderPlugin.getState(state)
|
|
69
|
-
if (!decorations)
|
|
70
|
-
return -1
|
|
71
|
-
const found = decorations.find(undefined, undefined, (spec: Spec) => spec.id === id)
|
|
72
|
-
if (!found.length)
|
|
73
|
-
return -1
|
|
74
|
-
return found[0]?.from ?? -1
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const handleUpload = (view: EditorView, event: DragEvent | ClipboardEvent, files: FileList | undefined) => {
|
|
78
|
-
if (!files || files.length <= 0)
|
|
109
|
+
if (!enableHtmlFileUploader && event.clipboardData?.getData('text/html'))
|
|
79
110
|
return false
|
|
80
111
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
view
|
|
88
|
-
|
|
89
|
-
uploader(files, schema)
|
|
90
|
-
.then((fragment) => {
|
|
91
|
-
const pos = findPlaceholder(view.state, id)
|
|
92
|
-
if (pos < 0)
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
view.dispatch(
|
|
96
|
-
view.state.tr
|
|
97
|
-
.replaceWith(pos, pos, fragment)
|
|
98
|
-
.setMeta(placeholderPlugin, { remove: { id } }),
|
|
99
|
-
)
|
|
100
|
-
})
|
|
101
|
-
.catch((e) => {
|
|
102
|
-
console.error(e)
|
|
103
|
-
})
|
|
104
|
-
return true
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const uploadPlugin = new Plugin({
|
|
108
|
-
props: {
|
|
109
|
-
handlePaste: (view, event) => {
|
|
110
|
-
if (!(event instanceof ClipboardEvent))
|
|
111
|
-
return false
|
|
112
|
-
|
|
113
|
-
if (!options?.enableHtmlFileUploader && event.clipboardData?.getData('text/html'))
|
|
114
|
-
return false
|
|
115
|
-
|
|
116
|
-
return handleUpload(view, event, event.clipboardData?.files)
|
|
117
|
-
},
|
|
118
|
-
handleDrop: (view, event) => {
|
|
119
|
-
if (!(event instanceof DragEvent))
|
|
120
|
-
return false
|
|
121
|
-
|
|
122
|
-
return handleUpload(view, event, event.dataTransfer?.files)
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
})
|
|
126
|
-
return [placeholderPlugin, uploadPlugin]
|
|
112
|
+
return handleUpload(view, event, event.clipboardData?.files)
|
|
113
|
+
},
|
|
114
|
+
handleDrop: (view, event) => {
|
|
115
|
+
if (!(event instanceof DragEvent))
|
|
116
|
+
return false
|
|
117
|
+
|
|
118
|
+
return handleUpload(view, event, event.dataTransfer?.files)
|
|
119
|
+
},
|
|
127
120
|
},
|
|
128
|
-
}
|
|
121
|
+
})
|
|
129
122
|
})
|