How to upload video in Quill Editor? - quill

Currently, we are able to upload image using Quill Editor. which is base64 but we can upload that usign image handler. like this below:
modules: {
toolbar: {
container: '#toolbar',
handlers: {
'image': imageHandler
}
}
},
the offical image handler is here:
function () {
let 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', () => {
if (fileInput.files != null && fileInput.files[0] != null) {
let reader = new FileReader();
reader.onload = (e) => {
let range = this.quill.getSelection(true);
this.quill.updateContents(new Delta()
.retain(range.index)
.delete(range.length)
.insert({ image: e.target.result })
, Emitter.sources.USER);
fileInput.value = "";
}
reader.readAsDataURL(fileInput.files[0]);
}
});
this.container.appendChild(fileInput);
}
fileInput.click();
}
My question is how to upload video instead?

Related

How can I check if the data_URL is returning an image of video ? - Firebase & Next.js/React

The image is uploaded to firebase and returned as a data_URL that looks like this:
https://firebasestorage.googleapis.com/v0/b/app_name/o/posts%2postId?alt=media&token=token
I am trying to check if the file type is a video or an image, then return a div depending on the "mediaType". Because firebase storage doesn't include the file extension in the url, it is difficult to determine the file type.
First attempt:
const [mediaType, setMediaType] = useState(null);
useEffect(() => {
if (postImage) {
const storageRef = firebase.storage().ref();
storageRef.child(postImage).getDownloadURL().then(url => {
fetch(url)
.then(res => res.blob())
.then(blob => {
let type = blob.type;
if (type.startsWith("image")) {
setMediaType("image");
} else if (type.startsWith("video")) {
setMediaType("video");
} else {
setMediaType("other");
console.log("Unknown file format: " + type);
}
});
});
}
}, [postImage]);
Second attempt:
const handleFile = async (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = async (e) => {
const dataURL = e.target.result;
if (dataURL.startsWith('data:image/')) {
setMediaType('image');
setDataUrl(dataURL);
console.log("Image: " + dataURL);
} else if (dataURL.startsWith('data:video/')) {
setMediaType('video');
setDataUrl(dataURL);
console.log("Video: " + dataURL);
} else {
let response = await fetch(dataURL);
let type = response.headers.get("Content-Type");
if (type.startsWith("image")) {
setMediaType("image");
setDataUrl(dataURL);
} else if (type.startsWith("video")) {
setMediaType("video");
setDataUrl(dataURL);
} else {
setMediaType("other");
console.log("Unknown file format: " + type);
}
}
}
reader.readAsDataURL(file);
}
The div inside my return statement:
<div className="w-full px-3">
{mediaType === 'image' ? <img className="shadow-md w-full" src={postImage || 'default-image.jpg'} alt="" /> : null}
{mediaType === 'video' ? <ReactPlayer layout="fill" url={postImage} config={{file:{attributes:{controlsList:'nodownload'}}}} controls onContextMenu={e => e.preventDefault()}/> : null}
{mediaType === 'other' ? <p>File is not an image or video</p> : null}
</div>
What I would do is add metadata while uploading the file to firebase. You can check the documentation to see how:
//This is a metadata, you can customize these
//as you can see the content type is set to be image/jpeg
var newMetadata = {
cacheControl: 'public,max-age=300',
contentType: 'image/jpeg'
.........
.........
};
You will use this metadata while uploading the file using:
storageRef.updateMetadata(newMetadata).......
And when reading the file read out the metadata that you set to the file to for example detect its type:
storageRef.getMetadata().then((metadata) => {
//use this metadata to know the type here.......
})
Hope this gives you an idea of what to do.

how to Open electron app from browser in both windows and mac

