I am using quill editor and using a image handler for uploading images and it used to work fine but now i am moving to server side rendering and find this error of "File chooser dialog can only be shown with a user activation." while trying to open the file chooser for uploading the file.
imageHandler() {
//
let self=this
let image;
let image_extension;
var input = document.createElement("input");
// Set its type to file
input.type = "file";
// Set accept to the file types you want the user to select.
// Include both the file extension and the mime type
input.accept = "accept";
// set onchange event to call callback when user has selected file
input.addEventListener("change", onchange)
// dispatch a click event to open the file dialog
input.dispatchEvent(new MouseEvent("click")); //getting the error in this line.
input.onchange = async () => {
//
const file = input.files[0];
var ValidImageTypes = ["image/gif", "image/jpeg", "image/png", "image/jpg", "image/GIF", "image/JPEG", "image/PNG", "image/JPG"];
let file_type = file.type
let filename = file.name
let extension = filename.split('.').pop();
// debugger
if(ValidImageTypes.indexOf(file_type) >= 0){
if(file.size<=500000&&file.size>=50000){
// debugger
var fileToLoad = file
// loadImage(fileToLoad, (canvas) => {
// if(canvas){
// this.setState({
// image=canvas.toDataURL()
// image_extension=extension
// });
this.getBase64(file)
.then(result => {
// debugger
file["base64"] = result;
console.log("File Is",file.base64 );
const res = new Promise(function(resolve, reject) {
axios({
method:'post',
url:API_URL+'api/v1/postblogimage',
headers:{
'x-access-handler':loggedinUser.token
},
data:{
image: file.base64,
image_extension:image_extension,
userid:loggedinUser.userid
}
})
//axios.post(API_URL + 'api/v1/postblogimage', formData, config)
.then((response) => {
if (response.data.error == 'false' || response.data.error == false) {
if (response.data.status == 200 && response.data.message == "Image uploaded successfully") {
//
const range = self.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)
self.quill.setSelection(range.index + 1);
// Remove placeholder image
self.quill.deleteText(range.index, 1);
// Insert uploaded image
let url=response.data.data[0].imageURL;
self.quill.insertEmbed(range.index, 'image', url);
self.quill.pasteHTML(range.index, <img src={url} class="blog-image-content" alt="Responsive image"/>);
}
}
// else if(response.data.error == 'true' || response.data.status == '500')
// componentProps.error('Sorry, Inappropriate image')
// }
}).catch((error) => {
// reject(Error("It broke"));
});
});
// }
// }, {orientation: true});
// }
})
}
else{
// componentProps.error(" Sorry, File size should be of size between 50 kb to 500kb")
}
}
else{
// this.setState({
// image_warning:'Invalid image type',
// image:'',
// image_extension:''
//})
// this.fileInput.value=''
}
};
}
//render function
<ReactQuill
ref={(el) => this.quillRef = el
}
onChange={this.handleChange}
placeholder={"You can insert images between your blog as well. Max image size to not exceed 500kb.Once you have uploaded an image, just wait, image will show up, if it is approved. Use #hashtags to highlight keywords/impact-terms in your blog, your blog might show up in trending keywords. Example: #gain"}
modules={{
toolbar: {
container: [
[{ header: '1' }, { header: [2,3, 4, 5, 6] }, { font: [] }],
[{ size: [ 'small', false, 'large', 'huge' ] }],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{ list: 'ordered' }, { list: 'bullet' }],
['link', 'image', 'video'],
['clean'],
['code-block'],
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'align': [] }],
],
handlers: {
image: this.imageHandler
}
}
}}
/>
Before you click you must add the input to the document body
document.body.appendChild(input);
Related
One quick question. I want to process my canvas into the JotForm Api.
I tried doing it by chart only and it is working. But when doing it on the canvas itself it do not show any data in my JotForm.
This is my code
//Listen for Jotform to get ready
JFCustomWidget.subscribe('ready', function (data) {
//listen for button click
var snapBtn = document.getElementById('snap')
snapBtn.addEventListener('click', () => {
screenshot();
})
// prep data
function prepData(dataURL) {
return {
valid: true,
value: JFCustomWidgetUtils.buildMetadata('imagelinks', [{
'name': "Data from table",
'base64': dataURL
}])
}
}
//process image for form submission
var resultChart, imageData;
var submissionData = {
valid: false,
value: ''
};
// function screenshot() {
// document.querySelectorAll('.chartjs-render-monitor').forEach( chart => { chart.style.display !== 'none' ? resultChart = chart : ''} );
// if(resultChart){
// imageData = resultChart.toDataURL();
// submissionData = prepData( imageData );
// JFCustomWidget.sendData( submissionData );
// }
// }
function screenshot() {
html2canvas(document.body, {
scrollY: -window.scrollY,
crossOrigin: 'Anonymous',
allowTaint: true,
foreignObjectRendering: true,
}).then(function (canvas) {
document.body.appendChild(canvas);
$data0101 = document.body.appendChild(canvas).toDataURL();
document.body.removeChild(canvas);
})
document.querySelectorAll($data0101).forEach
// document.querySelectorAll('.chartjs-render-monitor').forEach( chart => { chart.style.display !== 'none' ? resultChart = chart : ''} );
if (resultChart) {
imageData = $data0101;
submissionData = prepData(imageData);
JFCustomWidget.sendData(submissionData);
}
}
//listen for submit event
JFCustomWidget.subscribe('submit', function () {
JFCustomWidget.sendSubmit(submissionData);
});
});
The working code here is on the part where I commented it.
// function screenshot() {
// document.querySelectorAll('.chartjs-render-monitor').forEach( chart => { chart.style.display !== 'none' ? resultChart = chart : ''} );
// if(resultChart){
// imageData = resultChart.toDataURL();
// submissionData = prepData( imageData );
// JFCustomWidget.sendData( submissionData );
// }
// }
and here,
// document.querySelectorAll('.chartjs-render-monitor').forEach( chart => { chart.style.display !== 'none' ? resultChart = chart : ''} );
I need to get the canvas or the whole HTML itself that is on the actual monitor instead of just the chart I made.
Is there a way I can get my canvas to be inserted inside not the chart. I am lost at this area. Thanks
I am uploading an image using drag n drop and cropping it using croppie plugin. Also, in case if the user has selected the wrong image and wants to change it then there is a browse again button to switch back to drag n drop state.
Everything was working fine while I was doing this with jquery code. However, I am trying to refactor my code to use Javascript Promise, it just runs for the first time only.
Promise code:
const dragDrop = (params, element) => {
return new Promise((resolve, reject) => {
$(element || '.drag-drop').on('dragover', (e) => {
e.preventDefault();
}).on('dragleave', (e) => {
e.preventDefault();
}).on('drop', (e) => {
e.preventDefault();
let fileList = e.originalEvent.dataTransfer.files;
let conditions = $.extend({}, {
files: 1,
fileSize: (1024 * 1024 * 5),
type: ["image/gif", "image/jpeg", "image/jpg", "image/png"],
extension: ["gif", "jpeg", "jpg", "png"]
}, (params || {}));
if (fileList.length > conditions.files)
{
reject('Please choose only ' + conditions.files + ' file(s)');
}
else if (fileList[0].size > (conditions.fileSize))
{
reject('File to large.!<br>Allowed: ' + (conditions.fileSize) + 'MB');
}
else
{
if (fileList[0].type == '')
{
let ext = (fileList[0].name).split('.');
if ($.inArray(ext[ext.length - 1], conditions.extension) < 0)
{
reject('File type not allowed');
}
}
else if ($.inArray(fileList[0].type, conditions.type) < 0)
{
reject('File type not allowed');
}
}
resolve(fileList);
});
})
};
Drag-Drop code:
dragDrop().then((files) => {
croppie({
url: 'url to upload',
data: {
token: "user identification token string"
}
}, files);
}).catch((message) => {
alert(message);
});
Croppie code:
function croppie(ajax, files, croppie, el)
{
// variables
let $image = $((el.image !== undefined) ? el.image : 'div.js-image');
let $button = $((el.button !== undefined) ? el.button : '.js-crop-button');
let $dragDrop = $((el.dragDrop !== undefined) ? el.dragDrop : '.drag-drop');
let $browseButton = $((el.browse !== undefined) ? el.browse : '.js-browse');
$imageCrop = $image.croppie($.extend(true, {
enableExif: true,
enableOrientation: true,
viewport: {
width: 200,
height: 200,
type: 'square'
},
boundary: {
height: 500
}
}, croppie)).removeClass('d-none');
var reader = new FileReader();
reader.onload = (event) => {
$imageCrop.croppie('bind', {
url: event.target.result
});
}
reader.readAsDataURL(files[0]);
$image.parent().removeClass('d-none');
$button.removeClass('d-none');
$dragDrop.addClass('d-none');
$('.js-rotate-left, .js-rotate-right').off('click').on('click', function (ev) {
$imageCrop.croppie('rotate', parseInt($(this).data('deg')));
});
$browseButton.off('click').on('click', function() {
$image.croppie('destroy');
$image.parent().addClass('d-none');
$button.addClass('d-none');
$dragDrop.removeClass('d-none');
});
$button.off('click').on('click', () => {
$imageCrop.croppie('result', {
type: 'canvas',
size: 'viewport'
}).then((response) => {
ajaxRequest($.extend(true, {
data: {
"image": response,
},
success: (data) => {
(data.success == true)
? window.parent.location.reload()
: alert(data.message);
}
}, ajax));
});
});
}
I have a custom button (embed) in my quill editor that uses the prompt to call the windows popup
Now, I want to change the windows popup to a modal on the click of the embed button.
I honestly don't know how to go about this as this is my first time using a quill.
I'm using a quill extension file to create the custom button(embed)
I'm perplexed on were to create the modal and also how to call the modal when the quill custom button is clicked.
This is how I call the quill from my view
<div class="form-group col-xs-12">
<label class="control-label">
Description
</label>
<div id="createSchool_Description_div" style="height:300px;"></div>
</div>
<script>
$(document).ready(function () {
<text>
prepareQuill('#createSchool_Description_div');
</text>
}
My quill extension file
var quills = {};
function addQuillExtension(__quill) {
if (__quill === undefined || __quill === null) {
throw new this.DOMException("__quill editor not defined");
}
else {
__quill.root.addEventListener("paste", function (e) {
retrieveImageFromClipboardAsBase64(e, function (imageDataBase64) {
// If there's an image, open it in the browser as a new window :)
if (imageDataBase64) {
// data:image/png;base64,iVBORw0KGgoAAAAN......
let content = __quill.getContents();
__quill.clipboard.dangerouslyPasteHTML(content.length, "<img src=" + imageDataBase64 + ">");
//window.open(imageDataBase64);
}
});
}, false);
let embedbutton = __quill.container.previousSibling.querySelector('.ql-embed');
embedbutton.setAttribute('title', 'Embed video/audio');
embedbutton.onclick = function () {
let url = prompt("Enter youtube URL");
let spliturl = url.split('=');
let suffix = spliturl[1];
let embedurl = `https://www.youtube.com/embed/${suffix}?rel=0`;
//debugger;
let embedhtml = `<iframe class="youtubeembed" src="${embedurl}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
let content = __quill.getContents();
__quill.clipboard.dangerouslyPasteHTML(content.length, embedhtml);
};
}
function retrieveImageFromClipboardAsBase64(pasteEvent, callback, imageFormat) {
if (pasteEvent.clipboardData === false) {
if (typeof callback === "function") {
callback(undefined);
}
}
var items = pasteEvent.clipboardData.items;
if (items === undefined) {
if (typeof callback === "function") {
callback(undefined);
}
}
for (var i = 0; i < items.length; i++) {
// Skip content if not image
if (items[i].type.indexOf("image") === -1) continue;
// Retrieve image on clipboard as blob
var blob = items[i].getAsFile();
// Create an abstract canvas and get context
var mycanvas = document.createElement("canvas");
var ctx = mycanvas.getContext('2d');
// Create an image
var img = new Image();
// Once the image loads, render the img on the canvas
img.onload = function () {
// Update dimensions of the canvas with the dimensions of the image
mycanvas.width = this.width;
mycanvas.height = this.height;
// Draw the image
ctx.drawImage(img, 0, 0);
// Execute callback with the base64 URI of the image
if (typeof callback === "function") {
callback(mycanvas.toDataURL(imageFormat || "image/png"));
}
};
// Crossbrowser support for URL
var URLObj = window.URL || window.webkitURL;
// Creates a DOMString containing a URL representing the object given in the parameter
// namely the original Blob
img.src = URLObj.createObjectURL(blob);
}
}
}
function prepareQuill(selector, html) {
let quill;
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
//[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'script': 'sub' }, { 'script': 'super' }], // superscript/subscript
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
[{ 'direction': 'rtl' }], // text direction
//[{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'font': [] }],
[{ 'align': [] }],
['link', 'image', 'embed'],
['clean'], // remove formatting button
['save']
];
quill = new Quill(selector, {
modules: {
toolbar: toolbarOptions
},
theme: 'snow'
});
addQuillExtension();
if (html) {
quill.clipboard.dangerouslyPasteHTML(html);
}
quills[selector] = quill;
return quill;
//quill.enable();
}
function getEditorHtml(id) {
let holder = document.getElementById(id).querySelector('.ql-editor');
let clone = holder.cloneNode(true);
return clone.innerHTML;
}
function getQuillEditorHtml(id) {
let html = getEditorHtml(id);
return html;
}
function setQuillEditorHtml(selector, html) {
let quill = quills[selector];
if (quill) {
quill.clipboard.dangerouslyPasteHTML(html);
}
else {
throw `quill editor for '${selector}' not found`;
}
}
I do not think you need to write a custom button for this as quill already has a video embed button.
Just add 'video' in your toolbar options when creating the quill example below :
['bold', 'italic', 'underline', 'strike', '**video**']]
I have implemented Filepond uploaded in my page. When the user selects a file, I set that file on a html canvas for edits. However when the user wants to upload another file, filepond input retains last uploaded file.
I have tried FilePond.destroy(inputElement); after the file is successfully set on the canvas in the FilePond:addfile event.
$('.upload-file').filepond();
$.fn.filepond.registerPlugin(
FilePondPluginFileValidateType,
FilePondPluginFileValidateSize,
FilePondPluginImageResize,
FilePondPluginImageExifOrientation,
FilePondPluginImagePreview,
FilePondPluginImageTransform,
FilePondPluginImageCrop,
FilePondPluginImageValidateSize,
);
FilePond.setOptions({
labelIdle: 'Drag & Drop your file or <span class="filepond--label-
action"> Browse </span>',
maxFiles: 1,
allowDrop: true,
allowMultiple: false,
dropOnPage: true, //for page to work, element has to be false https://github.com/pqina/filepond/issues/113
dropOnElement: false,
labelTapToCancel: '', //we dont want to allow cancel
labelTapToUndo: '',
maxFileSize: intFileSizeInMB,
allowReplace: true,
allowRevert: false,
instantUpload: false
});
const pond = document.querySelector('.filepond--root');
pond.addEventListener('FilePond:addfile', e => {
console.log('File added', e.detail);
if (e.detail) {
if (e.detail.file && e.detail.file.file.name) {
SetFileOnCanvas(e.detail.file.file, e.detail.file.file.name);
const inputElement = document.querySelector('input[type="file"]');
FilePond.destroy(inputElement);
}
}
});
pond.addEventListener('FilePond:processfile', e => {
console.log('Process File COMPLETE', e.detail);
});
After a file is uploaded and set to Canvas the file upload input should be cleared and ready for another upload.
Working solution
var pond_ids = [];
if (pond.getFiles().length != 0) { // "pond" is an object, created by FilePond.create
pond.getFiles().forEach(function(file) {
pond_ids.push(file.id);
});
}
pond.removeFiles(pond_ids);
After upload file "Complete function"
you can do like this (simple example):
if (filePond.getFiles().length != 0) {
for (var i = 0; i <= filePond.getFiles().length - 1; i++) {
filePond.removeFile(filePond.getFiles()[0].id)
}
}
I know its too late but you can use
let filePond = FilePond.find(document.getElementById(filePondElementId));
if (filePond != null) {
//this will remove all files
filePond.removeFiles();
}
<script src="https://unpkg.com/filepond/dist/filepond.min.js"></script>
Assuming that you create your filepond instance through function create_pondProfile and your input has class filepond, in you filepond config in server block do like this:
server: {
url: '',
process: {
url: '/path/to/upload/',
headers: {'X-CSRF-TOKEN': csrf},
ondata: (formData) => {
return formData;
},
onload: (response) => {
FilePond.destroy(document.querySelector('.filepond'));
create_pondProfile('.filepond');
}
},
...
...
}
It will destroy current instance of filepond and creates new one after upload.
I am implementing a picture upload functionality to my app which I am developing with Ionic 4. I'm using the native plugin camera and a few others to do the following:
async selectImage() {
const actionSheet = await this.actionsheet.create({
header: "Select Image source",
buttons: [{
text: 'Load from Library',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
}
},
{
text: 'Use Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA);
}
},
{
text: 'Cancel',
role: 'cancel'
}
]
});
await actionSheet.present();
}
takePicture(sourceType: PictureSourceType) {
var options: CameraOptions = {
quality: 100,
sourceType: sourceType,
saveToPhotoAlbum: false,
correctOrientation: true
};
this.camera.getPicture(options).then(imagePath => {
var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
});
}
copyFileToLocalDir(namePath, currentName, newFileName) {
this.file.copyFile(namePath, currentName, this.file.dataDirectory, newFileName).then(success => {
this.presentToast('Dispongo a actualizar.');
this.updateStoredImages(newFileName);
}, error => {
// this.presentToast('Error while storing file.');
});
}
updateStoredImages(name) {
this.storage.get(STORAGE_KEY).then(images => {
let arr = JSON.parse(images);
if (!arr) {
let newImages = [name];
this.storage.set(STORAGE_KEY, JSON.stringify(newImages));
} else {
arr.push(name);
this.storage.set(STORAGE_KEY, JSON.stringify(arr));
}
let filePath = this.file.dataDirectory + name;
let resPath = this.pathForImage(filePath);
let newEntry = {
name: name,
path: resPath,
filePath: filePath
};
this.images = [newEntry, ...this.images];
this.ref.detectChanges(); // trigger change detection cycle
});
}
So, in the action sheet, when I press the first option (Load from Library) it opens the library and I can choose the picture without any problem. When I press ok, it throws an error: the error expected from the copyFileToLocalDir. However, if I do the same with the second option (Use Camera) and I take a photo with the camera, it loads it fine and I can store it later.
I can't find the problem, please help.
im using this code using ionic 3 and it's working fine .
and after i chose one image it will be uploading to firebase and on the same time view it at page.html
app.module.ts
you have to import
import { Camera } from "#ionic-native/camera";
import { File } from "#ionic-native/file";
and added them #providers
then use this code at page.ts which you will chose one image :
html view
<button ion-button full (click)="openGallery()">open gallery</button>
<img [src]="camel_profile_image_path" />
ts page
import { Camera, CameraOptions } from "#ionic-native/camera";
private camera: Camera,
async openGallery() {
try {
const opstions: CameraOptions = {
quality: 100,
targetHeight: 600,
targetWidth: 600,
destinationType: this.camera.DestinationType.DATA_URL,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
correctOrientation: true
}
const result = await this.camera.getPicture(opstions);
const image = 'data:image/jpeg;base64,' + result;
const pictures = storage().ref('Profile Images/' + this.randomNumber + '.jpg');
pictures.putString(image, 'data_url');
this.base64Image = image;
this.camel_profile_image_path = this.randomNumber; // view the image on html page
this.slidetothis();
} catch (error) {
console.error(error);
}
}