fxmontigny / quill-image-upload Goto Github PK
View Code? Open in Web Editor NEWA module for Quill rich text editor to upload images to be selected from toolbar editor.
A module for Quill rich text editor to upload images to be selected from toolbar editor.
Thanks for getting this up. Worked out of the box like a charm!
Since uploading to server takes some amount of time, it would be nice to show some feedback to the user.
When I upload an image to a server, then the response code is 201.
Line 95 in 71d9009
please check
https://www.django-rest-framework.org/api-guide/status-codes/#successful-2xx
image remove and delete
Tested on iOS 12.1.2 and macOS Mojave 10.14.
Feature perfectly works on Firefox and Chrome
Edit: Now works on Safari on macOS but still not working on iOS browsers
Well, my problem is that image is not uploaded to server but after choosing image in text editor and adding it in field i cant see this image too.
My code:
import Quill from 'quill';
import {
ImageUpload
} from 'quill-image-upload';
Quill.register('modules/imageUpload', ImageUpload);
const quill = new Quill(editor, {
theme: 'snow',
modules: {
toolbar: '#toolbar',
imageUpload: {
url: 'http://localhost:3000', // server url. If the url is empty then the base64 returns
method: 'POST', // change query method, default 'POST'
name: 'image', // custom form name
withCredentials: false, // withCredentials
headers: {}, // add custom headers, example { token: 'your-token'}
csrf: {
token: 'token',
hash: ''
}, // add custom CSRF
customUploader: () => {}, // add custom uploader
// personalize successful callback and call next function to insert new url to the editor
callbackOK: (serverResponse, next) => {
next(serverResponse);
},
// personalize failed callback
callbackKO: serverError => {
alert(serverError);
},
// optional
// add callback when a image have been chosen
checkBeforeSend: (file, next) => {
console.log(file);
next(file); // go back to component and send to the server},
}
}
}
});
var form = document.querySelector('form');
form.onsubmit = function () {
// Populate hidden form on submit
var about = document.querySelector('input[name=body]');
about.value = JSON.stringify(quill.root.innerHTML);
};
Frontend
<form method="POST" action="/articles/add?_csrf={{csrfToken}}" enctype="multipart/form-data">
<label class="label" for="editor-clanok-title">Názov článku</label>
<div class="input input-fullWidth">
<input id="editor-clanok-title" placeholder="Názov článku" type="text" name="heading" value="{{heading}}">
</div>
<label>Slug</label>
<input type="text" class="form-control" placeholder="Slug" name="slug">
<!-- Create the toolbar container -->
<div id="toolbar">
<span class="ql-formats">
<select class="ql-font"></select>
<select class="ql-size"></select>
</span>
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-strike"></button>
</span>
<span class="ql-formats">
<select class="ql-color"></select>
<select class="ql-background"></select>
</span>
<span class="ql-formats">
<button class="ql-script" value="sub"></button>
<button class="ql-script" value="super"></button>
</span>
<span class="ql-formats">
<button class="ql-header" value="1"></button>
<button class="ql-header" value="2"></button>
<button class="ql-blockquote"></button>
<button class="ql-code-block"></button>
</span>
<span class="ql-formats">
<button class="ql-list" value="ordered"></button>
<button class="ql-list" value="bullet"></button>
<button class="ql-indent" value="-1"></button>
<button class="ql-indent" value="+1"></button>
</span>
<span class="ql-formats">
<button class="ql-direction" value="rtl"></button>
<select class="ql-align"></select>
</span>
<span class="ql-formats">
<button class="ql-link"></button>
<button class="ql-image"></button>
<button class="ql-video"></button>
<button class="ql-formula"></button>
</span>
<span class="ql-formats">
<button class="ql-clean"></button>
</span>
</div>
<!-- Create the editor container -->
<div>
<input name="body" type="hidden" value="">
<div id="editor">
{{{body}}}
</div>
</div>
<label class="label" for="editor-clanok-dropzone">Thumbnail</label>
<input type="file" name="thumbnail" />
<div class="form-row">
<button type="submit" class="button button--green">Publikovať</button>
<button class="button button--outlined">Uložiť ako koncept</button>
</div>
</form>
Any suggestions everything else works fine.
How can i settings image upload dialog accepted formats? Default settings all file formats but i dont want this. Should be .jpg, .png vs. vs.
Hello,
I'm trying to use your lib with react-quill and I'm getting this error:
The given range isn't in document.
Here's my code snippet:
import React from 'react'
import ReactQuill, { Quill } from 'react-quill'
import { ImageUpload } from 'quill-image-upload';
Quill.register('modules/imageUpload', ImageUpload);
const QuillEditor = (props) => {
const defaultHeaderOptions = [2, 3, false]
return (
<ReactQuill
value={props.value}
onChange={props.onChange}
theme="bubble"
modules={{
toolbar: {
container: [
...
]},
imageUpload: {
url: '/api/articles/image_upload',
method: "POST",
headers: {
'X-CSRF-TOKEN': document.querySelector('[name="csrf-token"]').content
},
callbackOK: (serverResponse, next) => {
console.log(serverResponse)
next(serverResponse)
},
callbackKO: (serverError) => {
console.log(serverError);
},
checkBeforeSend: (file, next) => {
console.log(file);
next(file);
}
}
}}
/>
)
}
export default QuillEditor
Thanks,
It would be helpful to be able to modify sendToServer(file)
in order to handle file upload manually.
I'm trying to upload the file to Firebase Storage, which does not use POST request. Documentation
What would be the best way to expose sendToServer()
as an option to handle the upload logic?
I've modified the function as below:
sendToServer(file) {
// Handle custom upload
if (this.options.customUploader) {
this.options.customUploader(file, dataUrl => {
this.insert(dataUrl)
})
} else {
const url = this.options.url || 'your-url.com',
method = this.options.method || 'POST',
headers = this.options.headers || {},
callbackOK =
this.options.callbackOK || this.uploadImageCallbackOK.bind(this),
callbackKO =
this.options.callbackKO || this.uploadImageCallbackKO.bind(this),
fd = new FormData()
fd.append('image', file)
const xhr = new XMLHttpRequest()
// init http query
xhr.open(method, url, true)
// add custom headers
for (var index in headers) {
xhr.setRequestHeader(index, headers[index])
}
// listen callback
xhr.onload = () => {
if (xhr.status === 200) {
callbackOK(JSON.parse(xhr.responseText), this.insert.bind(this))
} else {
callbackKO({
code: xhr.status,
type: xhr.statusText,
body: xhr.responseText
})
}
}
xhr.send(fd)
}
}
Let me know if you find this useful for general use. Happy to work on a pull request.
Many thanks for providing the plugin!
I am trying to use this for image upload, but found that it cannot pass through CI CSRF even with token added in header.
after check the source code and CI CSRF documentation, I found that CI do not use header for CSRF verification. It use form data instead.
so I modified the sendToServer function in order to accept extra data for CI CSRF, and here is the code
sendToServer(file) {
const url = this.options.url || 'your-url.com',
method = this.options.method || 'POST',
headers = this.options.headers || {},
csrf = this.options.csrf || { token : 'token', hash : '' }, // added this line
callbackOK = this.options.callbackOK || this.uploadImageCallbackOK.bind(this),
callbackKO = this.options.callbackKO || this.uploadImageCallbackKO.bind(this),
fd = new FormData();
fd.append('image', file);
fd.append(csrf.token, csrf.hash); // and this line
// ...
var quill = new Quill(editor, {
// ...
modules: {
// ...
imageUpload: {
url: "", // server url
method: "POST",
headers: {},
//added this line, replace YOUR_TOKEN_NAME and YOUR_HASH with your csrf token value
csrf: { token : YOUR_TOKEN_NAME, hash : YOUR_HASH },
callbackOK: (serverResponse, next) => {
next(serverResponse);
},
callbackKO: (serverError) => {
alert(serverError);
}
}
}
});
and for CI csrf token name & hash, you may create JS variables from CI security class
var YOUR_TOKEN_NAME = '<?php echo $this->security->get_csrf_token_name(); ?>',
YOUR_HASH = '<?php echo $this->security->get_csrf_hash(); ?>';
I've got this working right up until the point insertEmbed (quill-image-upload/src/image-upload.js) is called:
/** * Insert the image into the document at the current cursor position * @param {String} dataUrl The base64-encoded image URI */ insert(dataUrl) { const index = (this.quill.getSelection() || {}).index || this.quill.getLength(); this.quill.insertEmbed(index, 'image', dataUrl, 'user'); }
My image has uploaded and returned its url which is being passed to the above insert method (I've checked with the console). After this absolutely nothing happens. No image inserted into quill editor, no errors thrown, just nothing happens.
The response from my upload controller (Laravel 7) is a json formatted string of the image's url. No keys.
My js:
`
Quill.register("modules/imageUpload", ImageUpload);
const quill = new Quill('#quill-body', {
modules: {
toolbar: [
[{ 'header': 2 }, { 'header': 3 }],
['bold', 'italic'],
[{ 'script': 'sub'}, { 'script': 'super' }],
['link', 'blockquote'],
[{ list: 'ordered' }, { list: 'bullet' }],
[ 'link', 'image', 'video'],
[ 'clean' ]
],
imageUpload: {
url: 'http://mpba.local/image-upload', // server url. If the url is empty then the base64 returns
method: 'POST', // change query method, default 'POST'
name: 'file', // custom form name
withCredentials: false, // withCredentials
headers: { "X-CSRF-TOKEN": token.content }, // add custom headers, example { token: 'your-token'}
// csrf: { token: 'X-CSRF-TOKEN', hash: token.content }, // add custom CSRF
// customUploader: () => {}, // add custom uploader
// personalize successful callback and call next function to insert new url to the editor
// callbackOK: (serverResponse, next) => {
// next(serverResponse);
// },
// personalize failed callback
callbackKO: serverError => {
alert(serverError);
},
// optional
// add callback when a image have been chosen
// checkBeforeSend: (file, next) => {
// console.log(file);
// next(file); // go back to component and send to the server
// }
}
},
theme: 'snow'
});
var form = document.querySelector('.hl-editor-content');
form.onsubmit = function() {
// Populate hidden form on submit
var body = document.querySelector('input[name=body]');
var html = quill.root.innerHTML;
body.value = html;
};`
I've looked at the quill api docs and have spent hours trying to figure this out. Any ideas? I've tried it on latest Safari and Firefox.
Current code will fallback to this.quill.getLength()
when you move your cursor to the beginning of content.
insert(dataUrl) {
const index =
(this.quill.getSelection() || {}).index || this.quill.getLength();
this.quill.insertEmbed(index, 'image', dataUrl, 'user');
}
Check the result of getSelection
may be a better solution.
insert(dataUrl) {
const selection = this.quill.getSelection();
const index = selection
? selection.index
: this.quill.getLength();
this.quill.insertEmbed(index, 'image', dataUrl, 'user');
}
how can i use callbacks before sending image to server?
i wanna build a confirmation by user before send images
thanks
I wrote once but then i realized i only forgot to use webpack. But now i am trying i cant find a way how to make it works.
my plugin
And i disable CSRF protection from server
import Quill from 'quill';
import {
ImageUpload
} from 'quill-image-upload';
Quill.register('modules/imageUpload', ImageUpload);
const quill = new Quill(editor, {
theme: 'snow',
modules: {
toolbar: '#toolbar',
imageUpload: {
url: 'http://localhost:3000', // server url. If the url is empty then the base64 returns
method: 'POST', // change query method, default 'POST'
name: 'image', // custom form name
withCredentials: false, // withCredentials
headers: {}, // add custom headers, example { token: 'your-token'}
csrf: {
token: 'token',
hash: ''
}, // add custom CSRF
customUploader: () => {}, // add custom uploader
// personalize successful callback and call next function to insert new url to the editor
callbackOK: (serverResponse, next) => {
next(serverResponse);
},
// personalize failed callback
callbackKO: serverError => {
alert(serverError);
},
// optional
// add callback when a image have been chosen
checkBeforeSend: (file, next) => {
console.log(file);
next(file); // go back to component and send to the server
}
}
}
});
But all i get is console log with data.
File(65201) {name: "ggg.jpg", lastModified: 1542188728626, lastModifiedDate: Wed Nov 14 2018 10:45:28 GMT+0100 (Central European Standard Time), webkitRelativePath: "", size: 65201, …}
I dont know if is this image saved somewhere or if i need to make any script or route for this.
I am new in js so maybe i am missing somethin. Thanks for any guidance :)
On https://github.com/fxmontigny/quill-image-upload/blob/master/src/image-upload.js#L96
the index calculation doesn't work as intended when the cursor is at 0th position.
I am posting to a server, but am unsure what the server should return and how to bind it to Quill to show the image uploaded.
I assume a json string like:
{ "url": "Http://...."}
but are there any examples of binding that URL so it display in the editor in the callbackOK method?
Hi, i cannot use this module because my code won't bundle:
node_modules\quill-image-upload\index.js:6
export class ImageUpload {
^
ParseError: 'import' and 'export' may appear only with 'sourceType: module'
Any ideas?
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.