const { app, BrowserWindow, ipcMain, dialog, screen,Tray } = require('electron');
try {
require('electron-reloader')(module)
} catch (_) { }
const path = require('path')
let deeplinkingUrl;
let mainWindow;
const createWindow = () => {
let { width, height } = screen.getPrimaryDisplay().size
// Create the browser window.
mainWindow = new BrowserWindow({
width: width,
height: height,
minWidth: width,
minHeight: height,
productName: "abc",
copyright: "Copyright © 2022 ${author}",
// mac: {
// icon: "./img/abc_256x256px.ico"
// },
icon: __dirname + "/img/icon.ico",
// icon: "./img/abc_256x256px.ico",
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
devTools: false,
}
})
mainWindow.setClosable(false);
mainWindow.setMenuBarVisibility(false);
mainWindow.maximize();
mainWindow.setMovable(false);
mainWindow.setResizable(false);
if (process.platform == 'win32') {
// Keep only command line / deep linked arguments
deeplinkingUrl = process.argv.slice(1)
}
logEverywhere("createWindow# " + deeplinkingUrl)
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
//tray
let tray = null;
mainWindow.on('minimize', function (event) {
event.preventDefault();
mainWindow.hide();
tray = createTray();
});
mainWindow.on('restore', function (event) {
mainWindow.maximize();
mainWindow.show();
tray.destroy();
});
function createTray() {
let appIcon = new Tray(path.join(__dirname + "/img/icon.ico"));
appIcon.on('click', function (event) {
mainWindow.show();
});
appIcon.setToolTip('abc');
return appIcon;
}
}
app.whenReady().then(() => {
createWindow()
if (isDev && process.platform === 'win32') {
// Set the path of electron.exe and your app.
// These two additional parameters are only available on windows.
// Setting this is required to get this working in dev mode.
app.setAsDefaultProtocolClient('pro', process.execPath, [
resolve(process.argv[1])
]);
} else {
app.setAsDefaultProtocolClient('pro');
}
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
app.on('open-url', function (event, url) {
event.preventDefault();
deeplinkingUrl = url;})
})
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
return;
} else {
app.on('second-instance', (e, argv) => {
if (process.platform !== 'darwin') {
// Find the arg that is our custom protocol url and store it
deeplinkingUrl = argv.find((arg) => arg.startsWith('custom://'));
}
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore();
myWindow.focus();
}
});
}
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
function logEverywhere(s) {
console.log(s)
if (mainWindow && mainWindow.webContents) {
mainWindow.webContents.executeJavaScript(`console.log("${s}")`)
}
}
//to allow self signed certificate
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
// Verification logic.
event.preventDefault()
callback(true)
})
ipcMain.handle('download', async (someArgument) => {
const result = await download(someArgument)
return result;
})
const download = async (data) => {
let value = 100;
console.log(data.name)
dialog.showSaveDialog({
title: 'Select the File Path to save',
defaultPath: path.join(__dirname, data.name + '.p12'),
buttonLabel: 'Save',
filters: [
{
name: 'Personal Information Exchnage',
extensions: ['.p12']
}
],
properties: []
}).then((path) => {
value = 1;
console.log('success')
mainWindow.webContents.send('success', path);
}).catch((value) => {
value = 2;
mainWindow.webContents.send('failed', path);
console.log('error')
});
return value;
}
This code throws some error when I type 'pro://something' in the browser.
Erorr description: Error launching app, unable to find Electron app at C:\Windows\system32\pro:\something
I have also tried some other code which opens my app but in a different window.
I want to open the App but in the existing window of my app.

Is it possible to read xlsx in react if office is not installed on windows machine?

