I have the following function to copy to the clipboard:
function getScreenShot(target){
var src = document.getElementById(target);
html2canvas(src).then(function(canvas) {
//document.src.appendChild(canvas);
canvas.toBlob(function(blob) {
navigator.clipboard
.write([
new ClipboardItem(
Object.defineProperty({}, blob.type, {
value: blob,
enumerable: true
})
)
])
.then(function() {
// do something
});
});
}
This works only on my localhost. When I run it on the server, the content doesn't get copied. I read that it has to do with security issue. How do I solve it?
Here's a working version of the code. Note that images need to be on the same origin, or proxied.
const button = document.querySelector('button');
const createScreenshot = async (root) => {
const canvas = await html2canvas(root);
return new Promise((resolve) => {
canvas.toBlob((blob) => {
resolve(blob);
});
});
};
button.addEventListener('click', async () => {
button.style.display = 'none';
const blob = await createScreenshot(document.body);
try {
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
} catch (err) {
alert(`${err.name}: ${err.message}.`);
} finally {
button.style.display = '';
}
});
You can see this code in action at https://sugary-hickory-pixie.glitch.me/.
Related
I use lodash clonedeep for uploading files.
I wrote a function that forbids uploading identical files. But if I delete some file after uploading, it still stays in state and I can't upload file with the same name.
What can I do to get the file removed from the state too?
const [files, setFiles] = useState([]);
//state to store uploaded file's name
const [fileNames, setFileNames] = useState([]);
const onSelectFile = (e) => {
try {
let fileArr = cloneDeep(files);
let promises = [];
for (let file of e.target.files) {
promises.push(
new Promise((resolve, reject) => {
const fileName = file.name
//if the file has not been already uploaded
if (!fileNames.includes(fileName)) {
//add the current fileName in state
setFileNames([fileName, ...fileNames]);
const type = file.type;
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (evt) {
const fileData = evt.target.result;
fileArr.push({
name: fileName,
type: type,
data: fileData,
comment: "",
id: `${new Date().getTime()}_${fileName}`,
canDelete: true
});
if (typeof props.onFileSelected == "function")
props.onFileSelected(fileArr);
resolve(true);
}
reader.onerror = function (evt) {
console.log("error reading file");
reject(false);
}
} else {
alert("File has already been uploaded");
reject(false);
}
})
);
}
Promise.all(promises).then(r => {
setFiles(fileArr);
})
}
catch(e) {
console.log(e);
}
}
I don’t know what to do, it took me 40 hours to think, but I still didn’t understand anything.
From what I can understand from your question, you aren't saving the images on disk. You also haven't included the logic you are using for deleting files. Either way, the implementation is similar.
So when a user deletes a file, assuming they are deleting by filename, we use the filter() method to only keep those that aren't the file we want to delete.
const fileNameToRemove = 'example.txt';
setFiles(files.filter(file=> file.name !== fileNameToRemove));
setFileNames(fileNames.filter(name => name !== fileNameToRemove));
So you will want to do something like this, I haven't used clonedeep like you're in this example, but it's a quick add. I have also moved the read file section into its own function, and am I returning a promise, so I can use async/await within the core upload function.
const [files, setFiles] = useState([]);
const [fileNames, setFileNames] = useState([]);
const readFileAsync = async (file) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsArrayBuffer(file);
fileReader.onload = () => {
resolve(fileReader.result);
}
fileReader.onerror = () => {
reject(null);
}
})
}
const onSelectFile = async (e) => {
const uploadingFiles = e.target.files;
for (const file of uploadingFiles) {
const fileName = file.name;
if (fileNames.includes(fileName)) {
console.error("File duplicate");
continue;
}
try {
const fileContentsBuffer = await readFileAsync(file);
setFiles([...files, {
name: fileName,
type: file.type,
data: fileContentsBuffer,
comment: "",
id: `${new Date().getTime()}_${fileName}`,
canDelete: true
}])
setFileNames([...fileNames, fileName]);
} catch (e) {
console.error("Error reading file");
continue;
}
}
}
const deleteFile = (fileName) => {
const fileDataToDelete = files.find((file) => {
return file.name === fileName;
})
if (!fileDataToDelete.canDelete) {
console.error('Can\'t delete file!');
return;
}
setFileNames(fileNames.filter(name => name != fileName));
setFiles(files.filter(file => file.name != fileName && file.canDelete));
}
I am trying to test image pasting functionality using Playwright.
I mamanged to copy image to the clipboard but not able to paste it.
This is my code.
test.only("Clipboard", async ({browser}, testInfo) => {
const context = await browser.newContext({ permissions: ["clipboard-read", "clipboard-write"] });
const page = await context.newPage();
await page.evaluate(async () => {
const base64 = `data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==`;
const response = await fetch(base64);
const blob = await response.blob();
await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]);
const clipboardImageHolder = document.getElementById("clipboard-image");
clipboardImageHolder.focus();
const result = await navigator.clipboard.readText();
console.log(result);
});
});
when I run the test, then I press Ctrl+v manaull; I see the image pasted in the div element
Finally, this worked for me.
await page.evaluate(async () => {
const base64 = `data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==`;
const response = await fetch(base64);
const blob = await response.blob();
const clipboardImageHolder = document.getElementById("you-are-the-one");
clipboardImageHolder.focus();
let pasteEvent = new Event("paste", { bubbles: true, cancelable: true });
pasteEvent = Object.assign(pasteEvent, {
clipboardData: {
items: {
a: {
kind: "file",
getAsFile() {
return new File([blob], "foo.png", { type: blob.type });
},
},
},
},
});
console.log("event", pasteEvent);
clipboardImageHolder.dispatchEvent(pasteEvent);
});
I had to dispatch paste event and added clipboardData object to it.
I am working on a video recording task using MediaRecorder API. As from frontend I can start the webcam, record video, play the recorded video and download the video.
But when I try to upload the video to php server, it's not at all working. I don't really understand why it is happening, I also tried using so many methods but none of it is working. Please check the code attatched below.
JS:-
let mediaRecorder
let recordedBlobs
const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
const playButton = document.querySelector('button#play');
const downloadButton = document.querySelector('button#download');
document.querySelector("button#start").addEventListener("click", async function() {
const hasEchoCancellation = document.querySelector("#echoCancellation").checked
const constraints = {
audio: {
echoCancellation:{
exact: hasEchoCancellation
}
},
video: {
width: 1280,
height: 720
}
}
await init(constraints)
})
async function init(constraints) {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints)
handleSuccess(stream)
} catch(e) {
console.log(e)
}
}
function handleSuccess(stream) {
recordButton.disabled = false
window.stream = stream
const gumVideo = document.querySelector("video#gum")
gumVideo.srcObject = stream
}
recordButton.addEventListener("click", () => {
if(recordButton.textContent === "Record") {
startRecording()
} else {
stopRecording()
recordButton.textContent = 'Record'
playButton.disabled = false
downloadButton.disabled = false
}
})
function startRecording() {
recordedBlobs = []
let options = {
mimeType: "video/webm;codecs=vp9,opus"
}
try {
mediaRecorder = new MediaRecorder(window.stream, options)
} catch(e) {
console.log(e)
}
recordButton.textContent = "Stop Recording"
playButton.disabled = true
downloadButton.disabled = true
mediaRecorder.onstop = (event) => {
console.log('Recording Stopped')
}
mediaRecorder.ondataavailable = handleDataAvailable
mediaRecorder.start()
}
function handleDataAvailable(event) {
if(event.data && event.data.size > 0) {
recordedBlobs.push(event.data)
}
}
function stopRecording() {
mediaRecorder.stop()
}
playButton.addEventListener('click', function() {
const superBuffer = new Blob(recordedBlobs, {
type: 'video/webm'
})
var file = new File([superBuffer], 'test.webm')
var url = window.URL.createObjectURL(superBuffer)
// var video = blobToFile(superBuffer, 'test.webm')
sendToServer(file)
recordedVideo.src = null
recordedVideo.srcObject = null
recordedVideo.src = url
recordedVideo.controls = true
recordedVideo.play()
})
downloadButton.addEventListener('click', () => {
const blob = new Blob(recordedBlobs, {type: 'video/mp4'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'test.mp4';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
});
function sendToServer(file) {
let url = 'send.php'
let headers = {
'Content-Type': 'multipart/form-data'
}
var formData = new FormData()
formData.append("file", file)
axios.post(url, formData, headers)
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.log(error.response)
})
}
function blobToFile(theBlob, fileName){
//A Blob() is almost a File() - it's just missing the two properties below which we will add
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
PHP:-
$target_dir = "uploads/";
$target_file = $target_dir . 'test.webm';
if(move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
echo "File uploaded successfully";
} else {
echo "File not uploaded";
}
print_r($_FILES['file']['error']);
No matter how much I tried, I can't figure out why it is not working. It is showing that "File not uploaded" like it can't read the file from tmp_name. Please help me fix the problem.
Any help on this problem will be really appreciated.
Thank you.
I download data from API in chunks decrypt it and than pass to ReadableStream.
But after last chunk, the file is not downloaded.
I work with axios and StreamSaver.js
Code:
Above in the code I declare:
this.filestream = streamSaver.createWriteStream('sample.jpg');
this.writer = await this.filestream.getWriter();
let readableStream;
readableStream = new ReadableStream({
start(ctrl) {
const nextChunk = async () => {
let fileDataResponse = await that.$api.post(
'endpoint', {
file_id: UUID,
chunk_index: index
}, {
headers: {
...
}
}
);
done =
fileDataResponse.data.length <=
fileDataResponse.data.current_index;
if (fileDataResponse.data.data) {
let data = await that.decryptData(fileDataResponse.data.data);
ctrl.enqueue(data);
}
if (!done) {
index += 1;
nextChunk();
} else {
ctrl.close();
}
};
nextChunk();
}
});
const reader = readableStream.getReader();
const close = () => {
that.writer.close();
};
const pump = () =>
reader.read().then((res) => {
if (!res.done) {
that.writer.write(res.value).then(pump);
} else {
close();
}
});
pump();
Where could be my error here?
Thank you a lot!
Issue was the res.value is not an Int8Array
I am working on an app and I am using expo, I want to make sure each user can upload an image to firebase, and later publish this image on the profile page.
Using expo this is how I upload images:
const pickImage = async () => {
let pickerResult = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(pickerResult);
handleImagePicked(pickerResult);
};
the result in the console is:
Object {
"cancelled": false,
"height": 312,
"type": "image",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fallergyn-app-77bfd368-65fd-43f9-8c34-9c35cef42c25/ImagePicker/daaa229c-c352-4994-ae18-ca2dbb3534ce.jpg",
"width": 416,
}
and this is how I upload to the firebase:
const handleImagePicked = async (pickerResult) => {
try {
if (!pickerResult.cancelled) {
setImage(pickerResult.uri);
await uploadImageAsync(pickerResult.uri);
console.log("done");
}
} catch (e) {
console.log(e);
alert("Upload failed, sorry :(");
} finally {
}
};
async function uploadImageAsync(uri) {
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", uri, true);
xhr.send(null);
});
const ref = firebase
.storage()
.ref()
.child("images" + Math.random());
const snapshot = await ref.put(blob);
// We're done with the blob, close and release it
blob.close();
return await snapshot.ref.getDownloadURL();
}
this code works it saves the path of the image this: "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fallergyn-app-77bfd368-65fd-43f9-8c34-9c35cef42c25/ImagePicker/daaa229c-c352-4994-ae18-ca2dbb3534ce.jpg" in the firebase under user collection using the uid of the user.
I am not sure if this is good, because I want to make sure the image itself is uploaded to firebase, I saw some threads in StackOverflow regarding this issue either too old or no answers, so I am hoping to get some sort of solution to what I need to do.
if I use
const ref = firebase
.storage()
.ref()
.child("images" + Math.random());
.putFile(uri);
this tells me that putFile is not a function. the same with put(uri)
Try this one. This function returns the path of the saved image from firebase which you will store in the user's document instead.
const handleImagePicked = async (pickerResult) => {
if (!pickerResult.cancelled) {
setImage(pickerResult.uri);
const result = await uploadImageAsync(pickerResult.uri);
if(result) {
console.log('success');
//save the result path to firestore user document
return;
}
alert("Upload failed, sorry :(");
}
};
export const uploadImageAsync = async (uri: string) => {
let filename = uri;
if (Platform.OS === 'ios') {
filename = uri.replace('file:', '');
}
const ext = filename.split('.').pop();
const path = `images/${id}.${ext}`;
const ref = firebase.storage().ref(path);
try {
const response = await fetch(filename);
const blob = await response.blob();
await ref.put(blob);
return path;
} catch {
return null;
}
};
This worked for me , using rn-fetch-blob
import launchImageLibrary from 'react-native-image-picker';
import RNFetchBlob from 'rn-fetch-blob';
import storage from '#react-native-firebase/storage';
const pickImage = () => {
let options = {
mediaType: 'photo',
quality: 0.5,
};
launchImageLibrary(options, (response) => {
console.log('Response = ', response);
uploadImagePicked(response);
});
};
const uploadImagePicked = (response) => {
if (response.fileName) {
const fileName = response.fileName;
var storageRef = storage().ref(`receiptImages/${fileName}`);
RNFetchBlob.fs.readFile(response.uri , 'base64')
.then(data => {
storageRef.putString(data, 'base64', {contentType:"image/jpg"})
.on(
storage.TaskEvent.STATE_CHANGED,
snapshot => {
console.log("snapshot: " + snapshot.state);
console.log("progress: " + (snapshot.bytesTransferred / snapshot.totalBytes) * 100);
if (snapshot.state === storage.TaskState.SUCCESS) {
console.log("Success");
}
},
error => {
console.log("image upload error: " + error.toString());
},
() => {
storageRef.getDownloadURL()
.then((downloadUrl) => {
console.log("File available at: " + downloadUrl);
})
})
})
.catch(error => {
console.log(error);
})
}
else {
console.log("Skipping image upload");
}
}