I haven't found anything about this anywhere. How can I copy a selected image into the clipboard?
I have created a custom js that adds a button to the popover of the image which works fine but I'm stuck here:
$.extend($.summernote.plugins, {
'imageCopy': function (context) {
var self = this;
var ui = $.summernote.ui,
$editable = context.layoutInfo.editable,
options = context.options,
$editor = context.layoutInfo.editor,
lang = options.langInfo,
$note = context.layoutInfo.note;
context.memo('button.imageCopy', function () {
var button = ui.button({
contents: options.imageCopy.icon,
container: false,
tooltip: lang.imageCopy.tooltip,
click: function () {
var img = $($editable.data('target'));
console.log('copy image=' + img);
}
});
return button.render();
});
}
});
So I don't really know how I can get the data from the currently selected image and put it into the clipboard.
Just referred Summernote docs and other stuff. what I understood is it is providing restoreTarget attribute for getting reference of the selected image. You can get the source of the image through that and copy it to clipboard using Clipboard API.
Here is the code that I've tried.
The snippet does not use a button but shows how to make use of the Clipboard API. Simply click on the image.
It will be blocked on iframes. The errormessage refers to https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-permissions-in-cross-origin-iframes which depends on the flags allowed for the snippets here.
Also type "image/jpeg" returns an error while "image/png" works.
img.onclick = ({ target }) => {
fetch(target.src)
.then(function(response) {
return response.blob()
})
.then(function(blob) {
navigator.clipboard.write( [new ClipboardItem({ [blob.type]: blob })]).then(
function () {
console.log("Yay");
},
function (error) {
console.error(error);
}
);
});
};
<img id="img" src="https://i.imgur.com/I6N0hf2.png" style="height: 100px;">
Related
i'm having a problem on making my code to adjust to my web server, because of the security purposes, all inline javascript code to my html is not allowed.
everything is already okay i'm just having a hard time converting my other code to pure javascript
Here is my existing code,,,
<label class=qrcode-text-btn><input type=file accept="image/*" capture=environment id="openQRCamera" tabindex=-1></label>
the original code is this
<label class=qrcode-text-btn><input type=file accept="image/*" capture=environment onchange="openQRCamera(this);" tabindex=-1></label>
the onchange is not working because it is inline in the html.
this function needs to open a camera and detect if there is a qr that exists.
here is what i have now on converting it.
document.querySelector("#openQRCamera").addEventListener('onchange', (node) => {
var reader = new FileReader();
reader.onload = function() {
node.value = "";
qrcode.callback = function(res) {
if(res instanceof Error) {
alert("There is no QR detected");
} else {
node.parentNode.previousElementSibling.value = res;
}
};
qrcode.decode(reader.result);
};
reader.readAsDataURL(node.files[0]);
});
here is the original code
function openQRCamera(node) {
var reader = new FileReader();
reader.onload = function() {
node.value = "";
qrcode.callback = function(res) {
if(res instanceof Error) {
alert("There is no QR detected");
} else {
node.parentNode.previousElementSibling.value = res;
}
};
qrcode.decode(reader.result);
};
reader.readAsDataURL(node.files[0]);
}
i am using this website as my source of code, everything is working fine in my localhost, but the server is just strict, and i think that's normal for all the websites.
https://www.sitepoint.com/create-qr-code-reader-mobile-website/
i just been stuck and try to do other solution like adding event listener, and append of input just by using jquery, but it's not working. thanks in advance.
The event listener you are using is faulty, instead of listenning to 'onchange' you have to listen to 'change' like so:
document.querySelector("#openQRCamera").addEventListener('change', () => {
//remove the node as parameter and get it with javascript:
var node = document.getElementById('openQRCamera');
..
here is the problem I am trying to solve - I am not sure it is possible at all. I have a web app and I need to enable data copy/paste from the app and to the app, and I have a problem with paste. If I past with CTRL + V shortcut I can get the data from the clipboard using
e.originalEvent.clipboardData.getData('text')
in 'paste' eventhandler and it works fine. What I need to enable is 'Paste' from custom context menu and my first try was to dispatch paste event manually like this
var event = new KeyboardEvent('paste', {
view: window,
bubbles: true,
cancelable: true
});
document.dispatchEvent(event);
and it actually hit paste eventhandler, but I couldn't get access to clipboard data like in the previous case. I understand that this is forbidden because of security issues - if this was allowed any page would be able to access data from the clipboard. My question is how to implement this - we are able to copy data from excel to e.g. google drive document and paste it there using a custom context menu (http://pokit.org/get/?1b5f6f4f0ef4b80bb8637649121bcd75.jpg), so I believe it is possible. Thank u all!
So, in my web application I have a custom context menu which has 'Paste' action (bunch of '<li>' tags in a popup). And when the user click on 'Paste' I call this function
if (browser === 'CHROME') {
var extensionId = 'some_id';
chrome.runtime.sendMessage(extensionId, { message: "getClipboardData" },
function (clipboardData) {
console.log('Clipboard data: ', clipboardData);
var txt = $('.helper_textarea');
$(txt).val(clipboardData);
// Call 'paste' function we have clipboard data
}
);
}
In my extension I have i paste.js file I have
function getDataFromClipboard() {
var bg = chrome.extension.getBackgroundPage();
var helperTextArea = bg.document.getElementById('sandbox');
if (helperTextArea == null) {
helperTextArea = bg.document.createElement('textarea');
document.body.appendChild(helperTextArea);
}
helperTextArea.value = '';
helperTextArea.select();
// Clipboard data
var clipboardData = '';
bg.document.execCommand("Paste");
clipboardData = helperTextArea.value;
helperTextArea.value = '';
return clipboardData;
}
chrome.runtime.onMessageExternal.addListener(
function(req, sender, callback) {
if (req) {
if (req.message) {
if (req.message == "installed") {
console.log('Checking is extension is installed!');
callback(true);
}
else if(req.message = "getClipboardData") {
console.log('Get clipboard data');
callback(getDataFromClipboard());
}
}
}
return true;
}
);
And in manifest file
"background" : {
"scripts" : [ "paste.js" ]
},
"externally_connectable": {
"matches": ["*://localhost:*/*"]
},
and of course
"permissions": ["clipboardRead" ],
I use this function to check if extension is added
isExtensionInstalled: function (extensionId, callback) {
chrome.runtime.sendMessage(extensionId, { message: "installed" },
function (reply) {
if (reply) {
callback(true);
} else {
callback(false);
}
});
},
And this is working great. Now the problem is how to port this to Edge. What is equivalent to 'chrome.runtime.sendMessage' in Edge? Thanks for your help.
I am using a custom confirmation dialogue with a textarea(codemirror) on it with some text populated. As code mirrors hides the actual textarea element, firefox is not able to get the data from the hidden textarea field. The definition for the confirmation box goes like below:
var confirmationDialog = MD.ui.dialogs.confirm({
title: title,
text: '',
type: 'dataUri',
dataUri: formUrl,
position: 'center',
buttonForward: {
text: 'Copy',
action: function () {
DataGridExportDialog.CopyToClipboard("#rawXmlImpExp");
}
},
buttonCancel: {
text: 'Cancel',
action: function () {
confirmationDialog.close();
confirmationDialog.destroy();
}
}
});
According to the requirement I have updated the confirm button functionality with copy to clipboard functionality so that on clicking on 'Copy' the text in the textarea should be copied to clipboard. Below is the copyToClipboard().
DataGridExportDialog.CopyToClipboard = function( containerId ) {
/*var textareaData = $('#rawXmlImpExp').val();
var range = document.createRange();
range.selectNodeContents(textareaData);
window.getSelection().addRange(range);*/
var copyTextarea = document.querySelector(containerId);
copyTextarea.select();
try {
var successful = document.execCommand('copy');
raiseMessage('Configuration XML copied to clip board.')
} catch (err) {
raiseWarning('Unable to copy. Please do so manually.');
}}
This implementation works fine on chrome but fails in firefox. Any ideas where my code fails on firefox.
Unhided the textarea in try block and hidden the same in finally block.
CopyToClipboard = function( containerId ) {
const copyTextarea = $(containerId);
try {
$(copyTextarea).css('display','block');
copyTextarea[0].select();
document.execCommand('copy');
raiseMessage('Configuration XML copied to clip board.');
}
catch (err) {
raiseWarning('Unable to copy. Please do so manually.');
}
finally {
$(copyTextarea).css('display','none');
}
}
I'm wondering if there's any way to make Dropzone.js (http://dropzonejs.com) work with a standard browser POST instead of AJAX.
Some way to inject the inputs type=file in the DOM right before submit maybe?
No. You cannot manually set the value of a <input type='file'> for security reasons. When you use Javascript drag and drop features you're surpassing the file input altogether. Once a file is fetched from the user's computer the only way to submit the file to the server is via AJAX.
Workarounds: You could instead serialize the file or otherwise stringify it and append it to the form as a string, and then unserialize it on the server side.
var base64Image;
var reader = new FileReader();
reader.addEventListener("load", function () {
base64Image = reader.result;
// append the base64 encoded image to a form and submit
}, false);
reader.readAsDataURL(file);
Perhaps you're using dropzone.js because file inputs are ugly and hard to style? If that is the case, this Dropzone.js alternative may work for you. It allows you to create custom styled inputs that can be submitted with a form. It supports drag and drop too, but with drag and drop you cannot submit the form the way you want. Disclaimer: I am author of aforementioned library.
So, if I understood correctly you want to append some data (input=file) before submit your form which has dropzone activated, right?
If so, I had to do almost the same thing and I got it through listening events. If you just upload one file, you should listen to "sending" event, but if you want to enable multiple uploads you should listen to "sendingmultiple". Here is a piece of my code that I used to make this work:
Dropzone.options.myAwesomeForm = {
acceptedFiles: "image/*",
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
init: function() {
var myDropzone = this;
[..some code..]
this.on("sendingmultiple", function(files, xhr, formData) {
var attaches = $("input[type=file]").filter(function (){
return this.files.length > 0;
});
var numAttaches = attaches.length;
if( numAttaches > 0 ) {
for(var i = 0; i < numAttaches; i++){
formData.append(attaches[i].name, attaches[i].files[0]);
$(attaches[i]).remove();
}
}
});
[..some more code..]
}
}
And that's it. I hope you find it helpful :)
PS: Sorry if there's any grammar mistakes but English is not my native language
For future visitors
I've added this to dropzone options:
addedfile: function (file) {
var _this = this,
attachmentsInputContainer = $('#attachment_images');
file.previewElement = Dropzone.createElement(this.options.previewTemplate);
file.previewTemplate = file.previewElement;
this.previewsContainer.appendChild(file.previewElement);
file.previewElement.querySelector("[data-dz-name]").textContent = file.name;
file.previewElement.querySelector("[data-dz-size]").innerHTML = this.filesize(file.size);
if (this.options.addRemoveLinks) {
file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\">" + this.options.dictRemoveFile + "</a>");
file._removeLink.addEventListener("click", function (e) {
e.preventDefault();
e.stopPropagation();
if (file.status === Dropzone.UPLOADING) {
return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function () {
return _this.removeFile(file);
});
} else {
if (_this.options.dictRemoveFileConfirmation) {
return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function () {
return _this.removeFile(file);
});
} else {
return _this.removeFile(file);
}
}
});
file.previewElement.appendChild(file._removeLink);
}
attachmentsInputContainer.find('input').remove();
attachmentsInputContainer.append(Dropzone.instances[0].hiddenFileInput).find('input').attr('name', 'files');
return this._updateMaxFilesReachedClass();
},
This is default implementation of dropzone's addedfile option with 3 insertions.
Declared variable attachmentsInputContainer. This is invisible block. Something like
<div id="attachment_images" style="display:none;"></div>
Here I store future input with selected images
Then in the end of function remove previously added input(if any) from block and add new
attachmentsInputContainer.find('input').remove();
attachmentsInputContainer.append(Dropzone.instances[0].hiddenFileInput).find('input').attr('name', 'files');
And now, when you send form via simple submit button, input[name="files"] with values will be send.
I've made this hack because I append files to post that maybe not created yet
This is what I used for my past projects,
function makeDroppable(element, callback) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', true);
input.style.display = 'none';
input.addEventListener('change', triggerCallback);
element.appendChild(input);
element.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.add('dragover');
});
element.addEventListener('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
});
element.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
triggerCallback(e);
});
element.addEventListener('click', function() {
input.value = null;
input.click();
});
function triggerCallback(e) {
var files;
if(e.dataTransfer) {
files = e.dataTransfer.files;
} else if(e.target) {
files = e.target.files;
}
callback.call(null, files);
}
}
I am creating a HTML5 SVG editor for Chrome. As a packaged app, I implemented a save dialog using this code:
function prepareExport(){
var svg = document.getElementById("canvas");
svgDoc = svg.children;
var exported = document.querySelector('#canvasWrap').innerHTML;
/*old stuff, does not work in packed apps. well for me anyway
var output = document.querySelector(".opt");
var outputTextarea = document.querySelector(".optText");
output.style.display = "block";
outputTextarea.style.display = "none";
var dlButton = document.querySelector(".dragout");
dlButton.setAttribute("href" ,"data:image/xml+svg;base64," + window.btoa(exported));
dlButton.setAttribute("data-downloadurl" ,dlButton.dataset['downloadurl'] + window.btoa(exported));
dlButton.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('DownloadURL', this.dataset.downloadurl);
}, false);
*/
chrome.fileSystem.chooseEntry({type: 'saveFile'}, function(writableFileEntry, unused) {
writableFileEntry.createWriter(function(writer) {
writer.onerror = errorHandler;
writer.onwriteend = function(e) {
console.log('write complete');
};
writer.write(new Blob([exported], {type: 'image/svg+xml'}));
}, errorHandler);
});
}
I ran this function using a button, Export SVG, and guess what? the dialog did not appear. I do not know why and this is my javascript console:
http://prntscr.com/1uklw7
This is probably a permission error. Have you added the write filesystem permission to your manifest? See http://developer.chrome.com/apps/fileSystem.html for details.
If that isn't the problem, you can get more details from chrome.lastError in your callback. See http://developer.chrome.com/apps/runtime.html#property-lastError for details of this.
Also you might want to check out the file system sample: https://github.com/GoogleChrome/chrome-app-samples/tree/master/filesystem-access.