Currently I am using below code to read xlsx file in react when my system having office (excel) installed. But the same is throwing error on other machine where office(excel) is not installed.
Error is at this point console.log(this.state.file.type)
Here is console.log :
lastModified: 1595606065652
lastModifiedDate: Fri Jul 24 2020 15:54:25 GMT+0000 (Greenwich Mean Time) {}
name: "ExamAnswer.xlsx"
size: 14266
type: "" // here type is null
webkitRelativePath: ""
__proto__: File
So, could you please tell how to read file type
handleExamInputFile() {
const reader = new FileReader();
const rABS = !!reader.readAsBinaryString;
console.log("file", this.state.file);
console.log(this.state.file.type);
let fileType =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
if (this.state.file.size > 0) {
console.log(this.state.file.size);
if (this.state.file.type === fileType) {
if (rABS) {
reader.readAsBinaryString(this.state.file);
} else {
reader.readAsArrayBuffer(this.state.file);
}
reader.onload = (e) => {
const bstr = e.target.result;
const wb = XLSX.read(bstr, {
type: rABS ? "binary" : "array",
bookVBA: true,
});
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = XLSX.utils.sheet_to_json(ws, {
raw: true,
});
const header = [];
const columnCount = XLSX.utils.decode_range(ws["!ref"]).e.c + 1;
for (let i = 0; i < columnCount; ++i) {
if (ws[`${XLSX.utils.encode_col(i)}1`] != undefined) {
header[i] = ws[`${XLSX.utils.encode_col(i)}1`].v;
}
}
console.log(header);
let headerMustHave = ["Exam Name", "EId", "Name"];
// let ifFound = header.every(function (val) {
// console.log(val);
// return headerMustHave.indexOf(val) !== -1;
// });
let checker = (arr, target) => target.every((v) => arr.includes(v));
let ifFound = checker(header, headerMustHave);
console.log(ifFound);
if (ifFound === true) {
for (var i = 0; i < data.length; i++) {
let excel_date = this.ExcelDateToJSDate(data[i]["Report Date"]);
data[i]["Report Date"] = excel_date;
}
this.setState({
data: data,
result: JSON.stringify(data),
cols: make_cols(ws["!ref"]),
});
const exceldata = JSON.parse(this.state.result);
const excelList = exceldata.map((data) => data);
const excel = { data: excelList };
const url = "http://localhost:8000/upload";
const config = {
headers: {
Accept: "*",
"Content-Type": "application/json",
"Allow-Control-Allow-Origin": "*",
// Accept: "application/json",
},
};
return post(url, excel, config).then((response) => {
toast.success(response.data, {
position: toast.POSITION.TOP_CENTER,
});
document.getElementById("file1").value = "";
this.setState({ file: "" });
});
} else {
toast.error("Some columns are not presented in uploaded file.", {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
this.setState({ file: "" });
}
};
} else {
toast.error(
"This file format is not supported. Please select an .xlsx file.",
{
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
}
);
this.setState({ file: "" });
}
} else {
toast.error("Please select .xlsx file to upload.", {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
this.setState({ file: "" });
}
}
Alternatively, is it possible to read the same xlsx file through python on above type machine?
TIA
Since this is React.js code, it's running client-side, in a browser.
Your problem with type being empty is that not all machines and browsers know how to map the file type .xlsx to the MIME type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; those with Excel, or maybe LibreOffice installed, certainly might, but even that's not a given. Whether or not Excel is actually installed has no bearing on whether the XLSX.js library you're using can actually parse the file (since the browser doesn't know about Excel).
As I mentioned in the comments, you can simply optionally look at the extension of the file uploaded – and even that's not necessary; you could just attempt to pass the file to XLSX; it would fail to parse files that are not XLSX documents anyway.
Here's a refactoring of your code to move to promise-based asynchronicity, moving the actual processing code out of the React component, so it's more easily testable.
In addition, you seemed to be doing some strange to-JSON-from-JSON coercion before posting the data; I got rid of that (and all of the Toast error handling for a more minimal example)...
function ExcelDateToJSDate(x) {
return x; // TODO: implement
}
function processWorkbook(wb) {
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = XLSX.utils.sheet_to_json(ws, {
raw: true,
});
const header = [];
const columnCount = XLSX.utils.decode_range(ws["!ref"]).e.c + 1;
for (let i = 0; i < columnCount; ++i) {
const col = `${XLSX.utils.encode_col(i)}1`;
if (ws[col] != undefined) {
header[i] = ws[col].v;
}
}
console.log(header);
const headerMustHave = ["Exam Name", "EId", "Name"];
const checker = (arr, target) => target.every((v) => arr.includes(v));
let ifFound = checker(header, headerMustHave);
if (ifFound === true) {
for (var i = 0; i < data.length; i++) {
let excel_date = ExcelDateToJSDate(data[i]["Report Date"]);
data[i]["Report Date"] = excel_date;
}
}
return { ws, data };
}
/**
* Read a DOM File into a binary string or array buffer; returns a Promise.
*/
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
let type;
if (reader.readAsBinaryString) {
reader.readAsBinaryString(file);
type = "binaryString";
} else {
reader.readAsArrayBuffer(file);
type = "arrayBuffer";
}
reader.onload = (event) => {
resolve({ type, data: event.target.result });
};
reader.onerror = (event) => reject(event);
});
}
async function processExamInputFile(file) {
if (!file) {
throw new Error("No file selected.");
}
if (
!(
file.type === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ||
file.name.endsWith(".xlsx")
)
) {
throw new Error("Invalid file type or extension.");
}
const { data, type } = await readFile(file);
const wb = XLSX.read(data, {
type: type === "binaryString" ? "binary" : "array",
bookVBA: true,
});
return processWorkbook(wb);
}
class X {
async handleExamInputFile() {
try {
const { ws, data } = await processExamInputFile(this.state.file);
this.setState({
data: data,
result: JSON.stringify(data),
cols: make_cols(ws["!ref"]),
});
await post(
"http://localhost:8000/upload",
{ data },
{
headers: {
Accept: "*",
"Content-Type": "application/json",
"Allow-Control-Allow-Origin": "*",
},
},
);
} catch (err) {
console.log(err); // TODO: improve
}
}
}

How to get an Image url after image crop, instead of a blob url

I am writing a react code and using react-image-crop to to crop the images being uploaded. I have a dropzone for image. So, whenever a image is dropped, the FileReader reads the image and when loading is complete, I get encoded base64 dataUrl.
Now, when I crop this image, I get a blob url, as,
blob:http://localhost:3000/bc361b08-589f-430b-a71e-b0bc3b59fd1a
// For reading and cropping the image
onSelectFile = e => {
if (e.target.files && e.target.files.length > 0) {
const reader = new FileReader();
reader.addEventListener("load", () =>
this.setState({ src: reader.result })
);
reader.readAsDataURL(e.target.files[0]);
}
};
// If you setState the crop in here you should return false.
onImageLoaded = image => {
this.imageRef = image;
};
onCropComplete = crop => {
this.makeClientCrop(crop);
};
onCropChange = (crop, percentCrop) => {
this.setState({ crop });
};
async makeClientCrop(crop) {
if (this.imageRef && crop.width && crop.height) {
const croppedImageUrl = await this.getCroppedImg(
this.imageRef,
crop,
"newFile.jpeg"
);
this.setState({ croppedImageUrl });
}
console.log(this.state.croppedImageUrl, "myResult croppedImageUrl")
}
getCroppedImg(image, crop, fileName) {
const canvas = document.createElement("canvas");
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
canvas.width = crop.width;
canvas.height = crop.height;
const ctx = canvas.getContext("2d");
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width,
crop.height
);
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (!blob) {
//reject(new Error('Canvas is empty'));
return;
}
blob.name = fileName;
window.URL.revokeObjectURL(this.fileUrl);
this.fileUrl = window.URL.createObjectURL(blob);
resolve(this.fileUrl);
}, "image/jpeg");
});
}
onDrop = (files, rejectedFiles) => {
const self = this
this.setState({
loading: true
})
if (!!rejectedFiles && !!rejectedFiles.length) {
this.verifyFile(rejectedFiles)
this.setState({
dropZoneClassName: 'dropzone-error',
loading: false,
error: true
})
return
}
if (files && files.length > 0) {
const isVerified = this.verifyFile(files)
if (isVerified) {
this.setState({
dropZoneClassName: 'dropzone-success'
})
// imageBase64Data
const currentFile = files[0]
const myFileItemReader = new FileReader()
myFileItemReader.addEventListener("load", () => {
const myResult = myFileItemReader.result
console.log(myResult, "myResult")
const e = myResult.slice(5, myResult.length)
console.log(e, "myResult after slice")
this.setState({
imgSrc: myResult,
imgSrcExt: extractImageFileExtensionFromBase64(myResult),
src: myResult,
newSrc: e
})
}, false)
myFileItemReader.readAsDataURL(currentFile)
}
}
}
onImageClick = (e) => {
console.log(e, "myResult croppedImageUrl")
if (!e) {
return
}
e = this.state.croppedImageUrl
const self = this
this.props.uploadProfileImage('', '', this.state.croppedImageUrl).then(function ({ payload }) {
self.setState({
loading: false,
dropZoneClassName: '',
error: false,
})
self.state.onUpload(e)
})
}
Expected Result : The cropped image should get uploaded to the server.
Actual Result : The image is not being uploaded because it is a blob.
Is it possible to not get a blob after cropping and instead get a normal url?

