Copy div text content using javascript/jQuery - javascript

There are quite a few posts on this but after spending several hours trying to adapt the solutions that already exist, it's become clear to me that this is a little bit more complicated.
I'm attempting to create 'copy to clipboard' functionality so that our users can copy their serial number with a single click (I managed to achieve this functionality with 2 different solutions) but there's a major catch.
As the serial number is generated dynamically using a shortcode I cannot place it inside a HTML 'text'/'value' field, like so:
<input id="serial" value="[shortcode here]">
as this breaks the shortcode, so it has to be placed inside it's own div, which I have done like this:
<div id="serial">[shortcode here]</div>
This outputs the shortcode on the page with the direct parent ID of 'serial', so the JS I'm using should then select the text from the element ID - #serial.
Unfortunately it doesn't...
I've tried to adapt this method also with no luck:
From the Roll Your Own section: https://www.sitepoint.com/javascript-copy-to-clipboard/
This one was working with with plain text but not with the shortcode or custom div.
Can anyone provide me with a working clipboard solution as shown in the example above that won't break the shortcode?

document.getElementById("copyButton").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget"), "msg");
});
document.getElementById("copyButton2").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget2"), "msg");
});
document.getElementById("pasteTarget").addEventListener("mousedown", function() {
this.value = "";
});
function copyToClipboardMsg(elem, msgElem) {
var succeed = copyToClipboard(elem);
var msg;
if (!succeed) {
msg = "Copy not supported or blocked. Press Ctrl+c to copy."
} else {
msg = "Text copied to the clipboard."
}
if (typeof msgElem === "string") {
msgElem = document.getElementById(msgElem);
}
msgElem.innerHTML = msg;
setTimeout(function() {
msgElem.innerHTML = "";
}, 2000);
}
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.textContent;
}
// select the content
var currentFocus = document.activeElement;
target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
<input id="copyTarget" value="Some initial text"> <button id="copyButton">Copy</button><br><br>
<span id="copyTarget2">Some Other Text</span> <button id="copyButton2">Copy</button><br><br>
<input id="pasteTarget"> Click in this Field and hit Ctrl+V to see what is on clipboard<br><br>
<span id="msg"></span><br>
Would you please try above snippet?

Second #pruvik7373 answer
I think [shortcode] may contain some code which can translate into anything else so instead of using textContent use innerHTML it will make sure to copy everything as it is.
document.getElementById("copyButton").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget"), "msg");
});
document.getElementById("copyButton2").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("serial"), "msg");
});
document.getElementById("pasteTarget").addEventListener("mousedown", function() {
this.value = "";
});
function copyToClipboardMsg(elem, msgElem) {
var succeed = copyToClipboard(elem);
var msg;
if (!succeed) {
msg = "Copy not supported or blocked. Press Ctrl+c to copy."
} else {
msg = "Text copied to the clipboard."
}
if (typeof msgElem === "string") {
msgElem = document.getElementById(msgElem);
}
msgElem.innerHTML = msg;
setTimeout(function() {
msgElem.innerHTML = "";
}, 2000);
}
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.innerHTML;
}
// select the content
var currentFocus = document.activeElement;
target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
<input id="copyTarget" value="Some initial text"> <button id="copyButton">Copy</button><br><br>
<div id="serial"><div>[pw_map address="New York City"</div> enablescrollwheel="false" key="YOUR API KEY"]</div> <button id="copyButton2">Copy</button><br><br>
<input id="pasteTarget"> Click in this Field and hit Ctrl+V to see what is on clipboard<br><br>
<span id="msg"></span><br>

