Giter Site home page Giter Site logo

chenjuneking / quill-image-drop-and-paste Goto Github PK

View Code? Open in Web Editor NEW
101.0 101.0 43.0 2.36 MB

A quill editor module for drop and paste image, with a callback hook before insert image into the editor

License: ISC License

Shell 1.85% HTML 11.10% JavaScript 11.24% Vue 7.69% CSS 27.82% TypeScript 40.13% SCSS 0.17%

quill-image-drop-and-paste's People

Contributors

brianlukoff avatar chenjuneking avatar dependabot[bot] avatar eg-dev avatar lafiosca avatar mu-hun avatar siihyun avatar tianjianchn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

quill-image-drop-and-paste's Issues

Break on copy paste text from Google docs or MS word

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.

Import error: export default was not found

Getting error

"export 'default' (imported as 'QuillImageDropAndPaste') was not found in 'quill-image-drop-and-paste'

import QuillImageDropAndPaste from 'quill-image-drop-and-paste'

ImageData.toFile argument is required in type definition

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:

toFile(filename: string): File | null;

I think this is due to the abstract method definition here:

public abstract toFile(filename: string);

Even though the implementation makes it optional here:

public toFile(filename?: string): File | null {

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.

With the release of Quill 2.0, Parchment image blot gets triggered regardless of if your handler is set

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

how to play gif

Hi there . I was playing with Script Demo (vanilla js) to see if I can drag image into editor container.
I have two questions.

  • is there any way to display image inside editor container? (since the sample would display image on separate div container)
  • the GIF image wouldnt play when dragged.

Many tanks.

TypeError: moduleClass is not a constructor [nextjs]

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",

@chenjuneking

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}
      />
    </>
  );
}

Any plans to make this lib work for angular?

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

Duplicate image on paste

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. 🙏

Paste related questions

Version

quill-image-drop-and-paste: '1.2.9'

Question

Paste related questions:

  1. paste delayed response
  2. wrong paste

paste delayed response

  1. paste https://github.surmon.me/vue-quill-editor
  2. You will find this without any problem, then empty the text box
  3. paste https://www.vuescript.com/quill-editor-component-vue2/
  4. You will notice a noticeable delay of a few seconds before the content is filled.

wrong paste

  1. paste https://www.vuescript.com/quill-editor-component-vue2/
  2. Copy pasteboard contents elsewhere as quill-editor
  3. In the text box, Ctrl+A selects all the text, and then pastes it, you will find that the content does not match the clipboard.

paste

Uncaught (in promise) ReferenceError: position is not defined

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?

plugin not firing when copy image from web

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

TypeError: Cannot read property 'register' of undefined

Hi, I think there are some errors in this version. when I'm trying to apply this line,
Quill.register("modules/imageDropAndPaste", QuillImageDropAndPaste);
an error is occured.

image

And react-demo example didn't work properly as well.
image

Can you check it?
Thanks.

Getting the file directly in the handler

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

minify, increases the imagesize

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.

Does not seem to work with Vue

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.

plain text file drop is not working

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

How i can in Vue 3 rewrite the toolbar's insert image button with image handler.?

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?

Image drop issue

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.

No license defined

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

url image

Hi, is there a way to enhance this plug in with the paste of image URL?

It will make it a complete plugin

Paste not working

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 ?

Network Request happens on every url added

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?

image

IndexSizeError: Failed to construct 'ImageData'

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>
  );
};

QuillImageDropAndPaste.ImageData is not a constructor

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.

Use Quill's clipboard matcher instead of addEventListener on Quill.root

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.

} else if (type.match(/^text\/plain$/i)) {
e.preventDefault();
file.getAsString((s) => {
utils
.urlIsImage(s)
.then(() => {
that.insert(s, 'image');
})
.catch(() => {
that.insert(s, 'text');
});
});
}

file.getAsString((s) => {
  utils
    .urlIsImage(s)
    .then(() => {
      e.preventDefault();
      that.insert(s, 'image');
    });
});

Jest error: SyntaxError: Unexpected token 'export'

` 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.

Rewrite the toolbar’s insert image button error: Failed to construct ImageData

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);
      }
    };

};

Inserting any URL in editor is being recognized as image

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.

image
image

The problem is the function urlIsImage that are not handling with URL properly.
image

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.

Plugin doesn't work on Firefox

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

Script tag file not working

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.