@writergate/quill-image-uploader-nextjs 0.1.8 → 0.1.9
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/quill.imageUploader.min.js +1 -1
- package/package.json +7 -3
- package/src/blots/comment.js +28 -0
- package/src/demo.js +49 -49
- package/src/quill.imageUploader.js +225 -200
- package/src/utils/delta-to-html.js +15 -0
- package/src/utils/nano-id.js +9 -0
@@ -1 +1 @@
|
|
1
|
-
!function(e){var t={};function n(i){if(t[i])return t[i].exports;var
|
1
|
+
!function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=1)}([function(e,t){e.exports=Quill},function(e,t,n){"use strict";n.r(t);var i=n(0),o=n.n(i),r=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),l=function e(t,n,i){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,n);if(void 0===o){var r=Object.getPrototypeOf(t);return null===r?void 0:e(r,n,i)}if("value"in o)return o.value;var l=o.get;return void 0!==l?l.call(i):void 0};function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}var u=function(e){function t(){return a(this,t),s(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),r(t,[{key:"deleteAt",value:function(e,n){l(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"deleteAt",this).call(this,e,n),this.cache={}}}],[{key:"create",value:function(e){var n=l(t.__proto__||Object.getPrototypeOf(t),"create",this).call(this,e);if(!0===e)return n;var i=document.createElement("img");return i.setAttribute("src",e),n.appendChild(i),n}},{key:"value",value:function(e){var t=e.dataset;return{src:t.src,custom:t.custom}}}]),t}(o.a.import("blots/block"));u.blotName="imageBlot",u.className="image-uploading",u.tagName="span",o.a.register({"formats/imageBlot":u});var c=u,f=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}();function d(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function h(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}var p=function(e){function t(){return d(this,t),h(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),f(t,null,[{key:"create",value:function(e){var n=function e(t,n,i){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,n);if(void 0===o){var r=Object.getPrototypeOf(t);return null===r?void 0:e(r,n,i)}if("value"in o)return o.value;var l=o.get;return void 0!==l?l.call(i):void 0}(t.__proto__||Object.getPrototypeOf(t),"create",this).call(this);return console.log(e),n.setAttribute("data-comment",e),n}},{key:"formats",value:function(e){return e.getAttribute("data-comment")||!0}}]),t}(o.a.import("blots/block"));p.blotName="hiddenCommentBlot",p.className="hidden-comment",p.tagName="span",o.a.register({"formats/hiddenCommentBlot":p});var m=p,g=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}();var v=function(){function e(t,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.quill=t,this.options=n,this.range=null,"function"!=typeof this.options.upload&&console.warn("[Missing config] upload function that returns a promise is required"),"function"!=typeof this.options.newComment&&console.warn("[Missing config] newComment function that returns a promise is required"),"function"!=typeof this.options.showComments&&console.warn("[Missing config] showComments function that returns a promise is required");var i=this.quill.getModule("toolbar");i.addHandler("image",this.selectLocalImage.bind(this)),i.addHandler("code-block",this.fixHighlighter.bind(this)),i.addHandler("clean",this.clean.bind(this)),i.addHandler("underline",this.addComment.bind(this)),i.addHandler("link",this.toggleLink.bind(this)),this.handleDrop=this.handleDrop.bind(this),this.handlePaste=this.handlePaste.bind(this),this.quill.root.addEventListener("drop",this.handleDrop,!1),this.quill.root.addEventListener("paste",this.handlePaste,!1)}return g(e,[{key:"toggleLink",value:function(e){e?this.quill.theme.tooltip.edit():this.quill.theme.tooltip.edit("link",this.quill.getFormat().link)}},{key:"addComment",value:function(){var e=this.quill.getSelection();console.log(e);var t=this.quill.getText(e.index,e.length);e&&e.length>0&&this.options.newComment&&(this.quill.insertEmbed(e.index-1,m.blotName,"new-comment","silent"),e.top=this.quill.getBounds(e.index,e.length).top,this.options.newComment(e,t),this.quill.insertEmbed(e.index,m.blotName,"new-comment-1","silent")),this.quill.theme.tooltip.hide()}},{key:"fixHighlighter",value:function(){var e=this.quill.getSelection(!0);if(!this.quill.getFormat(e)["code-block"])return this.quill.formatLine(e.index,e.length,"code-block","user");this.quill.removeFormat(e.index,e.length,"user"),this.quill.removeFormat(e.index,e.length,"user")}},{key:"clean",value:function(){var e=this.quill.getSelection(!0);this.quill.getFormat(e);this.quill.removeFormat(e.index,e.length,"user"),this.quill.removeFormat(e.index,e.length,"user")}},{key:"selectLocalImage",value:function(){var e=this;this.range=this.quill.getSelection(),this.fileHolder=document.createElement("input"),this.fileHolder.setAttribute("type","file"),this.fileHolder.setAttribute("accept","image/*"),this.fileHolder.setAttribute("style","visibility:hidden"),this.fileHolder.onchange=this.fileChanged.bind(this),document.body.appendChild(this.fileHolder),this.fileHolder.click(),window.requestAnimationFrame((function(){document.body.removeChild(e.fileHolder)}))}},{key:"handleDrop",value:function(e){var t=this;if(e.stopPropagation(),e.preventDefault(),e.dataTransfer&&e.dataTransfer.files&&e.dataTransfer.files.length){if(document.caretRangeFromPoint){var n=document.getSelection(),i=document.caretRangeFromPoint(e.clientX,e.clientY);n&&i&&n.setBaseAndExtent(i.startContainer,i.startOffset,i.startContainer,i.startOffset)}else{var o=document.getSelection(),r=document.caretPositionFromPoint(e.clientX,e.clientY);o&&r&&o.setBaseAndExtent(r.offsetNode,r.offset,r.offsetNode,r.offset)}this.range=this.quill.getSelection();var l=e.dataTransfer.files[0];setTimeout((function(){t.range=t.quill.getSelection(),t.readAndUploadFile(l)}),0)}}},{key:"handlePaste",value:function(e){var t=this,n=e.clipboardData||window.clipboardData;if(n&&(n.items||n.files))for(var i=n.items||n.files,o=/^image\/(jpe?g|gif|png|svg|webp)$/i,r=0;r<i.length;r++)o.test(i[r].type)&&function(){var n=i[r].getAsFile?i[r].getAsFile():i[r];n&&(t.range=t.quill.getSelection(),e.preventDefault(),setTimeout((function(){t.range=t.quill.getSelection(),t.readAndUploadFile(n)}),0))}()}},{key:"readAndUploadFile",value:function(e){var t=this,n=!1,i=new FileReader;i.addEventListener("load",(function(){if(!n){var e=i.result;t.insertBase64Image(e)}}),!1),e&&i.readAsDataURL(e),this.options.upload(e).then((function(e){t.insertToEditor(e)}),(function(e){n=!0,t.removeBase64Image(),console.warn(e)}))}},{key:"fileChanged",value:function(){var e=this.fileHolder.files[0];this.readAndUploadFile(e)}},{key:"insertBase64Image",value:function(e){var t=this.range;this.quill.insertEmbed(t.index,c.blotName,""+e,"user")}},{key:"insertToEditor",value:function(e){var t=this.range;this.quill.deleteText(t.index,3,"user"),this.quill.insertEmbed(t.index,"image",""+e,"user"),t.index++,this.quill.setSelection(t,"user")}},{key:"removeBase64Image",value:function(){var e=this.range;this.quill.deleteText(e.index,3,"user")}}]),e}();window.ImageUploader=v;t.default=v}]);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@writergate/quill-image-uploader-nextjs",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.9",
|
4
4
|
"repository": {
|
5
5
|
"type": "git",
|
6
6
|
"url": "git+https://github.com/enlear/quill-image-uploader-nextjs.git"
|
@@ -58,5 +58,9 @@
|
|
58
58
|
"bugs": {
|
59
59
|
"url": "https://github.com/enlear/quill-image-uploader-nextjs/issues"
|
60
60
|
},
|
61
|
-
"homepage": "https://github.com/enlear/quill-image-uploader-nextjs#readme"
|
62
|
-
|
61
|
+
"homepage": "https://github.com/enlear/quill-image-uploader-nextjs#readme",
|
62
|
+
"dependencies": {
|
63
|
+
"nanoid": "^4.0.2",
|
64
|
+
"quill-delta-to-html": "^0.12.1"
|
65
|
+
}
|
66
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import Quill from "quill";
|
2
|
+
|
3
|
+
const InlineBlot = Quill.import("blots/block");
|
4
|
+
|
5
|
+
class CommentBlot extends InlineBlot {
|
6
|
+
/**
|
7
|
+
*
|
8
|
+
* @param {{commentId:string, commentInfo:string}} Comment ID of creating comment + DOM representation of selected content
|
9
|
+
* @returns
|
10
|
+
*/
|
11
|
+
static create({ commentId, commentInfo }) {
|
12
|
+
const node = super.create();
|
13
|
+
node.setAttribute("data-comment", commentId);
|
14
|
+
node.innerHtml = commentInfo;
|
15
|
+
return node;
|
16
|
+
}
|
17
|
+
|
18
|
+
static formats(node) {
|
19
|
+
return node.getAttribute("data-comment") || true;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
CommentBlot.blotName = "CommentBlot";
|
24
|
+
CommentBlot.className = "comment";
|
25
|
+
CommentBlot.tagName = "span";
|
26
|
+
Quill.register({ "formats/hiddenCommentBlot": CommentBlot });
|
27
|
+
|
28
|
+
export default CommentBlot;
|
package/src/demo.js
CHANGED
@@ -5,62 +5,62 @@ Quill.debug("warn");
|
|
5
5
|
Quill.register("modules/imageUploader", ImageUploader);
|
6
6
|
|
7
7
|
const fullToolbarOptions = [
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
[{ header: [1, 2, 3, false] }],
|
9
|
+
["bold", "italic"],
|
10
|
+
["clean"],
|
11
|
+
["image"],
|
12
12
|
];
|
13
13
|
var quill = new Quill("#editor", {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
},
|
32
|
-
false
|
33
|
-
);
|
34
|
-
|
35
|
-
if (file) {
|
36
|
-
fileReader.readAsDataURL(file);
|
37
|
-
} else {
|
38
|
-
reject("No file selected");
|
39
|
-
}
|
40
|
-
});
|
14
|
+
theme: "snow",
|
15
|
+
modules: {
|
16
|
+
toolbar: {
|
17
|
+
container: fullToolbarOptions,
|
18
|
+
},
|
19
|
+
imageUploader: {
|
20
|
+
upload: (file) => {
|
21
|
+
const fileReader = new FileReader();
|
22
|
+
return new Promise((resolve, reject) => {
|
23
|
+
fileReader.addEventListener(
|
24
|
+
"load",
|
25
|
+
() => {
|
26
|
+
let base64ImageSrc = fileReader.result;
|
27
|
+
setTimeout(() => {
|
28
|
+
resolve(base64ImageSrc);
|
29
|
+
//reject('Issue uploading file');
|
30
|
+
}, 1500);
|
41
31
|
},
|
42
|
-
|
32
|
+
false
|
33
|
+
);
|
34
|
+
|
35
|
+
if (file) {
|
36
|
+
fileReader.readAsDataURL(file);
|
37
|
+
} else {
|
38
|
+
reject("No file selected");
|
39
|
+
}
|
40
|
+
});
|
41
|
+
},
|
43
42
|
},
|
43
|
+
},
|
44
44
|
});
|
45
45
|
|
46
|
-
quill.on("text-change", function(delta, oldDelta, source) {
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
quill.on("text-change", function (delta, oldDelta, source) {
|
47
|
+
if (source == "api") {
|
48
|
+
console.log("An API call triggered this change.");
|
49
|
+
} else if (source == "user") {
|
50
|
+
console.log("A user action triggered this change.");
|
51
|
+
}
|
52
|
+
console.log(oldDelta, delta);
|
53
53
|
});
|
54
54
|
|
55
|
-
quill.on("selection-change", function(range, oldRange, source) {
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
} else {
|
60
|
-
var text = quill.getText(range.index, range.length);
|
61
|
-
console.log("User has highlighted", text);
|
62
|
-
}
|
55
|
+
quill.on("selection-change", function (range, oldRange, source) {
|
56
|
+
if (range) {
|
57
|
+
if (range.length == 0) {
|
58
|
+
console.log("User cursor is on", range.index);
|
63
59
|
} else {
|
64
|
-
|
60
|
+
var text = quill.getText(range.index, range.length);
|
61
|
+
console.log("User has highlighted", text);
|
65
62
|
}
|
66
|
-
}
|
63
|
+
} else {
|
64
|
+
console.log("Cursor not in the editor");
|
65
|
+
}
|
66
|
+
});
|
@@ -1,229 +1,254 @@
|
|
1
1
|
import LoadingImage from "./blots/image.js";
|
2
|
+
import CommentBlot from "./blots/comment.js";
|
3
|
+
import GenerateRandomId from "./utils/nano-id.js";
|
4
|
+
import DeltaToHtml from "./utils/delta-to-html.js";
|
2
5
|
|
3
6
|
class ImageUploader {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
7
|
+
constructor(quill, options) {
|
8
|
+
this.quill = quill;
|
9
|
+
this.options = options;
|
10
|
+
this.range = null;
|
11
|
+
|
12
|
+
if (typeof this.options.upload !== "function")
|
13
|
+
console.warn(
|
14
|
+
"[Missing config] upload function that returns a promise is required"
|
15
|
+
);
|
16
|
+
|
17
|
+
if (typeof this.options.newComment !== "function")
|
18
|
+
console.warn(
|
19
|
+
"[Missing config] newComment function that returns a promise is required"
|
20
|
+
);
|
21
|
+
|
22
|
+
if (typeof this.options.showComments !== "function")
|
23
|
+
console.warn(
|
24
|
+
"[Missing config] showComments function that returns a promise is required"
|
25
|
+
);
|
26
|
+
|
27
|
+
var toolbar = this.quill.getModule("toolbar");
|
28
|
+
toolbar.addHandler("image", this.selectLocalImage.bind(this));
|
29
|
+
toolbar.addHandler("code-block", this.fixHighlighter.bind(this));
|
30
|
+
toolbar.addHandler("clean", this.clean.bind(this));
|
31
|
+
toolbar.addHandler("underline", this.addComment.bind(this));
|
32
|
+
toolbar.addHandler("link", this.toggleLink.bind(this));
|
33
|
+
|
34
|
+
this.handleDrop = this.handleDrop.bind(this);
|
35
|
+
this.handlePaste = this.handlePaste.bind(this);
|
36
|
+
|
37
|
+
this.quill.root.addEventListener("drop", this.handleDrop, false);
|
38
|
+
this.quill.root.addEventListener("paste", this.handlePaste, false);
|
39
|
+
}
|
40
|
+
|
41
|
+
toggleLink(formatTextToLink) {
|
42
|
+
if (formatTextToLink) {
|
43
|
+
this.quill.theme.tooltip.edit();
|
44
|
+
} else {
|
45
|
+
this.quill.theme.tooltip.edit("link", this.quill.getFormat().link);
|
36
46
|
}
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
}
|
48
|
+
|
49
|
+
addComment() {
|
50
|
+
const commentId = GenerateRandomId();
|
51
|
+
var range = this.quill.getSelection();
|
52
|
+
if (range && range.length > 0 && this.options.newComment) {
|
53
|
+
range.top = this.quill.getBounds(range.index, range.length).top;
|
54
|
+
|
55
|
+
const selectedContents = this.quill.getContents(
|
56
|
+
range.index,
|
57
|
+
range.length
|
58
|
+
);
|
59
|
+
|
60
|
+
const selectedText = this.quill.getText(range.index, range.length);
|
61
|
+
const selectedHTML = DeltaToHtml(selectedContents);
|
62
|
+
|
63
|
+
console.log({ selectedContents, selectedText, selectedHTML });
|
64
|
+
|
65
|
+
this.quill.deleteText(range.index, range.length);
|
66
|
+
this.quill.insertEmbed(
|
67
|
+
range.index,
|
68
|
+
CommentBlot.blotName,
|
69
|
+
{ commentId, commentInfo: selectedHTML },
|
70
|
+
"silent"
|
71
|
+
);
|
72
|
+
this.options.newComment(range, selectedText, commentId);
|
44
73
|
}
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
74
|
+
this.quill.theme.tooltip.hide();
|
75
|
+
}
|
76
|
+
|
77
|
+
fixHighlighter() {
|
78
|
+
const range = this.quill.getSelection(true);
|
79
|
+
const formats = this.quill.getFormat(range);
|
80
|
+
// if its not a code-block yet, turn it into one.
|
81
|
+
if (!formats["code-block"]) {
|
82
|
+
return this.quill.formatLine(
|
83
|
+
range.index,
|
84
|
+
range.length,
|
85
|
+
"code-block",
|
86
|
+
"user"
|
87
|
+
);
|
55
88
|
}
|
56
89
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
90
|
+
// if it was a code-block, and the user meant to remove it
|
91
|
+
this.quill.removeFormat(range.index, range.length, "user");
|
92
|
+
// running it twise to remove colors
|
93
|
+
this.quill.removeFormat(range.index, range.length, "user");
|
94
|
+
}
|
95
|
+
|
96
|
+
clean() {
|
97
|
+
const range = this.quill.getSelection(true);
|
98
|
+
const formats = this.quill.getFormat(range);
|
99
|
+
// running it twise to remove colors
|
100
|
+
this.quill.removeFormat(range.index, range.length, "user");
|
101
|
+
this.quill.removeFormat(range.index, range.length, "user");
|
102
|
+
}
|
103
|
+
|
104
|
+
selectLocalImage() {
|
105
|
+
this.range = this.quill.getSelection();
|
106
|
+
this.fileHolder = document.createElement("input");
|
107
|
+
this.fileHolder.setAttribute("type", "file");
|
108
|
+
this.fileHolder.setAttribute("accept", "image/*");
|
109
|
+
this.fileHolder.setAttribute("style", "visibility:hidden");
|
110
|
+
|
111
|
+
this.fileHolder.onchange = this.fileChanged.bind(this);
|
112
|
+
|
113
|
+
document.body.appendChild(this.fileHolder);
|
114
|
+
|
115
|
+
this.fileHolder.click();
|
116
|
+
|
117
|
+
window.requestAnimationFrame(() => {
|
118
|
+
document.body.removeChild(this.fileHolder);
|
119
|
+
});
|
120
|
+
}
|
121
|
+
|
122
|
+
handleDrop(evt) {
|
123
|
+
evt.stopPropagation();
|
124
|
+
evt.preventDefault();
|
125
|
+
if (
|
126
|
+
evt.dataTransfer &&
|
127
|
+
evt.dataTransfer.files &&
|
128
|
+
evt.dataTransfer.files.length
|
129
|
+
) {
|
130
|
+
if (document.caretRangeFromPoint) {
|
131
|
+
const selection = document.getSelection();
|
132
|
+
const range = document.caretRangeFromPoint(evt.clientX, evt.clientY);
|
133
|
+
if (selection && range) {
|
134
|
+
selection.setBaseAndExtent(
|
135
|
+
range.startContainer,
|
136
|
+
range.startOffset,
|
137
|
+
range.startContainer,
|
138
|
+
range.startOffset
|
139
|
+
);
|
140
|
+
}
|
141
|
+
} else {
|
142
|
+
const selection = document.getSelection();
|
143
|
+
const range = document.caretPositionFromPoint(evt.clientX, evt.clientY);
|
144
|
+
if (selection && range) {
|
145
|
+
selection.setBaseAndExtent(
|
146
|
+
range.offsetNode,
|
147
|
+
range.offset,
|
148
|
+
range.offsetNode,
|
149
|
+
range.offset
|
150
|
+
);
|
151
|
+
}
|
152
|
+
}
|
70
153
|
|
71
|
-
|
72
|
-
|
73
|
-
const formats = this.quill.getFormat(range);
|
74
|
-
// running it twise to remove colors
|
75
|
-
this.quill.removeFormat(range.index, range.length, 'user');
|
76
|
-
this.quill.removeFormat(range.index, range.length, 'user');
|
77
|
-
}
|
154
|
+
this.range = this.quill.getSelection();
|
155
|
+
let file = evt.dataTransfer.files[0];
|
78
156
|
|
79
|
-
|
157
|
+
setTimeout(() => {
|
80
158
|
this.range = this.quill.getSelection();
|
81
|
-
this.
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
this.fileHolder.onchange = this.fileChanged.bind(this);
|
87
|
-
|
88
|
-
document.body.appendChild(this.fileHolder);
|
159
|
+
this.readAndUploadFile(file);
|
160
|
+
}, 0);
|
161
|
+
}
|
162
|
+
}
|
89
163
|
|
90
|
-
|
164
|
+
handlePaste(evt) {
|
165
|
+
let clipboard = evt.clipboardData || window.clipboardData;
|
91
166
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
167
|
+
// IE 11 is .files other browsers are .items
|
168
|
+
if (clipboard && (clipboard.items || clipboard.files)) {
|
169
|
+
let items = clipboard.items || clipboard.files;
|
170
|
+
const IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png|svg|webp)$/i;
|
96
171
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
if (
|
101
|
-
evt.dataTransfer &&
|
102
|
-
evt.dataTransfer.files &&
|
103
|
-
evt.dataTransfer.files.length
|
104
|
-
) {
|
105
|
-
if (document.caretRangeFromPoint) {
|
106
|
-
const selection = document.getSelection();
|
107
|
-
const range = document.caretRangeFromPoint(evt.clientX, evt.clientY);
|
108
|
-
if (selection && range) {
|
109
|
-
selection.setBaseAndExtent(
|
110
|
-
range.startContainer,
|
111
|
-
range.startOffset,
|
112
|
-
range.startContainer,
|
113
|
-
range.startOffset
|
114
|
-
);
|
115
|
-
}
|
116
|
-
} else {
|
117
|
-
const selection = document.getSelection();
|
118
|
-
const range = document.caretPositionFromPoint(evt.clientX, evt.clientY);
|
119
|
-
if (selection && range) {
|
120
|
-
selection.setBaseAndExtent(
|
121
|
-
range.offsetNode,
|
122
|
-
range.offset,
|
123
|
-
range.offsetNode,
|
124
|
-
range.offset
|
125
|
-
);
|
126
|
-
}
|
127
|
-
}
|
172
|
+
for (let i = 0; i < items.length; i++) {
|
173
|
+
if (IMAGE_MIME_REGEX.test(items[i].type)) {
|
174
|
+
let file = items[i].getAsFile ? items[i].getAsFile() : items[i];
|
128
175
|
|
176
|
+
if (file) {
|
129
177
|
this.range = this.quill.getSelection();
|
130
|
-
|
131
|
-
|
178
|
+
evt.preventDefault();
|
132
179
|
setTimeout(() => {
|
133
|
-
|
134
|
-
|
180
|
+
this.range = this.quill.getSelection();
|
181
|
+
this.readAndUploadFile(file);
|
135
182
|
}, 0);
|
183
|
+
}
|
136
184
|
}
|
185
|
+
}
|
137
186
|
}
|
187
|
+
}
|
138
188
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
// IE 11 is .files other browsers are .items
|
143
|
-
if (clipboard && (clipboard.items || clipboard.files)) {
|
144
|
-
let items = clipboard.items || clipboard.files;
|
145
|
-
const IMAGE_MIME_REGEX = /^image\/(jpe?g|gif|png|svg|webp)$/i;
|
146
|
-
|
147
|
-
for (let i = 0; i < items.length; i++) {
|
148
|
-
if (IMAGE_MIME_REGEX.test(items[i].type)) {
|
149
|
-
let file = items[i].getAsFile ? items[i].getAsFile() : items[i];
|
150
|
-
|
151
|
-
if (file) {
|
152
|
-
this.range = this.quill.getSelection();
|
153
|
-
evt.preventDefault();
|
154
|
-
setTimeout(() => {
|
155
|
-
this.range = this.quill.getSelection();
|
156
|
-
this.readAndUploadFile(file);
|
157
|
-
}, 0);
|
158
|
-
}
|
159
|
-
}
|
160
|
-
}
|
161
|
-
}
|
162
|
-
}
|
163
|
-
|
164
|
-
readAndUploadFile(file) {
|
165
|
-
let isUploadReject = false;
|
189
|
+
readAndUploadFile(file) {
|
190
|
+
let isUploadReject = false;
|
166
191
|
|
167
|
-
|
192
|
+
const fileReader = new FileReader();
|
168
193
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
}
|
176
|
-
},
|
177
|
-
false
|
178
|
-
);
|
179
|
-
|
180
|
-
if (file) {
|
181
|
-
fileReader.readAsDataURL(file);
|
194
|
+
fileReader.addEventListener(
|
195
|
+
"load",
|
196
|
+
() => {
|
197
|
+
if (!isUploadReject) {
|
198
|
+
let base64ImageSrc = fileReader.result;
|
199
|
+
this.insertBase64Image(base64ImageSrc);
|
182
200
|
}
|
201
|
+
},
|
202
|
+
false
|
203
|
+
);
|
183
204
|
|
184
|
-
|
185
|
-
|
186
|
-
this.insertToEditor(imageUrl);
|
187
|
-
},
|
188
|
-
(error) => {
|
189
|
-
isUploadReject = true;
|
190
|
-
this.removeBase64Image();
|
191
|
-
console.warn(error);
|
192
|
-
}
|
193
|
-
);
|
194
|
-
}
|
195
|
-
|
196
|
-
fileChanged() {
|
197
|
-
const file = this.fileHolder.files[0];
|
198
|
-
this.readAndUploadFile(file);
|
199
|
-
}
|
200
|
-
|
201
|
-
insertBase64Image(url) {
|
202
|
-
const range = this.range;
|
203
|
-
this.quill.insertEmbed(
|
204
|
-
range.index,
|
205
|
-
LoadingImage.blotName,
|
206
|
-
`${url}`,
|
207
|
-
"user"
|
208
|
-
);
|
205
|
+
if (file) {
|
206
|
+
fileReader.readAsDataURL(file);
|
209
207
|
}
|
210
208
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
209
|
+
this.options.upload(file).then(
|
210
|
+
(imageUrl) => {
|
211
|
+
this.insertToEditor(imageUrl);
|
212
|
+
},
|
213
|
+
(error) => {
|
214
|
+
isUploadReject = true;
|
215
|
+
this.removeBase64Image();
|
216
|
+
console.warn(error);
|
217
|
+
}
|
218
|
+
);
|
219
|
+
}
|
220
|
+
|
221
|
+
fileChanged() {
|
222
|
+
const file = this.fileHolder.files[0];
|
223
|
+
this.readAndUploadFile(file);
|
224
|
+
}
|
225
|
+
|
226
|
+
insertBase64Image(url) {
|
227
|
+
const range = this.range;
|
228
|
+
this.quill.insertEmbed(
|
229
|
+
range.index,
|
230
|
+
LoadingImage.blotName,
|
231
|
+
`${url}`,
|
232
|
+
"user"
|
233
|
+
);
|
234
|
+
}
|
235
|
+
|
236
|
+
insertToEditor(url) {
|
237
|
+
const range = this.range;
|
238
|
+
// Delete the placeholder image
|
239
|
+
this.quill.deleteText(range.index, 3, "user");
|
240
|
+
// Insert the server saved image
|
241
|
+
this.quill.insertEmbed(range.index, "image", `${url}`, "user");
|
242
|
+
|
243
|
+
range.index++;
|
244
|
+
this.quill.setSelection(range, "user");
|
245
|
+
}
|
246
|
+
|
247
|
+
removeBase64Image() {
|
248
|
+
const range = this.range;
|
249
|
+
this.quill.deleteText(range.index, 3, "user");
|
250
|
+
}
|
226
251
|
}
|
227
252
|
|
228
253
|
window.ImageUploader = ImageUploader;
|
229
|
-
export default ImageUploader;
|
254
|
+
export default ImageUploader;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
const QuillDeltaToHtmlConverter =
|
2
|
+
require("quill-delta-to-html").QuillDeltaToHtmlConverter;
|
3
|
+
|
4
|
+
/**
|
5
|
+
*
|
6
|
+
* @param deltaOpsn The Delta Operation to convert to HTML
|
7
|
+
* @param cfg The configuration of the Converter - https://github.com/nozer/quill-delta-to-html#configuration
|
8
|
+
* @description https://github.com/nozer/quill-delta-to-html
|
9
|
+
*/
|
10
|
+
const deltaToHtml = (deltaOpsn, cfg = {}) => {
|
11
|
+
const converter = new QuillDeltaToHtmlConverter(deltaOps, cfg);
|
12
|
+
return converter.convert();
|
13
|
+
};
|
14
|
+
|
15
|
+
export default deltaToHtml;
|