chenjuneking / quill-image-drop-and-paste Goto Github PK
View Code? Open in Web Editor NEWA quill editor module for drop and paste image, with a callback hook before insert image into the editor
License: ISC License
A quill editor module for drop and paste image, with a callback hook before insert image into the editor
License: ISC License
Formatted text from Google Docs will become no format text on Quill if I enable this module.
Text from MS Word will be considered as image using this module and still no format text on Quill. So the editor will have 2: 1 is the image of text, 1 is the no format text.
Getting error
"export 'default' (imported as 'QuillImageDropAndPaste') was not found in 'quill-image-drop-and-paste'
import QuillImageDropAndPaste from 'quill-image-drop-and-paste'
Hello, just a very minor issue here. It appears the type definition requires the filename
parameter of ImageData.toFile
although the documentation says it is optional:
quill-image-drop-and-paste/src/index.d.ts
Line 14 in 8fb0def
I think this is due to the abstract method definition here:
Even though the implementation makes it optional here:
Judging by the code there, I can work around this by passing an empty string as the parameter, but I thought you might like to fix the typing to match.
Pretty simple. Upgrade to Quill 2.0, drag over an image and even if your handler is set, Parchment Image Blot runs trying to create the dropped image.
It's pretty clear to me that minified distributed Quill 1.3.7 was actually using a different version of quill-delta. So the issue may lie there rather than once we get to the parchment script.
Quill 2.0.1
Quill-Delta 5.1.0
Angular 17.3.7
Ngx-Quill 25.3.2
Hi there . I was playing with Script Demo (vanilla js) to see if I can drag image into editor container.
I have two questions.
Many tanks.
Hey guys ,
I am trying to implement drop and paste , i basically want catch image and upload to cloud instead of using base64 .
The code below is my current implementation . But I get the error TypeError: moduleClass is not a constructor
.
Not sure what is wrong.
Any help is very much appreciated, thanks.
Versions:
"react-quill": "^2.0.0-beta.2",
"quill": "^1.3.7",
"quill-image-drop-and-paste": "^1.2.5",
import React, { useState, useRef, useEffect } from "react";
// KaTeX dependency
import katex from "katex";
import "katex/dist/katex.css";
// Quill dependency
const Quill =
typeof window === "object" ? require("react-quill").Quill : () => false;
const ReactQuill =
typeof window === "object" ? require("react-quill") : () => false;
import "react-quill/dist/quill.snow.css";
const QuillImageDropAndPaste =
typeof window === "object"
? require("quill-image-drop-and-paste")
: () => false;
// MathQuill dependency
import "jquery";
typeof window === "object"
? require("mathquill/build/mathquill.js")
: () => false;
import "mathquill/build/mathquill.css";
const mathquill4quill =
typeof window === "object" ? require("mathquill4quill") : () => false;
import "mathquill4quill/mathquill4quill.css";
//Global definition
if (typeof window !== "undefined") {
window.Quill = Quill;
window.katex = katex;
}
export default function QuillPage() {
const [load, setLoad] = useState(true);
const [value, setValue] = useState("");
const quillRef = useRef();
useEffect(() => {
Quill.register("modules/imageDropAndPaste", QuillImageDropAndPaste);
// window.Quill = Quill;
window.katex = katex;
const enableMathQuillFormulaAuthoring = mathquill4quill({ Quill, katex });
console.log(window);
enableMathQuillFormulaAuthoring(
quillRef.current.editor,
{
operators: [
["\\pm", "\\pm"],
["\\sqrt{x}", "\\sqrt"],
["\\sqrt[n]{x}", "\\nthroot"],
["\\frac{x}{y}", "\\frac"],
["\\sum^{s}_{x}{d}", "\\sum"],
["\\prod^{s}_{x}{d}", "\\prod"],
["\\coprod^{s}_{x}{d}", "\\coprod"],
["\\int^{s}_{x}{d}", "\\int"],
["\\binom{n}{k}", "\\binom"],
["\\log{x}", "\\log"],
],
displayHistory: true, // defaults to false
historyCacheKey: "__my_app_math_history_cachekey_", // optional
historySize: 20, // optional (defaults to 10)
},
quillRef.current.options
);
setLoad(false);
}, [quillRef]);
useEffect(() => {
console.log(value);
}, [value]);
const imageHandler = () => {
console.log("image");
};
return (
<>
<ReactQuill
ref={quillRef}
modules={{
formula: true,
imageDropAndPaste: {
handler: imageHandler(),
},
toolbar: [["formula", "image"]],
}}
theme="snow"
value={value}
onChange={setValue}
/>
</>
);
}
Initially I thought it would work for angular, however I can't get it to work. the following error keeps coming back
Error: Uncaught (in promise): TypeError: moduleClass is not a constructor
TypeError: moduleClass is not a constructor
also
import * as QuillImageDropAndPaste from 'quill-image-drop-and-paste';
gives an error, even though the module is installed. following error:
Cannot find module 'quill-image-drop-and-paste' or its corresponding type declarations.
I thought that the following code worked, but it does not
const QuillImageDropAndPaste = require('quill-image-drop-and-paste');
Quill.register('modules/imageDropAndPaste', QuillImageDropAndPaste);
any thoughts?
i'm also using https://www.npmjs.com/package/ngx-quill
I tested this on the plunker demo and tried to drag-drop the gif from giphy extension. it didn't work.
I have defined a custom image handler and that does trigger a modal to upload an image and that does work.
I also replaced it with a function that only does alert("Works!");
just to be sure it's not the cause of my issue.
However immediately upon pasting the image inside the editor, I immediately get an inserted image as a string blob inserted into the editor. This way after continuing with my upload modal, I end up having two images.
Once the inline string blob and once an image tag with my uploaded image as src.
PS: There is a typo in the docs: "didnot" => "did not". ;)
If you didnot config a image handler, it will insert the image with dataURL into the quill editor directory after your drop/paste.
Any help on how to prevent the default behaviour is highly appreciated. 🙏
quill-image-drop-and-paste
: '1.2.9'
Paste related questions:
https://github.surmon.me/vue-quill-editor
https://www.vuescript.com/quill-editor-component-vue2/
https://www.vuescript.com/quill-editor-component-vue2/
quill-editor
Hi!
I've got an error with latest Quill 1.3.6:
filepond.js:8694 Uncaught (in promise) ReferenceError: position is not defined
at Object.root.ref.paster.onload (filepond.js:8694)
at cb (filepond.js:7929)
at filepond.js:7894
at Array.forEach (<anonymous>)
at filepond.js:7893
Any ideas how to fix it?
I see in README that you create filename yourself, but is it possible to inherit it from pasted / dropped file?
hello i found some issue,
The plugin doesn't work when copy image from web, handler doesn't call at all
but its work when i copy from my local drive
I've tested it on Chrome on Windows 10
Hey,
I successfully implemented a conversion from base64 to a file and uploaded that to PHP with this code:
/**
* Do something to our dropped or pasted image
* @param.imageDataUrl - image's base64 url
* @param.type - image's mime type
*/
function imageDropAndPasteHandler(imageDataUrl, type) {
// give a default mime type if the type was null
if (!type) type = 'image/png';
var imageData = imageDataUrl.replace(/^data:image\/\w+;base64,/, '');
var byteCharacters = b64_to_utf8(imageData);
const byteNumbers = new Array(byteCharacters.length);
// Each character's code point (charCode) will be the value of the byte.
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
var imageBlob = new Blob([byteArray], {type: `${type}`});
var imageFile = new File([imageBlob], "image.png", {type: `${type}`});
// generate a form data
var formData = new FormData()
formData.append('image', imageFile)
const xhr = new XMLHttpRequest();
xhr.open('POST', 'upload/supportEditorImage', true);
xhr.onload = () => {
if (xhr.status === 200) {
// this is callback data: url
console.log(xhr.response);
const url = JSON.parse(xhr.responseText).fileUrl;
insertToEditor(url);
}
};
xhr.send(formData);
}
But my question is:
Would it be possible to avoid this base64->File conversion by gettting directly the copied file?
If no, I'll stick with my solution.
Cheers,
Gilles
I tried to minify a 1024x1024px jpg image of 48Kb size to 320x320px, type .jpg, quality 0.7, the resulting image is 52Kb. Roughly 1/9 th reduction in pixel data but resulting image size is bigger. When we are drawing an RGB formatted image on a canvas, there will be 33% increase because of transparency for same size, that can't be avoided as of now. I think from canvas we can directly get Blob and we can read the initial image as Blob too. So internal logic of resizing could be lot more efficient.
I can't seem to get this up and running with Vue. I tried unsuccessfully to get it going in my own app and after trying different things over a few hours I decided to try and just get your example up and running to see what I'm doing wrong.
I cloned the repot and went into the examples folder, into the vue folder and ran straight from your code and it's not working there either.
None of the consoles you have set to run in the imageHandler fire and I threw a few debuggers in and around and node of them hit in the handler. Nothing from your code was modified beside adding the debugger.
When a plain text file is dropped on editor, following errors are raised at browser console and drop event fails (Chrome Version 91.0.4472.164 (Official Build) (64-bit))
QuillImageDropAndPaste.js:162 Uncaught TypeError: file.getAsString is not a function
at QuillImageDropAndPaste.js:162
at FileList.forEach ()
at ImageDropAndPaste.readFiles (QuillImageDropAndPaste.js:152)
at ImageDropAndPaste.handleDrop (QuillImageDropAndPaste.js:121)
(anonymous) @ QuillImageDropAndPaste.js:162
readFiles @ QuillImageDropAndPaste.js:152
handleDrop @ QuillImageDropAndPaste.js:121
https://codesandbox.io/s/grzyb9k-quill-problem-image-handler-3gqxuu
When i try do this i have errors:
this.imageHandler is not a function
When i change addEventListener
to arrow function i got error:
Uncaught TypeError: ImageData constructor: Argument 1 is not an object.
And last when i try arrow function in addHandler
i got error:
Uncaught TypeError: _this.container is undefined
Please help me with this, what I need to do?
When I dropped a first pic, it is fine.
But when I want to drop a second pic after the first one, it was always dropped before the first pic and cannot be dropped after it.
Hi guys, thanks for provision of this helpful package!
Unfortunately, there is no indication of the license. This means, in legal terms, that the use of the package is basically prohibited. No matter whether in a private or commercial environment.
I would like to use the package in one of my projects, but I can't because of the restriction described above.
Could you please add the information about the license?
Here are a few suggestions about the possible license:
https://opensource.org/licenses/MIT
https://opensource.org/licenses/ISC
https://opensource.org/licenses/Apache-2.0
Hi, is there a way to enhance this plug in with the paste of image URL?
It will make it a complete plugin
Hey guys, I'm using vue and it's 100% as in your example.
All works except when copy / paste the file.
Used Latest Firefox & Google Chrome.
Drang & Drop is working good.
Can't find whats is wrong. Can you guys look at this ?
A network request is sent whenever a URL is pasted in the editor.
& if the URL is of an image it is replaced with an image. which is not the behavior I need.
Can there be any workaround to run this function urlIsImage optionally?
Can a parameter be passed to use this functionality depending on the use case?
Hi,
I face an error when using the quill-image-drop-and-paste, When using the upload file custom handler.
I am using nextJS
The error : IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number.
Any help regarding this very much appreciated . @chenjuneking
Attached below is my code .
import React, { useState } from "react";
import { useQuill } from "react-quilljs";
import axios from "components/shared/Axios";
export default () => {
const imageHandler = async (dataUrl, type, imageData) => {
console.log("imageHandler", dataUrl, type, imageData);
const types = dataUrl.match(/image\/[^;]+/);
var file = imageData.toFile("something." + types);
var blob = imageData.toBlob();
const formData = new FormData();
formData.append("file", file);
axios
.post(`${process.env.NEXT_PUBLIC_API}/upload-file`, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
responseType: "json",
})
.then((res) => {
if (res.data.ok == true) {
insertToEditor(res.data.fileUrl);
} else {
console.error(res.data);
}
})
.catch((e) => {
console.error(e);
});
};
const { quill, Quill, quillRef } = useQuill({
modules: {
toolbar: "#toolbar",
imageDropAndPaste: {
// add an custom image handler
handler: imageHandler,
},
},
formats: ["size", "bold", "script"], // Important
});
if (Quill && !quill) {
// For execute this line only once.
const QuillImageDropAndPaste =
require("quill-image-drop-and-paste").default; // Install with 'yarn add quill-magic-url'
Quill.register("modules/imageDropAndPaste", QuillImageDropAndPaste);
}
// Insert Image(selected by user) to quill
const insertToEditor = (url) => {
const range = quill.getSelection();
quill.insertEmbed(range.index, "image", url);
};
React.useEffect(() => {
if (quill) {
console.log("quill regestered", quill);
quill.getModule("toolbar").addHandler("image", function (clicked) {
if (clicked) {
var fileInput = this.container.querySelector(
"input.ql-image[type=file]"
);
if (fileInput == null) {
fileInput = document.createElement("input");
fileInput.setAttribute("type", "file");
fileInput.setAttribute(
"accept",
"image/png, image/gif, image/jpeg, image/bmp, image/x-icon"
);
fileInput.classList.add("ql-image");
fileInput.addEventListener("change", function (e) {
var files = e.target.files,
file;
if (files.length > 0) {
file = files[0];
var type = file.type;
var reader = new FileReader();
reader.onload = (e) => {
// handle the inserted image
console.log(e.target.result);
var dataUrl = e.target.result;
imageHandler(dataUrl, type, new ImageData(dataUrl, type));
fileInput.value = "";
};
reader.readAsDataURL(file);
}
});
}
fileInput.click();
}
});
}
}, [quill]);
return (
<div style={{ width: 500, height: 300, border: "1px solid lightgray" }}>
<div ref={quillRef} />
<div id="toolbar">
<select className="ql-size">
<option value="small" />
<option selected />
<option value="large" />
<option value="huge" />
</select>
<button className="ql-bold" />
<button className="ql-image" />
<button className="ql-script" value="sub" />
<button className="ql-script" value="super" />
</div>
</div>
);
};
Also, one more issue to instantiate an object out of ImageData class. I am using Nuxt (Vue) framework and when importing this class inside plugin, error is thrown as QuillImageDropAndPaste.ImageData is not a constructor.
const ImageData = QuillImageDropAndPaste.ImageData
But if you declare the class as an expression, this error goes away. So if you declare as
ImageData = class {
constructor(dataUrl, type) {
this.dataUrl = dataUrl
this.type = type
}
// rest of the codes
}
then that error is not thrown. I would request you to incorporate this modification in the next minor version.
Also if you change the name 'ImageData' it would be better as browsers have builtin ImageData class/method.
Hi. I have some issues using quill editor.
Is it possible to move cursor at the end of the sentence after user wrote something by copy & paste?(ctrl+v or command+v)
Now it remains at the first of sentence.
Thanks
it should be 'image'
this.insert.call(this, utils.resolveDataUrl(dataUrl, type), 'image')
I've run into an issue where the paste listener on Qill.root prevents the intended behavior for Quill's clipboard matchers.
My own Node.TEXT_NODE matcher cannot execute, because the text paste is prevented and (through the pasteHandler) always inserted as plaintext.
Using the intended clipboard matcher syntax of Quill would allow developers to decide in which order the matchers should trigger. This would make it more flexible to combine with other paste handlers one might want to use with Quill.
Alternatively allowing developers to pass a handler for non-image text could also work.
Another alternative could be to not always prevent the paste event, but only in the case that a text which can be converted to an image is pasted.
quill-image-drop-and-paste/src/ImageDropAndPaste.ts
Lines 133 to 145 in 7209a13
file.getAsString((s) => {
utils
.urlIsImage(s)
.then(() => {
e.preventDefault();
that.insert(s, 'image');
});
});
` Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
/xxx/node_modules/quill-image-drop-and-paste/src/QuillImageDropAndPaste.js:171
export default ImageDropAndPaste
^^^^^^
SyntaxError: Unexpected token 'export'`
How can I deal with this problem? sorry to bother you.
Trying to implement the toolbar image handler to compress images with this package but I keep getting the error “Failed to construct ImageData:the provided value is not of type ImageDataSettings at reader.load”
also tried using the exact code from example sample from documentation but get same exact error.
btw my console logged values match the console logs from the imageData values from the imageHandler for drop and paste, which are working fine.
const toolbarImageHandler = () => {
const input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.click();
input.onchange = () => {
const file = input.files ? input.files[0] : null;
if (file) {
const type = file.type;
const name = file.name;
const reader = new FileReader();
console.log(reader);
reader.onload = (e) => {
// handle the inserted image
const dataUrl = e.target.result;
imageHandler(dataUrl, type, new ImageData(dataUrl, type, name));
input.value = "";
};
reader.readAsDataURL(file);
}
};
};
quill-image-drop-and-paste
version 1.2.11
quill
version 1.3.7
When Im inserting a new URL from any website on my quill editor the plugin recognized it as image an then inserting this URL as src
attribute inside an img
tag.
The problem is the function urlIsImage
that are not handling with URL properly.
During the next weekend I'll try to open a PR to solve this issue, but if somebody knows some workaround to solve this, I'm all ears.
The plugin doesn't work on Firefox.
handler
doesn't call at all
For testing just run this example on latest Firefox.
I've tested it on Firefox on Debian, and Firefox on Windows 10
Hey,
Nice plugin mate :)
I actually tried to use it with the script tag and fall into an error with your demo.
To fix it I changed line 31 by:
var ImageDropAndPaste = exports.ImageDropAndPaste = function() {
and removed the line 105:
exports.default=ImageDropAndPaste;
lines numbers are after pretty printing the file.
I just did that by comparing to the other drop and paste plugin and fixed the problem.
So I would like to know why because I don't have much knowledge of React and Vue 😄
Hope it helps,
Gilles
@chenjuneking rewrite the toolbar's insert image button error
It works with images under 100k, when image size is larger than 100kb, give me this error.
if i copy and image and hold paste, the handler will activate on the first few images, but for the rest it will just paste base64 images
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.