Closed dgandhi1993 closed 4 years ago
I managed to get the uploads in the S3 bucket done through the editor, however, I am unable to add the image URL that I received into the editor through any method or function call. Can someone guide me?
Normally you should return a result as reply to Suneditor after upload in JSON format:
{result: {"url": url, "name": "myname.jpg","size": 27861}}
So without testing myself, the sequence should be
client -> server: upload blob
server -> AWS S3: upload blob/file
AWS S3 -> server: reply - successful (url)
server -> client: reply - url, name etc.
Thus you cannot set image url in Suneditor after you replied with the url result, at least not what I am aware about. I need to update this answer: I think you might upload directly from client to AWS S3 without going through web server? That would not work for me at least (when I decide to use AWS S3) since I need to store url in my DB (server side) also, so a built-in upload directly from Suneditor would not be of any use for me (unless I rethink my storage concept...but I want to keep track of what and how much client is uploading...)
@MRB60 I am directly uploading to S3 and want to use the uploaded object key as a URL for the image. I see that in the upload image modal there is an option to add images via URLs. I just need access to that method and I think this problem is solved.
I don't save the URL at the moment since I am anyway saving the editor content in the DB.
Hi, @dgandhi1993
This can be integrated as a core offering since it is very common to have images on S3. It is available in many other editors out-of-the-box (check out Froala).
Please provide me a related link. And.. problem is solved?
@JiHong88 Please check this for an example link.
The issue is still not solved. What I am looking for is a way to add an image using a URL just like it happens in the Upload image modal, but using a method or function.
My two cents:
I plan to use AWS S3 too but will, for reason 3 in particular, not upload directly to AWS S3 but go via web server (without using local file storage).
For the same reason as above reply, I will not add option that depend on AWS. Maintenance will also be difficult. Or.. You can't implement it using Lambda?
I have managed to upload the image and get the S3 URL. The only thing I need is to get support to add an image using a URL.
Hmm.. What do you need other than the "imageUploadUrl" option?
I already have a URL that has been uploaded on a server. I need to just use it and add it as an image. How do I do that?
I don't understand. Are you asking how to add image with url?
Yes. I see that it is available through the upload image modal. But no direct way to do it.
You can using direct url.
Doesn't that mean this?
Yes, precisely. But this is through the modal. I want it to be done via a function call and not a modal. Instead of the user putting the URL, I am doing it programmatically.
How's that work? Tell me more detail.
I am using the onImageUploadBefore to upload the image to S3. This is working fine. I want to use this returned image link to be used in the editor.
Show me the onImageUploadBefore function.
My onImageUploadBefore
function uses the resize functionality provided in the documentation. Once the resize is done, I use the addPhoto
function to upload the blob to AWS S3.
editor.onImageUploadBefore = function (files, info, core, uploadHandler) {
try {
resizeImage(files, uploadHandler)
} catch (err) {
uploadHandler(err.toString())
}
};
function resizeImage (files, uploadHandler) {
const uploadFile = files[0];
const img = document.createElement('img');
const canvas = document.createElement('canvas');
const reader = new FileReader();
reader.onload = function (e) {
img.src = e.target.result
img.onload = function () {
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
const MAX_WIDTH = 1000;
const MAX_HEIGHT = 1000;
let width = img.width;
let height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(async function (blob) {
let res = await addPhoto([new File([blob], uploadFile.name)],loggedUser.institute._id,loggedUser._id);
if(res.success){
// Need to implement the image URL logic here
uploadHandler();
} else{
uploadHandler(res.message)
}
}, uploadFile.type, 1);
}
}
reader.readAsDataURL(uploadFile);
}
This is the function that adds the image to S3
function addPhoto(files) {
if (!files.length) {
return alert("Please choose a file to upload first.");
}
var file = files[0];
var photoKey = "uploads/"+(file.name.split(".")[0])+file.name.split(".")[1];
var upload = new AWS.S3.ManagedUpload({
params: {
Bucket: bucketName,
Key: photoKey,
Body: file,
ACL: "public-read"
}
});
var promise = upload.promise();
promise.then(
function(data) {
return ({success: true,finalImageURL:"https://"+bucketName+".s3.ap-south-1.amazonaws.com/"+photoKey})
},
function(err) {
return ({success: false,message:"There was an error uploading your photo"});
}
);
}
Don't run "uploadHandler", just call it like this:
const file = {name: "name", size:0};
const imageUrl = "imageUrl";
if (info.isUpdate) {
core.plugins.image.update_src.call(core, imageUrl, info.element, file);
break;
} else {
core.plugins.image.create_image.call(core, imageUrl, info.linkValue, info.linkNewWindow, info.inputWidth, info.inputHeight, info.align, file);
}
core.closeLoading();
In the next version, I will separate the above code so that we can add images directly.
You can call it like this from the next version.
if(res.success){
// Need to implement the image URL logic here
// uploadHandler();
// Call directly image register
const response = {
// The response must have a "result" array.
"result": [
{
"url": "/url",
"name": "name.jpg",
"size": "0"
},
]}
core.plugins.image.register.call(core, info, response);
}
@JiHong88 There is one issue with this call. When I add an image using this approach the editor fails to resize to accommodate the newly added image.
Ideal behavior would be when an image is added the editor auto-expands to accommodate the image.
Interestingly, this does not happen with setContents
. Can something be done about this?
@dgandhi1993 Are you using the "iframe" option?
No, just the img tag with the properties specified by the function provided by you.
This issue has been handled with setContents where the editor resizes based on the content provided.
On Sun, 28 Jun 2020 at 4:34 PM, JiHong.Lee notifications@github.com wrote:
@dgandhi1993 https://github.com/dgandhi1993 Are you using the "iframe" option?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/JiHong88/SunEditor/issues/414#issuecomment-650734804, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMAUK4VBJA5JGDCJQ3F5FG3RY4PSLANCNFSM4OGFEM5A .
The "height" property is "auto", but when adding an image with "register", does the height of the editor not adjust?
No, it does not change. The new image is placed in the existing available height of the editor and a scroll gets added instead.
@JiHong88 Are we fixing this?
@dgandhi1993 Try again with a new version. If that doesn't work, please elaborate on the editor's options and test order.
The new version has semi-fixed it. After digging a little deep, I found the cause to be the height property that is defined on the editor.
Apparently, the element with class se-wrapper-inner se-wrapper-wysiwyg sun-editor-editable
has a height set to 36px
in some cases, whereas at times it is set to auto
. The issue happens when it is set to 36px
.
Also, might be relevant here to note that usually, my editors have a width property set to 100%
but in cases where height is finite (like 36px
), the width is also a fixed value instead of a percentage.
I am still not able to figure out why this is happening as both the editors have identical HTML code, editor options and methods. I am not sure how the editor is getting these fixed value height and width.
36px
is default min-height value.
Show me the options used.
These are the options and functions used.
imageEditor = SUNEDITOR.create("imageContainer",{
mode: "balloon-always",
resizingBar: false,
showPathLabel: false,
display: "inline",
tabDisable: false,
placeholder: "Enter the question image here",
buttonList: [["image","removeFormat"]],
});
imageEditor.onImageUploadBefore = function (files, info, core, uploadHandler) {
try {
resizeImage(files, uploadHandler, info, core)
} catch (err) {
uploadHandler(err.toString())
}
};
imageEditor.setContents("");
Apparently, these are the same options for an editor on a different page and there it works absolutely fine.
Is there anything to do with the HTML code? In my case, everything is same, except in the one where I see the issue, I have to set the textarea
's width
to 100%
as it does not take the entire available space on its own.
The editor looks for the style of "textarea" first, and if not, sets the size to the "offset" size of "textarea". Otherwise, specify the size yourself.
{
width: "100%",
height: "auto"
}
if there is no content of "textarea", there is no need to reset the editor value to "setContents". And If you want to set the initial value to "setContents", call it in the "onload" function. https://github.com/JiHong88/SunEditor/issues/426#issuecomment-652825439
Even after manually setting these sizes on the textarea, I am facing the same issue. My editor height is stuck at 36px.
I just noticed that this editor does not extend even if I add text to it. It adds a scroll in the existing editor height.
I am sure there is a trivial mistake that I am making. Please help.
imageEditor = SUNEDITOR.create("imageContainer",{
mode: "balloon-always",
height: "auto", // are you using this option?
resizingBar: false,
showPathLabel: false,
display: "inline",
tabDisable: false,
placeholder: "Enter the question image here",
buttonList: [["image","removeFormat"]],
});
@JiHong88 Thanks a lot! That solved it! :)
You can call it like this from the next version.
if(res.success){ // Need to implement the image URL logic here // uploadHandler(); // Call directly image register const response = { // The response must have a "result" array. "result": [ { "url": "/url", "name": "name.jpg", "size": "0" }, ]} core.plugins.image.register.call(core, info, response); }
How do I do this in ReactJS & ExpressJS ??
@SorinGabriel02 "SunEditor" can be used as below from the latest version. ex
onImageUploadBefore(files, info, core, uploadHandler) {
const response = {..};
uploadHandler(response);
}
"suneditor-react" doesn't seem to have been updated yet. It will be available when the version is updated.
:React does not provide "core" object.
onImageUploadBefore(files, info, uploadHandler) {
const response = {..};
uploadHandler(response);
}
Here is my code that relates to saving an image on the back-end server and replacing the image data with a link to where the image is being stored on the back-end using a ReactJS component:
// inside the ReactJS editor component:
<SunEditor setOptions={{ ...otherOptions, imageUploadUrl: "http://localhost:5000/images/new"}} />
// inside the expressJS server:
const express = require("express");
const fileUpload = require("express-fileupload");
const cors = require("cors");
const app = express();
app.use(cors());
app.use(express.json());
app.use(fileUpload());
// tells express to look into this directory when working with /images
app.use("/images", express.static(`${__dirname}/upload/images/`));
// has to match the the value passed to **imageUploadUrl** prop
app.post("/images/new", (req, res, next) => {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).json({ error: "No files were uploaded." });
}
// permitted myme types
const mymeTypes = ["image/png", "image/jpeg", "image/jpg"];
// img object sent from client
let image = req.files["file-0"];
if (!mymeTypes.some((img) => img.mymetype === image.mymetype)) {
return res
.status(422)
.json({ error: "Only .png, .jpeg or .jpg are allowed." });
}
image.mv(`${__dirname}/upload/images/${image.name}`, (err) => {
if (err) return res.status(500).send(err);
res.json({
result: [
{
url: `http://localhost:5000/images/${image.name}`,
name: image.name,
size: image.size,
},
],
});
});
};)
@SorinGabriel02 "SunEditor" can be used as below from the latest version. ex
onImageUploadBefore(files, info, core, uploadHandler) { const response = {..}; uploadHandler(response); }
"suneditor-react" doesn't seem to have been updated yet. It will be available when the version is updated.
:React does not provide "core" object.
onImageUploadBefore(files, info, uploadHandler) { const response = {..}; uploadHandler(response); }
The above does not work on "suneditor-react": "^2.14.4" it still does not load the image as url from the response.
Mystery revealed...
Here is my code that relates to saving an image on the back-end server and replacing the image data with a link to where the image is being stored on the back-end using a ReactJS component:
// inside the ReactJS editor component: <SunEditor setOptions={{ ...otherOptions, imageUploadUrl: "http://localhost:5000/images/new"}} /> // inside the expressJS server: const express = require("express"); const fileUpload = require("express-fileupload"); const cors = require("cors"); const app = express(); app.use(cors()); app.use(express.json()); app.use(fileUpload()); // tells express to look into this directory when working with /images app.use("/images", express.static(`${__dirname}/upload/images/`)); // has to match the the value passed to **imageUploadUrl** prop app.post("/images/new", (req, res, next) => { if (!req.files || Object.keys(req.files).length === 0) { return res.status(400).json({ error: "No files were uploaded." }); } // permitted myme types const mymeTypes = ["image/png", "image/jpeg", "image/jpg"]; // img object sent from client let image = req.files["file-0"]; if (!mymeTypes.some((img) => img.mymetype === image.mymetype)) { return res .status(422) .json({ error: "Only .png, .jpeg or .jpg are allowed." }); } image.mv(`${__dirname}/upload/images/${image.name}`, (err) => { if (err) return res.status(500).send(err); res.json({ result: [ { url: `http://localhost:5000/images/${image.name}`, name: image.name, size: image.size, }, ], }); }); };)
It does not work for me, I am able to upload to server and getting the correct response format but on suneditor still inserts the data:image/jpeg;base64 image blob.
Correction its inserting 2 images one with data:image/jpeg;base64 and the server url one here is an image.
@mylastore Sorry for the late reply. Are two images created, base64 and url? Are there any events in use?
For Suneditor-React: https://github.com/mkhstar/suneditor-react/issues/128#issuecomment-761689780
@niltonxp It would be better to add a catch as well. http://suneditor.com/sample/html/out/document-user.html#onImageUploadBefore
Hello, I try to change the url after the image has been uploaded to S3 like dgandhi1993 did. I use the last version of suneditor-react (2.15.2).
After I upload image to S3 with my method handleImageUploadBefore, I get the url from AWS. It works perfectly.
But when I try to change the URL in SunEditor, the image is displayed but the url contains base64 code and not my S3 url. What I'm doing wrong ?
Here is my react code : `handleImageUploadBefore = async (files, info, uploadHandler) => { const imageInfo = await toBase64(files[0]);
if (imageInfo) {
console.log(imageInfo)
const mime = imageInfo.split(';')[0].split(':')[1];
const rawImage = imageInfo.split(';')[1];
this.props.uploadImageToS3(idArticle, mime, rawImage).then(url => {
console.log(url)
const response = {
"result": [
{
"url": `/${url}`,
"name": "name.jpg",
"size": "0"
},
]
};
uploadHandler(response);
})
}
}`
and the creation of the component :
<SunEditor lang="en" setOptions={{ height: 600, buttonList: buttonList.complex }} onImageUploadBefore={(files, imageInfo, uploadHandler) => this.handleImageUploadBefore(files, imageInfo, uploadHandler)} placeholder="Entrez le contenu de l'article ici..." {...input} />
Thank you for your help.
Hello, I try to change the url after the image has been uploaded to S3 like dgandhi1993 did. I use the last version of suneditor-react (2.15.2).
After I upload image to S3 with my method handleImageUploadBefore, I get the url from AWS. It works perfectly.
But when I try to change the URL in SunEditor, the image is displayed but the url contains base64 code and not my S3 url. What I'm doing wrong ?
Here is my react code : `handleImageUploadBefore = async (files, info, uploadHandler) => { const imageInfo = await toBase64(files[0]);
if (imageInfo) { console.log(imageInfo) const mime = imageInfo.split(';')[0].split(':')[1]; const rawImage = imageInfo.split(';')[1]; this.props.uploadImageToS3(idArticle, mime, rawImage).then(url => { console.log(url) const response = { "result": [ { "url": `/${url}`, "name": "name.jpg", "size": "0" }, ] }; uploadHandler(response); }) } }`
and the creation of the component :
<SunEditor lang="en" setOptions={{ height: 600, buttonList: buttonList.complex }} onImageUploadBefore={(files, imageInfo, uploadHandler) => this.handleImageUploadBefore(files, imageInfo, uploadHandler)} placeholder="Entrez le contenu de l'article ici..." {...input} />
Thank you for your help.
Ok I found the solution I have deleted '/' at the begining of the url in the result but I have another problem. When I submit, the image is displayed twice. One with base64 code in URL and the other with the correct S3 Url.
Hello, I try to change the url after the image has been uploaded to S3 like dgandhi1993 did. I use the last version of suneditor-react (2.15.2). After I upload image to S3 with my method handleImageUploadBefore, I get the url from AWS. It works perfectly. But when I try to change the URL in SunEditor, the image is displayed but the url contains base64 code and not my S3 url. What I'm doing wrong ? Here is my react code : `handleImageUploadBefore = async (files, info, uploadHandler) => { const imageInfo = await toBase64(files[0]);
if (imageInfo) { console.log(imageInfo) const mime = imageInfo.split(';')[0].split(':')[1]; const rawImage = imageInfo.split(';')[1]; this.props.uploadImageToS3(idArticle, mime, rawImage).then(url => { console.log(url) const response = { "result": [ { "url": `/${url}`, "name": "name.jpg", "size": "0" }, ] }; uploadHandler(response); }) } }`
and the creation of the component :
<SunEditor lang="en" setOptions={{ height: 600, buttonList: buttonList.complex }} onImageUploadBefore={(files, imageInfo, uploadHandler) => this.handleImageUploadBefore(files, imageInfo, uploadHandler)} placeholder="Entrez le contenu de l'article ici..." {...input} />
Thank you for your help.
Ok I found the solution I have deleted '/' at the begining of the url in the result but I have another problem. When I submit, the image is displayed twice. One with base64 code in URL and the other with the correct S3 Url.
It works now. Here is my new code :
handleImageUploadBefore = (files, info, uploadHandler) => {
toBase64(files[0]).then(imageInfo => {
if (imageInfo) {
const mime = imageInfo.split(';')[0].split(':')[1];
const rawImage = imageInfo.split(';')[1];
this.props.uploadImageToS3(idArticle, mime, rawImage).then(url => {
const response = {
"result": [
{
"url": `${url}`,
"name": files[0].name,
"size": files[0].size
},
]
};
uploadHandler(response);
})
}
});
}
Hi. I'm having trouble uploading files (images, videos, audios) to my server. I am a begginer in programming and so I would really like you to help me create a URL mapping file, In java, that I could perform this action. Any help is greatly appreciated.
And I have to say that this editor is the BEST I've Ever seen. It's awesome!.
Hello, If you want to upload photos to AWS S3, you can use Api gateway with mapping tempate. And then you simply call your api in Java.
Great Idea, thanks.
Can someone help me with getting the images uploaded to AWS S3 first and then using that link here in the editor?
@JiHong88 This can be integrated as a core offering since it is very common to have images on S3. It is available in many other editors out-of-the-box (check out Froala).