-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
upload image: replace the base64 url with the url getting from sever ? #2034
Comments
you can add custom toolbar handler. doc |
Actually, it's not a problem regarding replacing the base64 url, so the codes might look like below:
modules: {
toolbar: {
handlers: {
image: this.imageHandler
}, ...
imageHandler() {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async function() {
const file = input.files[0];
console.log('User trying to uplaod this:', file);
const id = await uploadFile(file); // I'm using react, so whatever upload function
const range = this.quill.getSelection();
const link = `${ROOT_URL}/file/${id}`;
// this part the image is inserted
// by 'image' option below, you just have to put src(link) of img here.
this.quill.insertEmbed(range.index, 'image', link);
}.bind(this); // react thing
} |
@lwyj123 @seongbin9786 Thanks. it's my fault to improperly describe the problem。 |
Hi, @zhatongning! I've been thinking about doing the exact same thing. Have you found a way to replace your base64 preview with the URL uploaded from server? |
Adding to @seongbin9786 answer, this code adds a loading placeholder image and replaces it once the image has been successfully uploaded. const imageHandler = () => {
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async () => {
const file = input.files[0];
const formData = new FormData();
formData.append('image', file);
// Save current cursor state
const range = this.quill.getSelection(true);
// Insert temporary loading placeholder image
this.quill.insertEmbed(range.index, 'image', `${ window.location.origin }/images/loaders/placeholder.gif`);
// Move cursor to right side of image (easier to continue typing)
this.quill.setSelection(range.index + 1);
const res = await apiPostNewsImage(formData); // API post, returns image location as string e.g. 'http://www.example.com/images/foo.png'
// Remove placeholder image
this.quill.deleteText(range.index, 1);
// Insert uploaded image
this.quill.insertEmbed(range.index, 'image', res.body.image);
}
} |
Thanks everyone, just one thing, it show be very nice to have this kind of examples in the official documentation. It avoids to search everywhere to find something like that ;) |
@seongbin9786 @james-brndwgn What's |
hey @seongbin9786 @james-brndwgn, adding custom image handler causing issues with editor typing. Editor can only type one character and then lose focus. Issue only comes up when editor is exported as functional component, and works fine as class component. |
Thank you @james-brndwgn, Your code was very helpful. By default, ActionText(Rails6) use Trix, but I tried to use Quill on ActionText. onMountQuitEditor(){
let editor = this.querySelector('.editor')
let toolbar = this.querySelector('.toolbar')
this.quill = new Quill(editor, {
modules: { toolbar: {
container: toolbar,
handlers: { image: this.onImage }
}
},
theme: 'snow'
})
}
onImage(){
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.onchange = async () => {
const file = input.files[0];
const range = this.quill.getSelection(true);
const attachment = {
file: file,
range: range,
uploadDidCompleteCallback: (attachment, attributes) => this.onUploadComplete(attachment, attributes)
}
if (attachment.file) {
const upload = new AttachmentUpload(attachment, this.rootElement())
upload.start()
}
}
}
onUploadComplete(attachment, attributes){
const range = attachment.range //this.quill.getSelection(true);
// Insert temporary loading placeholder image
// this.quill.insertEmbed(range.index, 'image', `${ window.location.origin }/images/loaders/placeholder.gif`);
// Move cursor to right side of image (easier to continue typing)
this.quill.setSelection(range.index + 1);
// Remove placeholder image
// this.quill.deleteText(range.index, 1);
// Insert uploaded image
this.quill.insertEmbed(range.index, 'image', attachment.url);
} // AttachmentUpload class is copied from @rails/actiontext/app/javascript/actiontext/attachment_upload.js
// and adjusted for Quill instead of Trix.
// https://github.com/rails/rails/blob/master/actiontext/app/javascript/actiontext/attachment_upload.js
import { DirectUpload } from "@rails/activestorage"
export class AttachmentUpload {
attachment: any;
element: any;
directUpload: DirectUpload;
constructor(attachment, element) {
this.attachment = attachment
this.element = element
this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this)
}
start() {
this.directUpload.create(this.directUploadDidComplete.bind(this))
}
directUploadWillStoreFileWithXHR(xhr) {
xhr.upload.addEventListener("progress", event => {
// to show progress
// const progress = event.loaded / event.total * 100
// this.attachment.setUploadProgress(progress)
})
}
directUploadDidComplete(error, attributes) {
if (error) {
throw new Error(`Direct upload failed: ${error}`)
}
this.attachment['ssid'] = attributes.attachable_sgid;
this.attachment['url'] = this.createBlobUrl(attributes.signed_id, attributes.filename)
this.attachment.uploadDidCompleteCallback(this.attachment, attributes)
// this.attachment.setAttributes({
// sgid: attributes.attachable_sgid,
// url: this.createBlobUrl(attributes.signed_id, attributes.filename)
// })
}
createBlobUrl(signedId, filename) {
return this.blobUrlTemplate
.replace(":signed_id", signedId)
.replace(":filename", encodeURIComponent(filename))
}
get directUploadUrl() {
// html tag must have attribute 'data-direct-upload-url'
return this.element.dataset.directUploadUrl
}
get blobUrlTemplate() {
// html tag must have attribute 'data-blob-url-template'
return this.element.dataset.blobUrlTemplate
}
} |
This is how I replaced placeholder image with my firebase storage image: `// current cursor state // placeholder image // method for saving in to storage const srcElem: HTMLImageElement = document.querySelector('[src^="data:image/"]'); |
Using an image handler like the following works when selecting an image from the toolbar: new Quill(element, {
modules: {
toolbar: {
handlers: {
image: imageHandler
}
}
},
...
}) ...but this doesn't handle replacing pasted images which are inserted as base64. What is the best way to replace the base64 url with an uploaded image url? |
@sebastiansandqvist This may help you: I am handling image upload(to server) using a Modal component.
When the modal opens the quill forgets the cursor position so, below is the code I store the position
The rest of the code is self explanatory.
|
I am using React Quill as the text editor. This works fine until I add the custom image handler. If I add the image handler as below, I can't type into the editor. Typing lose focus on every single keypress. It. be great if anyone can help me. Thanks in advance |
I have implemented react-quill to my application using hooks. So I tried this URL replace thing as you guys explained. but I still couldn't able to figure out how to get |
same issue here |
Here's my full(y) working code with custom image handler and few other tweaks. Thanks @seongbin9786
|
So finally what is |
Put the function calling
|
It still don't work for me and I really don't know what should I do to repair it. Maybe I just miss something in my code. @tomislav-arambasic can you look at this and tell me what am I doing wrong? My code below:
|
Here is my solution. It was running on my project. Note: "Index" is name file
|
@Puspendert Hi Puspender, I would love to see the whole approach(code) of yours, as I am also trying to do something similar(Opening a modal to drag and drop an image and then show it in the editor). I am able to upload the image with my handler but am unable to access the image to show it in the editor. |
@AjayDhimanELS #2034 (comment) Did you try everything explained here? |
@Puspendert Thanks for your prompt reply. Yes, I was receiving the |
@hvma411 Hey I just ran into the same issue in React, but then I realize I shouldn't have defined the image handler in the modules, but instead adding it after initilizing the quill editor. Here's my code (btw I'm using react hooks)
Hope you have solved it already, and this might help someone else. |
Does anyone have any idea of replacing the base64 urls on pasting content? Currently I'm stuck on this one as there might be multiple images in the clipboard and text contents as well, so I can't find a proper way to replace them, because I don't know where to insert the images. It's not like select and insert one image to the cursor point. Any help will be appreciated! |
是否可以用正则替换 |
editor.clipboard.addMatcher('img', (node: HTMLImageElement, delta) => {
if (node.src.startsWith('data:image')) {
const base64 = node.src.split(',')[1];
const buffer = Buffer.from(base64, 'base64');
const name = `${Date.now()}.png`;
const resFilePath = path.join(mailFileFolder, name);
fs.writeFileSync(resFilePath, buffer);
const ops = delta.ops;
ops.forEach((op) => {
if (op.insert && op.insert.image === node.src) {
op.insert.image = resFilePath;
}
});
return delta;
}
}); it works for me, which could replace base64 url when paste img |
@Puspendert, I am facing the same issue, did you find any solution for this |
@anmol5varma, I am facing the same issue, did you find any solution for this |
I have read many issues about uploading images, such as #633 #863.
When selecting an picture, the picture show immediately in the editor with base64 url, which was the default behaviour in snow/bubble theme.BUT I expect to replace the base64 url with the url getting from server.How can I solve the problem?
The text was updated successfully, but these errors were encountered: