Not sure why this has been so difficult for me today, but for some reason I cannot seem to get it to copy the current URL to the clipboard. Overall, I'm looking for a way to do it without needing to create some hidden text elements.
This is what I'm trying so far:
var shareBtn = document.querySelector(".share-button");
shareBtn.addEventListener('click', function(event) {
var cpLink = window.location.href;
cpLink.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copy command was ' + msg);
} catch (err) {
console.log('Oops, unable to copy');
}
event.preventDefault;
});
When I try to go about it using the .select() I get this error:
t.select is not a function
So I'm not 100% sure what the best way to go about this. Again, without using jQuery (or any other JS library) and not using some sort of hidden textfield.
You can create a temporary DOM element to hold the URL
Unfortunately there is no standard API for clipboard operations, so we're left with the hacky way of using a HTML input element to fit our needs. The idea is to create an input, set its value to the URL of the current document, select its contents and execute copy.
We then clean up the mess instead of setting input to hidden and polluting the DOM.
var dummy = document.createElement('input'),
text = window.location.href;
document.body.appendChild(dummy);
dummy.value = text;
dummy.select();
document.execCommand('copy');
document.body.removeChild(dummy);
2021 update: you can use the Clipboard API like so:
navigator.clipboard.writeText(window.location.href);
ppajer's answer is indeed all that's needed when the browser handles the copying, without any custom handling of clipboard events being involved.
But if you or some library hook into the copy event (say, window.addEventListener('copy', ...) and then if that handler relies on using window.getSelection(), then a 19 year old Firefox issue will bite you. Like MDN says:
It is worth noting that currently getSelection() doesn't work on the content of <textarea> and <input> elements in Firefox, Edge (Legacy) and Internet Explorer.
So, getSelection() returns a non-null result after HTMLInputElement#select, but without providing the actual selected content. Easily fixed by using a non-input element to temporarily hold the URL:
function copyUrl() {
if (!window.getSelection) {
alert('Please copy the URL from the location bar.');
return;
}
const dummy = document.createElement('p');
dummy.textContent = window.location.href;
document.body.appendChild(dummy);
const range = document.createRange();
range.setStartBefore(dummy);
range.setEndAfter(dummy);
const selection = window.getSelection();
// First clear, in case the user already selected some other text
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
document.body.removeChild(dummy);
}
(The above will also work when no custom handler hooks into the copy event.)
this might be one of the simpler ways to do it
window.navigator.clipboard.writeText(textToCopy);
var $temp = $("<input>");
var $url = $('.copy').attr('href');
$('.clipboard').on('click', function() {
$("body").append($temp);
$temp.val($url).select();
document.execCommand("copy");
$temp.remove();
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
})
Toast.fire({
icon: 'success',
title: 'URL copied! '
})
})
Related
I have the following code for chrome addon's js to copy some certain data to clipboard from a certain webpage(I will write code to get data from the webpage later).
// 1. Create the button
var testButton = document.createElement("button");
testButton.innerHTML = "Copy";
// 2. Append somewhere
var btnPos = document.getElementsByClassName("menu-userdetails")[0];
btnPos.appendChild(testButton);
// 3. Add event handler
testButton.addEventListener ("click", copyToClipboard);
function copyToClipboard() {
var textArea = document.createElement("textarea");
textArea.value = "test copying";
btnPos.appendChild(textArea);
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying text command was ' + msg);
} catch (err) {
console.log('Oops, unable to copy');
}
document.body.removeChild(textArea);
}
In this code I have to append the text area to the webpage(after button click) before copying it. But I don't want the textarea to be shown I want to just copy the data inside the textarea without displaying the textarea.
textArea.style.height = "0px";
textArea.style.width = "0px";
textArea.style.opacity = "0";
Adding this code hides the text area.
But even better solution was already in my code, I just made a little mistake in it.
I wrote
document.body.removeChild(textArea);
While actually I had to write
btnPos.removeChild(textArea);
this removes the text area after copying and its so fast that you can't even see the text area appear and disappear.
I needed to copy text from an extjs htmleditor component to the clipboard and then paste it into a text document (word or oppenoffice).
It is possible to achieve this with the W3C clipboard API?
handler:function(){
var one = Ext.ComponentQuery.query('#OneItemId')[0].getValue();
var two = Ext.ComponentQuery.query('#TwoItemId')[0];
document.addEventListener('copy', function(e){
e.clipboardData.setData('text/plain', one);
e.preventDefault();
});
document.addEventListener('paste', function(e){
var values = e.clipboardData.getData('text/html');
two.setValue(values);
});
}
https://fiddle.sencha.com/#fiddle/1cdi
I think you cannot use ClipboardEvent interface, because it represents events providing information related to modification of the clipboard, that is cut, copy, and paste events and since you want to copy on button click there is no such event.
Select and copy text in htmleditor component manually is abit tricky since its DOM representation is <iframe>.
I think solution is something like:
{
xtype:'button',
text:'Copy',
handler:function(){
var one = Ext.ComponentQuery.query('#OneItemId')[0];
var two = Ext.ComponentQuery.query('#TwoItemId')[0];
var editorFrame = one.inputEl.dom,
editorFrameDocument = editorFrame.contentDocument || editorFrame.contentWindow.document;
if(editorFrameDocument) {
var documentSelection, selectionRange;
// Select text in htmleditor iframe body
// IE
if (editorFrameDocument.body.createTextRange) {
selectionRange = editorFrameDocument.body.createTextRange();
selectionRange.moveToElementText(editorFrameDocument.body);
selectionRange.select();
} else if (window.getSelection) {
documentSelection = editorFrameDocument.getSelection()
selectionRange = editorFrameDocument.createRange()
selectionRange.selectNodeContents(editorFrameDocument.body);
documentSelection.removeAllRanges();
documentSelection.addRange(selectionRange);
}
// Copy selected text
editorFrameDocument.execCommand('copy');
}
}
}
Working fiddle
Just add some text to the editor, click "Copy" and paste wherever you want.
How can I copy a specific text with protractor ?
I would like to load a text to paste after with this command :
return browser.actions().sendKeys(Keys.CONTROL, 'v').perform();
Sample :
Load my text "test" and after with this command, paste "test"
I would like put a text in my clipboard
can I put a value directly in my ng-model, not use sendKeys ?
Yes, you can directly set the model value via .evaluate():
var elm = element(by.model("mymodel.field"));
elm.evaluate("mymodel.field = 'test';");
Putting a text into clipboard
The idea is to use an existing or dynamically create an input element where you would send the text to, select all the text in the input and copy it with a CTRL/COMMAND + C shortcut.
Sample:
var textToBeCopied = "my text";
// creating a new input element
browser.executeScript(function () {
var el = document.createElement('input');
el.setAttribute('id', 'customInput');
document.getElementsByTagName('body')[0].appendChild(el);
});
// set the input value to a desired text
var newInput = $("#customInput");
newInput.sendKeys(textToBeCopied);
// select all and copy
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "a"));
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "c"));
where browser.controlKey is a cross-platform way to handle CTRL/COMMAND keys:
Using cross-platform keyboard shortcuts in end-to-end testing
Somewhat related to this: I needed to test a dialog, which placed some text in the clipboard when the user pressed the 'Copy' button in the dialog. I wanted to test that the text really got copied to the clipboard. I found this 'copy-paste' library: https://www.npmjs.com/package/copy-paste . "A command line utility that allows read/write (i.e copy/paste) access to the system clipboard. It does this by wrapping pbcopy/pbpaste (for OSX), xclip (for Linux and OpenBSD), and clip (for Windows)." I would say it is a javascript module rather than a command line utility. Anyway, I started using it, as the depenency on xclip (for Linux) was not a problem for me.
Here's the snippet I use with protractor to copy text to the clipboard. I need tabs to be accepted because most of my testing involves cut-and-paste from spreadsheets, where tab is the default column delimiter.
Further, it accommodates nuances in the html body's layout better (overflow: hidden).
function copyToClipboard(browser, text) {
var id = 'someCustomIdToAvoidAliasing';
var newInput = browser.element(by.css("#" + id));
return browser.executeScript(function () {
var el = document.createElement('textarea');
el.setAttribute('id', 'someCustomIdToAvoidAliasing');
el.setAttribute('style', 'position:fixed;z-index:10000;top:0;left:0');
el.onkeydown = function(e) {
if (e.keyCode === 9) {
this.value = this.value + "\t";
return false;
}
};
document.getElementsByTagName('body')[0].appendChild(el);
})
.then(function() {
return newInput.sendKeys(text);
})
.then(function() {
return newInput.sendKeys(protractor.Key.CONTROL, "a", protractor.Key.NULL);
})
.then(function() {
return newInput.sendKeys(protractor.Key.CONTROL, "c", protractor.Key.NULL);
})
.then(function() {
return browser.executeScript(function() {
var el = document.getElementById('someCustomIdToAvoidAliasing');
el.remove();
});
});
}
I have no knowledge of JavaScript, but I managed to put this code together using bits and bolts from various Stack Overflow answers. It works OK, and it outputs an array of all selected checkboxes in a document via an alert box.
function getSelectedCheckboxes(chkboxName) {
var checkbx = [];
var chkboxes = document.getElementsByName(chkboxName);
var nr_chkboxes = chkboxes.length;
for(var i=0; i<nr_chkboxes; i++) {
if(chkboxes[i].type == 'checkbox' && chkboxes[i].checked == true) checkbx.push(chkboxes[i].value);
}
return checkbx;
}
And to call it I use:
<button id="btn_test" type="button" >Check</button>
<script>
document.getElementById('btn_test').onclick = function() {
var checkedBoxes = getSelectedCheckboxes("my_id");
alert(checkedBoxes);
}
</script>
Now I would like to modify it so when I click the btn_test button the output array checkbx is copied to the clipboard. I tried adding:
checkbx = document.execCommand("copy");
or
checkbx.execCommand("copy");
at the end of the function and then calling it like:
<button id="btn_test" type="button" onclick="getSelectedCheckboxes('my_id')">Check</button>
But it does not work. No data is copied to clipboard.
function copyToClipboard(text) {
var dummy = document.createElement("textarea");
// to avoid breaking orgain page when copying more words
// cant copy when adding below this code
// dummy.style.display = 'none'
document.body.appendChild(dummy);
//Be careful if you use texarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard
dummy.value = text;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
}
copyToClipboard('hello world')
copyToClipboard('hello\nworld')
OK, I found some time and followed the suggestion by Teemu and I was able to get exactly what I wanted.
So here is the final code for anyone that might be interested. For clarification, this code gets all checked checkboxes of a certain ID, outputs them in an array, named here checkbx, and then copies their unique name to the clipboard.
JavaScript function:
function getSelectedCheckboxes(chkboxName) {
var checkbx = [];
var chkboxes = document.getElementsByName(chkboxName);
var nr_chkboxes = chkboxes.length;
for(var i=0; i<nr_chkboxes; i++) {
if(chkboxes[i].type == 'checkbox' && chkboxes[i].checked == true) checkbx.push(chkboxes[i].value);
}
checkbx.toString();
// Create a dummy input to copy the string array inside it
var dummy = document.createElement("input");
// Add it to the document
document.body.appendChild(dummy);
// Set its ID
dummy.setAttribute("id", "dummy_id");
// Output the array into it
document.getElementById("dummy_id").value=checkbx;
// Select it
dummy.select();
// Copy its contents
document.execCommand("copy");
// Remove it as its not needed anymore
document.body.removeChild(dummy);
}
And its HTML call:
<button id="btn_test" type="button" onclick="getSelectedCheckboxes('ID_of_chkbxs_selected')">Copy</button>
For general purposes of copying any text to the clipboard, I wrote the following function:
function textToClipboard (text) {
var dummy = document.createElement("textarea");
document.body.appendChild(dummy);
dummy.value = text;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
}
The value of the parameter is inserted into value of a newly created <textarea>, which is then selected, its value is copied to the clipboard and then it gets removed from the document.
Very useful. I modified it to copy a JavaScript variable value to clipboard:
function copyToClipboard(val){
var dummy = document.createElement("input");
dummy.style.display = 'none';
document.body.appendChild(dummy);
dummy.setAttribute("id", "dummy_id");
document.getElementById("dummy_id").value=val;
dummy.select();
document.execCommand("copy");
document.body.removeChild(dummy);
}
When you need to copy a variable to the clipboard in the Chrome dev console, you can simply use the copy() command.
https://developers.google.com/web/tools/chrome-devtools/console/command-line-reference#copyobject
I managed to copy text to the clipboard (without showing any text boxes) by adding a hidden input element to body, i.e.:
function copy(txt){
var cb = document.getElementById("cb");
cb.value = txt;
cb.style.display='block';
cb.select();
document.execCommand('copy');
cb.style.display='none';
}
<button onclick="copy('Hello Clipboard!')"> copy </button>
<input id="cb" type="text" hidden>
Use Clipboard API
text = "HEllo World";
navigator.clipboard.writeText(text)
It works on Chrome 66+, Edge 79+, Firefox 63+ & doesn't work on I.E.
Read More About Clipboard API At MDN Docs
Nowadays there is a new(ish) API to do this directly. It works on modern browsers and on HTTPS (and localhost) only. Not supported by IE11.
IE11 has its own API.
And the workaround in the accepted answer can be used for unsecure hosts.
function copyToClipboard (text) {
if (navigator.clipboard) { // default: modern asynchronous API
return navigator.clipboard.writeText(text);
} else if (window.clipboardData && window.clipboardData.setData) { // for IE11
window.clipboardData.setData('Text', text);
return Promise.resolve();
} else {
// workaround: create dummy input
const input = h('input', { type: 'text' });
input.value = text;
document.body.append(input);
input.focus();
input.select();
document.execCommand('copy');
input.remove();
return Promise.resolve();
}
}
Note: it uses Hyperscript to create the input element (but should be easy to adapt)
There is no need to make the input invisible, as it is added and removed so fast. Also when hidden (even using some clever method) some browsers will detect it and prevent the copy operation.
At the time of writing, setting display:none on the element didn't work for me. Setting the element's width and height to 0 did not work either. So the element has to be at least 1px in width for this to work.
The following example worked in Chrome and Firefox:
const str = 'Copy me';
const el = document.createElement("input");
// Does not work:
// dummy.style.display = "none";
el.style.height = '0px';
// Does not work:
// el.style.width = '0px';
el.style.width = '1px';
document.body.appendChild(el);
el.value = str;
el.select();
document.execCommand("copy");
document.body.removeChild(el);
I'd like to add that I can see why the browsers are trying to prevent this hackish approach. It's better to openly show the content you are going copy into the user's browser. But sometimes there are design requirements, we can't change.
I just want to add, if someone wants to copy two different inputs to clipboard. I also used the technique of putting it to a variable then put the text of the variable from the two inputs into a text area.
Note: the code below is from a user asking how to copy multiple user inputs into clipboard. I just fixed it to work correctly. So expect some old style like the use of var instead of let or const. I also recommend to use addEventListener for the button.
function doCopy() {
try{
var unique = document.querySelectorAll('.unique');
var msg ="";
unique.forEach(function (unique) {
msg+=unique.value;
});
var temp =document.createElement("textarea");
var tempMsg = document.createTextNode(msg);
temp.appendChild(tempMsg);
document.body.appendChild(temp);
temp.select();
document.execCommand("copy");
document.body.removeChild(temp);
console.log("Success!")
}
catch(err) {
console.log("There was an error copying");
}
}
<input type="text" class="unique" size="9" value="SESA / D-ID:" readonly/>
<input type="text" class="unique" size="18" value="">
<button id="copybtn" onclick="doCopy()"> Copy to clipboard </button>
function CopyText(toCopy, message) {
var body = $(window.document.body);
var textarea = $('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
textarea.val(toCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = document.execCommand('copy');
if (!successful)
throw successful;
else
alert(message);
} catch (err) {
window.prompt("Copy to clipboard: Ctrl+C, Enter", toCopy);
}
textarea.remove();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<button type="button" onClick="CopyText('Hello World', 'Text copped!!')">Copy</button>
I've been trying to create an advanced text input where users can write hashtags.
The input is a div with contenteditable set true, and the hashtags should be child nodes as I'd allow users to put space inside the hashtags.
My problem is that on some browsers I can not set the focus on the hashtag's child node as the user types. On Chrome/Linux and Safari/OSX it seems to work well, but on Firefox and Chrome/OSX setting the focus don't seem to work. (I haven't got to Windows yet.)
var $elComposer = $('#composer');
var InsertTagPair = function (tagtype) {
var newTag = document.createElement (tagtype);
$(newTag).attr ('contenteditable', 'true');
$(newTag).attr ('class', 'tag');
$elComposer.off ('keypress');
if (window.getSelection) {
var selection = window.getSelection();
if (selection.getRangeAt && selection.rangeCount) {
var range = selection.getRangeAt (0);
range.deleteContents ();
range.insertNode (newTag);
range.selectNodeContents (newTag);
range.collapse (false);
selection.removeAllRanges ();
selection.addRange (range);
};
};
newTag.focus ();
return newTag;
};
var ComposerOnKeyPressed = function (event) {
if (event.charCode == 35) { // #
var contextTag = InsertTagPair ('span');
$elComposer.attr ('contenteditable', 'false');
return false;
};
return event;
};
$elComposer.on ('keypress', ComposerOnKeyPressed);
The above code is the essential part that's not working. See it here in action:
JSFiddle - http://jsfiddle.net/cja963ym/1/
To see a more complete version of the composer that makes more sense see this instead:
JSFiddle - http://jsfiddle.net/g_borgulya/ur6zk32s/15/
Symptom: on Firefox if you type in the editable div and press '#', you manually have to click it by mouse or move the focus with tab to be able to edit the hashtag, while on other platforms it gets the focus when I call newTag.focus() on the element.
I don't know how to move on, even how to debug this problem.
Adding newTag.focus() in the "#" handler made it work in Chrome and Firefox (Win) (it didn't before, but did on IE11, just wanted to let you know)
Fiddle fork : http://jsfiddle.net/ekxo4ra3/
Does that look OK for what you wanted ?