I have the following Page
When I click "Click Here To Copy", it calls document.execCommand("copy") to copy some text to the clipboard and it works.
However, when I hit the button "Open popup", it opens a div in the same page (no iframe), then when clicking on "Click Here To Copy", document.execCommand("copy") doesn't work.
Steps to reproduce :
document.execCommand("copy") works :
However if I open the popup, document.execCommand("copy") doesn't work
Does anyone know the reason for that please ?
Thanks
cheers,
Here is my entire code :
function CopyToClipBoard(d){
var c=document.createElement("textarea");
c.innerText=d;
document.body.appendChild(c);
c.select();
document.execCommand("copy");
document.body.removeChild(c);
}
<div onclick="CopyToClipBoard('text to be copied')">Click Here To copy</div>
Here is the cause of the problem :
The following code doesn't seem to work when there is an overlay of a document. For example when the caller is on a div with higher z-index or something... I'm not sure on what exactly causes this code to fail. But it seems related to overlayers, focusable elements or something... The fact is that, when the body of the document is hidden, the created text area is unable to focus and it doesn't work.
function CopyToClipBoard(d){
var c=document.createElement("textarea");
c.innerText=d;
document.body.appendChild(c);
c.select();
document.execCommand("copy");
document.body.removeChild(c);
}
<div onclick="CopyToClipBoard('text to be copied')">Click Here To copy</div>
Solution :
Instead of adding the text area to the body of the document, it can be added to the caller itself... Hence it will always be in the foreground. This assumes the text to copy is short such that the execution is fast enough for the user not to notice the creation and the removal of the text area...
function CopyToClipBoard(item, d){
var c=document.createElement("textarea");
c.value=d;
c.style.maxWidth = '0px';
c.style.maxHeight = '0px';
item.appendChild(c);
c.focus();
c.select();
document.execCommand("copy");
item.removeChild(c);
}
<div onclick="CopyToClipBoard(this,'text to be copied')">Click Here To copy</div>
Here is my working example of copyTextToClipboard function. Please try to add textArea.focus call.
const fallbackCopyTextToClipboard = text => {
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
}
const copyTextToClipboard = text => {
if (navigator.clipboard) {
return navigator.clipboard.writeText(text);
}
return new Promise((resolve, reject) => {
fallbackCopyTextToClipboard(text);
resolve();
});
};
Related
I'm trying to write in javascript and I want to understand why it doesn't work?
sample order code that I want to copy: 593004485164756431
when I copy to clipboard : 593004485164756500
I checked for an error in the console, there was no error, does the browser affect the error? i use firefox
this my code
function copyToClipboard(text) {
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text)
} else {
// text area method
let textArea = document.createElement("textarea")
textArea.value = text
// make the textarea out of viewport
textArea.style.position = "fixed"
textArea.style.left = "-999999px"
textArea.style.top = "-999999px"
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
return new Promise((res, rej) => {
// here the magic happens
document.execCommand('copy') ? res() : rej()
textArea.remove()
})
}
}
on button
<img onclick="copyToClipboard({{ $result['code_order'] }})" style="width:20px;cursor:pointer;" src="{{ url('img/copy-solid.svg') }}"/>
I hope I can find the solution to this problem. Thank you
I have a form input in my vue app that is used to create a password. I've successfully added a button to show/hide the password. I want to add a copy to clipboard function to let the user copy and paste the password in a safe place, but it's not working. What am I doing wrong here?
Template code
<small class="font-wieght-bold text-success mb-0" v-if="isCopied">Copied</small>
<div class="input-group">
<input :type="showPassword ? 'text' : 'password'" class="form-control" ref="password" required v-model="password">
<div class="input-group-append">
<button class="btn btn-secondary" #click.prevent="copyToClipboard()"><i class="fas fa-clipboard"></i></button>
</div>
</div>
Vue code
viewPassword() {
this.showPassword = !this.showPassword;
},
copyToClipboard() {
this.$refs.password.select();
document.execCommand('copy');
this.isCopied = true;
setTimeout( () => { this.isCopied = !this.isCopied },3000);
}
You need to copy the contents of your v-model, not the input itself.
You can use a function like this to copy from a variable.
It makes a new text box, uses the copy command, then immediately removes it. All in a single event loop so it never even renders.
const copyTextToClipboard = (text) => {
const textArea = document.createElement('textarea')
//
// *** This styling is an extra step which is likely not required. ***
//
// Why is it here? To ensure:
// 1. the element is able to have focus and selection.
// 2. if element was to flash render it has minimal visual impact.
// 3. less flakyness with selection and copying which **might** occur if
// the textarea element is not visible.
//
// The likelihood is the element won't even render, not even a flash,
// so some of these are just precautions. However in IE the element
// is visible whilst the popup box asking the user for permission for
// the web page to copy to the clipboard.
//
// Place in top-left corner of screen regardless of scroll position.
textArea.style.position = 'fixed'
textArea.style.top = '0'
textArea.style.left = '0'
// Ensure it has a small width and height. Setting to 1px / 1em
// doesn't work as this gives a negative w/h on some browsers.
textArea.style.width = '2em'
textArea.style.height = '2em'
// We don't need padding, reducing the size if it does flash render.
textArea.style.padding = 0
// Clean up any borders.
textArea.style.border = 'none'
textArea.style.outline = 'none'
textArea.style.boxShadow = 'none'
// Avoid flash of white box if rendered for any reason.
textArea.style.background = 'transparent'
textArea.value = text
document.body.appendChild(textArea)
textArea.select()
try {
const successful = document.execCommand('copy')
const msg = successful ? 'successful' : 'unsuccessful'
console.log('Copying text command was ' + msg)
} catch (err) {
console.log('Oops, unable to copy')
}
document.body.removeChild(textArea)
}
As an alternative solution to the one of the accepted answer I've tried with the clipboard API. In particular I've used the clipboard.writeText() method to copy the v-modeled data directly into the clipboard and it worked also with <input type="password">
Here is the refactored code of copyToClipboard() method:
copyToClipboard() {
navigator.clipboard.writeText(this.password);
this.isCopied = true;
setTimeout( () => { this.isCopied = !this.isCopied },3000);
}
I have a textarea that can be draged around in which text should still be selectable by draging over it. In order to distinguish a "over text drag" from a "move drag" I have to know weather the point where the user started its drag (i.e. mousedown position) was white space or text.
The only thing I can come up with to figure this out is calculating using character width and line height, which I would like to avoid.
Not really sure what you're asking, but here's my attempt to translate the insanity into working code:
let doc, htm, bod, I; // for use on other loads
addEventListener('load', ()=>{
doc = document; htm = doc.documentElement; bod = doc.body; I = id=>doc.getElementById(id);
// magic under here
const test = I('test');
function whiteStart(string){
if(string.match(/^\s+/)){
return true;
}
return false;
}
test.oncopy = test.ondragstart = function(){
let s = getSelection().toString();
if(whiteStart(s)){
console.log('"'+s+'" starts with one or more white spaces');
}
else{
console.log('"'+s+'" starts without a white space');
}
}
}); // end load
<div id='test'>I'm just going to put some text in here so we can run a very basic test. I hope this helps!</div>
I have a textarea on a form that is populated with text from a database query ready for someone to edit.
I would like the textarea to show the whole content without the need to scroll, but don't want to put a large textarea when there is only a small amount of text.
Text can be from 5 to 300 characters.
I have seen a solution to this type of issue but only where the textarea grows onkeyup as shown below.
<script>
function textAreaAdjust(o) {
o.style.height = "1px";
o.style.height = (25+o.scrollHeight)+"px";
}
</script>
<textarea onkeyup="textAreaAdjust(this)" style="overflow:hidden"></textarea>
Firstly, don't use onkeyup. It's not suitable for detecting text input.
I use the following code to resize a textarea to constantly resize a textarea element to fit the content:
var tarea = document.getElementsByTagName("textarea")[0];
tarea.oninput = function () {
tarea.style.height = tarea.scrollHeight + "px";
}
However, oninput isn't supported in older versions of IE, so you'll need to add onpropertychange if you need it to work in IE 8 and lower:
var tarea = document.getElementsByTagName("textarea")[0];
tarea.oninput = tarea.onpropertychange = function (evt) {
evt = evt || window.evt;
if (evt.type == "propertychange" && evt.propertyName != "value")
return;
tarea.style.height = tarea.scrollHeight + "px";
}
Working Demo: http://jsfiddle.net/D5e8t/
You can call the method on page load.
Copy the content of textarea to a invisible div, with the same width, and styles that affect size (font-size, line-height, padding, etc.). Measure the height of said div, and set your textarea to the same height.
Just little modifications to the above code will make textarea autosizable.
Just perfiorm the below steps
1) Add id to your text area
<textarea onkeyup="textAreaAdjust(this)" id="txt" runat="server" style="overflow:hidden"></textarea>
2) Before a closing of bode tag add the javascript code to call the testAreaAdjust block
<script type="text/javascript">
textAreaAdjust(document.getElementById('txt'));
</script>
This will autosize the textbox.
Hope this will help you
I have a contentEditable Div and I want remove any formatting especially for copy and paste text.
You can add a listener to the "paste" event and reformat the clipboard contents. Like so:
let editableDiv = document.querySelector('div[contenteditable="true"]');
editableDiv.addEventListener("paste", function(e) {
e.preventDefault();
var text = e.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
});
Here another example for all containers in the body:
let allEditableDivs = document.querySelectorAll('div[contenteditable="true"]');
[].forEach.call(allEditableDivs, function (el) {
el.addEventListener('paste', function(e) {
e.preventDefault();
var text = e.clipboardData.getData("text/plain");
document.execCommand("insertHTML", false, text);
}, false);
}
Saludos.
Have you tried using innerText?
ADDED:
If you want to strip markup from content pasted into the editable div, try the old hack of creating a temporary div -- see example below.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Strip editable div markup</title>
<script type="text/javascript">
function strip(html) {
var tempDiv = document.createElement("DIV");
tempDiv.innerHTML = html;
return tempDiv.innerText;
}
</script>
</head>
<body>
<div id="editableDiv" contentEditable="true"></div>
<input type="button" value="press" onclick="alert(strip(document.getElementById('editableDiv').innerText));" />
</body>
</html>
Was looking for answer to this for ages and ended up writing my own.
I hope this helps others. At the time of writing this it appears to work in ie9, latest chrome and firefox.
<div contenteditable="true" onpaste="OnPaste_StripFormatting(this, event);" />
<script type="text/javascript">
var _onPaste_StripFormatting_IEPaste = false;
function OnPaste_StripFormatting(elem, e) {
if (e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData) {
e.preventDefault();
var text = e.originalEvent.clipboardData.getData('text/plain');
window.document.execCommand('insertText', false, text);
}
else if (e.clipboardData && e.clipboardData.getData) {
e.preventDefault();
var text = e.clipboardData.getData('text/plain');
window.document.execCommand('insertText', false, text);
}
else if (window.clipboardData && window.clipboardData.getData) {
// Stop stack overflow
if (!_onPaste_StripFormatting_IEPaste) {
_onPaste_StripFormatting_IEPaste = true;
e.preventDefault();
window.document.execCommand('ms-pasteTextOnly', false);
}
_onPaste_StripFormatting_IEPaste = false;
}
}
</script>
Try <div id="editableDiv" contentEditable="plaintext-only"></div>
I know it's been a while, but I had the same problem. On my case, it's a GWT application to make it even worse.
Anyway, resolved the problem with:
var clearText = event.clipboardData.getData('text/plain');
document.execCommand('inserttext', false, clearText);
See: https://jsfiddle.net/erikwoods/Ee3yC/
I preferred "inserttext" command instead of "insertHTML", because the documentation says it's exactly to insert plain text, so seems more suitable.
See https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
With Jquery you can use .text() method, so, when blur for example you can replace the content with the text content
$("#element").blur(function(e) {
$(this).html($(this).text());
});
You can't access the system clipboard so you'll need a hack. See this question: JavaScript get clipboard data on paste event (Cross browser)
I'd like to add my solution to this issue:
ContentEditableElement.addEventListener('input', function(ev) {
if(ev.target.innerHTML != ev.target.textContent) {
// determine position of the text caret
var caretPos = 0,
sel, range;
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
var children = ev.target.childNodes;
var keepLooping = true;
for(let i = 0; keepLooping; i++) {
if(children[i] == range.commonAncestorContainer || children[i] == range.commonAncestorContainer.parentNode) {
caretPos += range.endOffset;
keepLooping = false;
} else {
caretPos += children[i].textContent.length;
}
}
// set the element's innerHTML to its textContent
ev.target.innerHTML = ev.target.textContent;
// put the caret where it was before
range = document.createRange();
range.setStart(ev.target.childNodes[0], caretPos);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
});
(this isn't compatible with older versions of IE)
Just for my later life. ;)
styles.css
/* Not easy to look exactly like input field: */
/* https://stackoverflow.com/a/8957518/1707015 */
.contenteditable_div {
/* box-shadow: 1px 1px 1px 0 lightgray inset; */
background-color:#dddddd;
overflow-wrap:break-word;
padding:3px;
}
index.html
<!-- Firefox doesn't support contenteditable="plaintext-only" yet! -->
<div class="contenteditable_div" contenteditable="true" id="blubbi">abc</div>
script.js
// Optional: Copy font from other input field:
// $('#blubbi').css('font', $('#blubbi_input_field').css('font'));
$('.contenteditable_div').on('input', function(){
// problems with setting cursor to beginning of div!
// this.innerHTML = this.innerText;
$(this).text($(this).text());
});
Keep in mind that this solution doesn't support or care about line breaks.
And keep in mind that setting the text like this will set the cursor to the beginning of your contenteditable div - while you are typing. Still a good solution if you need it only for copy & paste. Please write a comment if you have an easy solution for this "reverse typing problem" (under 10 lines of code please). ;)
Tested on Firefox 89, Chrome 90 and Safari 14.