File upload progress using react-dropzone

Using react-dropzone to upload the file, I want to achieve the file progress like in percentage of file transfer or mbs data transfer.
Here is the link of: https://react-dropzone.netlify.com/
onDrop(acceptedFiles, uploadApi) {
const filesToBeSent = this.state.filesToBeSent;
if (acceptedFiles.length) {
if (acceptedFiles[0].type === FileTypeList.TYPE) {
filesToBeSent.push(acceptedFiles);
const formData = new FormData();
formData.append("file", acceptedFiles[0]);
uploadApi(formData).then((response) => {
this.setState({
filesPreview: [],
filesToBeSent: [{}],
showNotification: true,
uploadResponse: response,
});
this.props.fetchHistory();
});
} else {
this.setState({
fileType: true,
});
}
} else {
this.setState({
fileSize: true,
});
}
}
<Dropzone maxSize={this.props.maxSize} onDrop={(files) => this.onDrop(files, this.props.uploadApi)}>
{({ getRootProps, getInputProps }) => {
return (
<div {...getRootProps()} className={"dropzone"}>
<UploadPanel id="uploadFileContainerId">
<p>
<img id="uploadImage" src={UploadImage} />
</p>
<input {...getInputProps()} />
<div>{t("assets:UPLOAD_FILE")}</div>
<Note>
{this.props.maxSizeTitle ? t("workers:UPLOAD_WORKER_FILE_SIZE") : t("assets:UPLOAD_FILE_SIZE")}
</Note>
</UploadPanel>
</div>
);
}}
</Dropzone>
In case you wanna detect file upload process you can use XMLHttpRequest
onDrop(acceptedFiles) {
const formData = new FormData();
formData.append('file', acceptedFiles[0])
const xhr = new XMLHttpRequest();
xhr.open(/*params*/);
xhr.send(formData)
xhr.upload.onprogress = event => {
const percentages = +((event.loaded / event.total) * 100).toFixed(2);
this.setState({percentages})
};
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
if (xhr.status !== 200) {
/*handle error*/
}
/*handle success*/
};
}
You can use React Dropzone Uploader, which gives you file previews with upload progress out of the box, and also handles uploads for you.
import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'
const Uploader = () => {
return (
<Dropzone
getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
accept="image/*,audio/*,video/*"
/>
)
}
Uploads can be cancelled or restarted. The UI is fully customizable.
Full disclosure: I wrote this library to address some of the shortcomings and excessive boilerplate required by React Dropzone.
Here is another example based on turchak's answer for handling any number of files:
onDrop(acceptedFiles) {
const formData = new FormData();
for (const file of acceptedFiles) formData.append('file', file);
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = event => {
const percentage = parseInt((event.loaded / event.total) * 100);
console.log(percentage); // Update progress here
};
xhr.onreadystatechange = () => {
if (xhr.readyState !== 4) return;
if (xhr.status !== 200) {
console.log('error'); // Handle error here
}
console.log('success'); // Handle success here
};
xhr.open('POST', 'https://httpbin.org/post', true);
xhr.send(formData);
}

Resources