Below code did the trick for me.
Note: Below snippet might not work as window object is not accessible.
$(function() {
$('#serial').click(function() {
window.clipboardData.setData('text', $(this).text());
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="serial">[shortcode here]</div>

You can do it like:
<div id="serial">[shortcode here]</div>
<input id="some_other_id" type="text" />
And the javascript code:
//first get text from your div and put it inside input field
//then apply code to copy that text from input field
$(document).ready(function(){
var text = $("#serial").text();
$("#some_other_id").val(text);
//your code for copying text from input field goes here
});

Related

JavaScript undo-buffer cleared after manipulativ textarea

In my Web App I have have an TextEditor, which can be manipulated by some buttons.
For example:
<textarea id="textareaId"></textarea>
<button onclick="add()">Click me</button>
<script>
add() {
document.getElementById('textareaId').value += 'some content';
}
</script>
The issue is, that the user cant undo this (for example by shortcut ctrl + z).
It looks like that the the undo-buffor for the textarea gets cleared by that. Is there any way to do the changes without losing the option of undoing?
You can cache the textarea's value using an array as stack:
var valuesStack = [];
var textarea = document.getElementById('textareaId');
textarea.addEventListener('keydown', function(event) {
if (event.ctrlKey && event.key === 'z') restore();
});
function cache() {
valuesStack.push(textarea.value);
}
function add() {
cache();
textarea.value += 'some content';
}
function restore() {
var value = valuesStack.pop();
if (value === undefined) textarea.value = "";
else textarea.value = value;
}
<textarea id="textareaId" onchange="cache()"></textarea>
<button onclick="add()">Click me</button>

Have any selection on page to be auto copied to clipboard [duplicate]

This question already has answers here:
How do I copy to the clipboard in JavaScript?
(27 answers)
Closed 4 years ago.
I need to copy any selection from a webpage to the clipboard, it can be on a div, text input, password input, span, etc.
I have the following function that does this for me, but the challenge is have the returned value from the function to be set on the clipboard
const getSelectionText = () => {
let text = "";
let activeDomElement = document.activeElement;
let activeDomElementTagName = activeDomElement ? activeDomElement.tagName.toLowerCase() : null;
if (
(activeDomElementTagName === 'textarea') || (activeDomElementTagName === 'input' &&
/^(?:text|search|password|tel|url)$/i.test(activeDomElement.type)) &&
(typeof activeDomElement.selectionStart === "number")
) {
text = activeDomElement.value.slice(activeDomElement.selectionStart, activeDomElement.selectionEnd);
} else if (window.getSelection) {
text = window.getSelection().toString();
}
return text;
}
Any idea, or links to resources would be helpful, thanks
Have a look at the example from w3schools.It is a basic example.
https://www.w3schools.com/howto/howto_js_copy_clipboard.asp
You can also use this -
Just call myFunction with your returned text as an argument.
function myFunction(arg) {
var x = document.createElement("INPUT");
x.setAttribute("type", "text");
x.setAttribute("value",arg);
x.select();
document.execCommand("Copy");
alert("Copied the text: " + x.value);
document.removeChild(x);
}
document.execCommand("copy") this will copied all your selected text !
function copySelectionText(){
var copysuccess // var to check whether execCommand successfully executed
try{
copysuccess = document.execCommand("copy") // run command to copy selected text to clipboard
} catch(e){
copysuccess = false
}
return copysuccess
}
document.body.addEventListener('mouseup', function(e){
var copysuccess = copySelectionText() // copy user selected text to clipboard
if(copysuccess) {
document.getElementById('paste').style.display = "block";
}
}, false)
<h3>Late</h3>
<p>dsfjdslkfjdslkfjdsklfj</p>
<code>Cdoing is godo for a wite </code>
<textarea placeholder="Paste Here with [Ctrl + V ]" style="display:none;" id="paste"> </textarea>

How to copy input of type date, if there is no selection being created?

I have a simple input:
<input type="date" class="self-select" value="1980-05-04">
<input type="text" class="self-select" value="my birthday">
And I have a listener for all such inputs:
$(document).on('focus', '.self-select', function(){
$(this).select();
});
The idea is that when user clicks to the input field, its' contents are selected, so he needs just ctrl+c to copy.
But this doesnt work with type="date" in Chrome. There is no selection and basically no way to copy date value from an input field.
Here is the fiddle:
https://fiddle.jshell.net/Dmatafonov/s8r9dt6j/
I managed to write some kind of a "hacky" walk around...
The trick is to copy to clipboard (using this other great SO answer) while the date input type is temporarely setted to "text" on CTRL+C keydown...
It's not perfect since only a segment of the date is selected on focus...
And some users will scratch their head a little until they notice that the whole date is copied anyway.
I have no solution for this.
What's important is that copying to clipboard is works.
Try the snippet!
// Your on focus -> select event handler
$(document).on('focus', '.self-select', function(){
$(this).select();
});
// An on keydown event handler to copy to clipboard when [ctrl]+[C] is pressed
// Exclusively for the "date" inputs.
$(document).on('keydown', 'input[type="date"]', function(e){
if( e.which == 67 && e.ctrlKey ){
var copiedDate = $(this).val();
//console.log( copiedDate );
// First, get the value and fix the date format from YYYY-MM-DD to MM/DD/YYYY
var tempDate = copiedDate.split("-");
var year = tempDate.shift();
//console.log( year );
tempDate.push(year);
var fixedDate = tempDate.join("/");
console.log( fixedDate );
// Then temporarly change the input type from "date" to "text"
$(this).attr("type","text").val(fixedDate);
// Use the copy to clipboard function
$(this).select();
copyToClipboard($(this));
// Set the input type back to "date" a small delay later
var that=$(this);
setTimeout(function(){
that.attr("type","date").val(copiedDate); // And restore original value
},20)
}
});
// ---------------------------------
// A nice JavaScript "copy to clipboard" function found here : https://stackoverflow.com/a/22581382/2159528
// ---------------------------------
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.textContent;
}
// select the content
var currentFocus = document.activeElement;
//target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
/* Textarea sizing for this snippet */
#pasteIt{
width:316px;
height:150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="date" class="self-select" value="1980-05-04">
<input type="text" class="self-select" value="my birthday">
<br>
<br>
<textarea id="pasteIt" placeholder="Paste here to test your clipboard."></textarea>
I ran into this same issue but also needed to be able to paste to another date field. I did something similar to the above but made it obvious to the user that the full date is being copied.
My use case also included the need to copy from and paste to datetime-local type fields.
https://jsfiddle.net/h444uL45/23/
var control_pressed = false;
function changeInputType(oldObject, oType) {
var newObject = document.createElement("input");
newObject.type = oType;
if(oldObject.size) {newObject.size = oldObject.size;}
if(oldObject.value) {newObject.value = oldObject.value;}
if(oldObject.name) {newObject.name = oldObject.name;}
if(oldObject.id) {newObject.id = oldObject.id;}
if(oldObject.className) {newObject.className = oldObject.className;}
oldObject.parentNode.replaceChild(newObject,oldObject);
newObject.select();
return newObject;
}
function swapToText(date_type) {
$('input[type="'+date_type+'"]').on("keydown", function(event) {
if ((event.keyCode == 17) && (control_pressed != true)) {
$(this).addClass("revert_date_to_text");
changeInputType(this, "text");
swapToDate(date_type);
control_pressed = true;
}
})
}
function swapToDate(date_type) {
$(".revert_date_to_text").on("keyup", function(event) {
if ((event.keyCode == 17) && (control_pressed != false)) {
$(this).removeClass("revert_date_to_text");
if (date_type == 'datetime-local') {
$(this).val($.format.date($(this).val().replace(/\//g,"-").replace("T"," ")+':00.000', "yyyy-MM-ddTHH:mm"));
} else {
$(this).val($.format.date($(this).val().replace(/\//g,"-"), "yyyy-MM-dd"));
}
changeInputType(this, date_type);
swapToText(date_type);
control_pressed = false;
}
})
}
$(function() {
$.getScript('https://cdnjs.cloudflare.com/ajax/libs/jquery-dateFormat/1.0/jquery.dateFormat.min.js');
swapToText('date');
swapToText('datetime-local');
});

Copy to clipboard buttons

I want to create "copy to clipboard" buttons to work on our sharepoint. They should be placed in a few different places, and what I need to copy is some text from from a specific field on the page (ex. a list of emails).
I know, I can just select the text and copy it, but we do it quite often, so having a button that automatically copies the text to the clipboard would be very useful.
I did manage to create one in a Script Editor, where I pasted the whole code below (which I found on the internet)
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>//<![CDATA[
window.onload=function(){
document.getElementById("copyButton").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget"), "msg");
});
document.getElementById("copyButton2").addEventListener("click", function() {
copyToClipboardMsg(document.getElementById("copyTarget2"), "msg");
});
document.getElementById("pasteTarget").addEventListener("mousedown", function() {
this.value = "";
});
function copyToClipboardMsg(elem, msgElem) {
var succeed = copyToClipboard(elem);
var msg;
if (!succeed) {
msg = "Copy not supported or blocked. Press Ctrl+c to copy."
} else {
msg = "Text copied to the clipboard."
}
if (typeof msgElem === "string") {
msgElem = document.getElementById(msgElem);
}
msgElem.innerHTML = msg;
setTimeout(function() {
msgElem.innerHTML = "";
}, 2000);
}
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.textContent;
}
// select the content
var currentFocus = document.activeElement;
target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
}//]]>
</script>
</head>
<body>
<input id="copyTarget" value="Some initial text"> <button id="copyButton">Copy</button><br><br>
<span id="copyTarget2">Some Other Text</span> <button id="copyButton2">Copy</button><br><br>
<input id="pasteTarget"> Click in this Field and hit Ctrl+V to see what is on clipboard<br><br>
<span id="msg"></span><br>
</body>
</html>
But we have main problems with it:
1) it reloads the page every time we click the "copy" button
2) it is not very elegant and friendly, when we think about updating our documents
I would be very grateful for any hints you may have for me, on how to make it work better.
This project may help: clipboardjs

Bug w IE8 Using Javascript to Insert Text at Caret

Focusing on IE, I have a textbox (single line <input/>) for which I need to insert text where the caret/cursor is. The text within a div is inserted at the caret position when the div is double clicked.
Bug: Text is inserted into the textbox, but at the beginning of the string in the textbox and not where the caret position is.
The following code works fine using the multiline input (no bug), the bug only occurs with the single line input.
Here is the simple Javascript for IE (other browser support has been removed for simplicity):
$.fn.insertAtCaret = function (tagName) {
return this.each(function () {
if (this.selectionStart || this.selectionStart == '0') {
//MOZILLA support
} else if (document.selection) {
//IE support
this.focus();
sel = document.selection.createRange();
sel.text = tagName;
} else {
//ELSE
}
});
};
Just so you have everything in front of you, here is the JQuery that calls $.fn.insertAtCaret:
$("#Subject").mousedown(function () { $("#InsertAtCaretFor").val("Subject"); });
$("#Subject").bind('click, focus, keyup', function () { $("#InsertAtCaretFor").val("Subject"); });
$("#Comment").mousedown(function () { $("#InsertAtCaretFor").val("Comment"); });
$("#Comment").bind('click, focus, keyup', function () { $("#InsertAtCaretFor").val("Comment"); });
$(".tag").dblclick(function () {
if ($("#InsertAtCaretFor").val() == "Comment") $("#Comment").insertAtCaret($(this).text());
if ($("#InsertAtCaretFor").val() == "Subject") $("#Subject").insertAtCaret($(this).text());
});
As you can see, when one of the two <input/>s are clicked, focused, etc., a hidden field (ID="InsertAtCaretFor") value is set to either "Subject" or "Comment". When the tag is double-clicked, its .text() is inserted at the caret position within the <input/> specified by the hidden field's value.
Here are the fields:
<%=Html.Hidden("InsertAtCaretFor") %>
<div class="form_row">
<label for="Subject" class="forField">
Subject:</label>
<%= Html.TextBox("Subject", "", new Dictionary<string, object> { { "class", "required no-auto-validation" }, { "style", "width:170px;" }, { "maxlength", "200" } })%>
</div>
<div class="form_row">
<label for="Comment" class="forField">
Comment:</label>
<%= Html.TextArea("Comment", new Dictionary<string,object> { {"rows","10"}, {"cols","50"}, { "class", "required"} })%>
</div>
Finally, here is an image so you can visually understand what I'm doing:
http://www.danielmckenzie.net/ie8bug.png
I'm using a different insertAtCaret code I found from googling around. Works on single inputs and textareas just fine.
$.fn.extend({
insertAtCaret: function (myValue) {
var $input;
if (typeof this[0].name != 'undefined')
$input = this[0];
else
$input = this;
if ($.browser.msie) {
$input.focus();
sel = document.selection.createRange();
sel.text = myValue;
$input.focus();
}
else if ($.browser.mozilla || $.browser.webkit) {
var startPos = $input.selectionStart;
var endPos = $input.selectionEnd;
var scrollTop = $input.scrollTop;
$input.value = $input.value.substring(0, startPos) + myValue + $input.value.substring(endPos, $input.value.length);
$input.focus();
$input.selectionStart = startPos + myValue.length;
$input.selectionEnd = startPos + myValue.length;
$input.scrollTop = scrollTop;
} else {
$input.value += myValue;
$input.focus();
}
}
});
After looking at your js code I'd change:
$(".tag").dblclick(function () {
if ($("#InsertAtCaretFor").val() == "Comment") $("#Comment").insertAtCaret($(this).text());
if ($("#InsertAtCaretFor").val() == "Subject") $("#Subject").insertAtCaret($(this).text());
});
To the following:
$(".tag").dblclick(function () {
if ($("#InsertAtCaretFor").val() == "Comment") {
$("#Comment").insertAtCaret($(this).text());
}
if ($("#InsertAtCaretFor").val() == "Subject") {
$("#Subject").insertAtCaret($(this).text());
}
});
Those two inline if statements with no ending curly brace look dangerous!
I've come the same problem myself in IE8. It seems that for INPUT type="text", it does not fill in selectionStart and selectionEnd. IE9 does, however.

Categories