I'm trying to copy a parameter string into my clipboard using native JS. This works fine so far, however I have a small cosmetic problem, when running my snippet in IE 7.
My code:
function copyStringToClipboard (str) {
// Create new element
var el = document.createElement('input');
el.setAttribute("display", "none");
el.setAttribute("type", "text");
el.value = str;
el.setAttribute('readonly', '');
document.body.appendChild(el);
el.select();
// Copy text to clipboard
document.execCommand('copy');
// Remove temporary element
document.body.removeChild(el);
}
As I mentioned above, this does work in the tested browsers. However, it creates a visible text-input field (line 3). I tried using el.style = {position: 'absolute', left: '-9999px'};, but Internet Explorer yields:
Not implemented
I thought about creating an input type="hidden", but it seems like this hidden field is not selectable - which makes sense. Needlessly to say, that this action triggers onClick(), so indeed with an user-action.
Ideas on how to solve this?
Instead of using el.setAttribute("display", "none");, You should change that line to:
el.style.display = "none";
Why this works?
Setting the attribute display none does not affect the style. It should be added as inline style or in the css to hide the input box.
Related
I am using a mouseup event to trigger a function which highlights text and surrounds the highlighted text with a span (function from stack overflow):
function highlightText(e) {
var t = window.getSelection().toString();
if (t) {
$("#mySpan").remove();
var range = window.getSelection().getRangeAt(0);
newNode = document.createElement("span");
newNode.id = 'mySpan';
range.surroundContents(newNode);
}
}
The main problem I am encountering is that as long as surroundContents is included, the text remains highlighted only about 20% of the highlight attempts (otherwise highlighting disappears immediately). I tried adding a setTimeout, not calling surroundContent for 1s. I also tried removing the remove() statement, but still no good.
Any ideas on why this is happening?
I was facing the same problem with Chromium on Android. In some specific cases, the call of range.surroundContents(newNode) would cause a very weird behaviour of page reload and so on. After checking the documentation of the function:
This method is nearly equivalent to
newNode.appendChild(range.extractContents());
range.insertNode(newNode). After surrounding, the boundary points of
the range include newNode.
So the obvious thing was to apply another way highlight the text. I found mark.js library which did exactly what I wanted without that annoying side effect. (Here's a JSFiddle sample that shows how it's used to highlight just selection). The difference is that library was not using range.surroundContents(newNode) nor newNode.appendChild but rather node.replaceChild.
Based on that, here's the solution to the problem I was having and I think it applies to your case as well.
function surroundRangeWithSpan(range) {
var span = document.createElement('span');
// The text is within the same node (no other html elements inside of it)
if (range.startContainer.isEqualNode(range.endContainer) && range.startContainer.childNodes.length == 0) {
// Here you customise your <span> element
customSurroundContents(range, span);
} else {
// Here you have to break the selection down
}
return span;
}
function customSurroundContents(range, span) {
var node = range.commonAncestorContainer;
var startNode = node.splitText(range.startOffset);
var ret = startNode.splitText(range.toString().length);
span.textContent = startNode.textContent;
startNode.parentNode.replaceChild(span, startNode);
}
And you pass window.getSelection().getRangeAt(0) to the function.
The likely cause of the failure is the selected text encompasses only the beginning or the ending of a non-text node, and not both of them.
So if were to run that code only selecting "This is Bo" in the following it will fail (and throw an exception) because it doesn't also capture the closing tag in the selection:
This is <em>bold</em>
So ending up with:
This is <em>bo
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents
I am trying to change the text of a Label using javascript like this in an aspx page
document.getElementById('DetailSection_EssLabel1').Text = "Revised Date";
But when I am in the debugging mode on IE by using F12 button, this is what I see for the field,
<SPAN class=FormFieldHeader id=DetailSection_EssLabel1 Text="Revised Date">Assigned Completion Date</SPAN>
Though the text is changed to Revised Date, it is still showing Assigned Completion Date in the front end. Can someone tell me what I am missing. Thanks
If you want to set a label's text, you'd better use textContent property, like this:
document.getElementById('DetailSection_EssLabel1').textContent = "Revised Date";
innerText is not a standard property and you'll definitely get an issue in FireFox
Neither innerText nor textContent are cross-browser compatible if you include IE 8 and older.
Using the jQuery text method is typically the easy button.
if jQuery is not an option, the most compatible way with pure DOM is to use text nodes, for example:
var outputDiv = document.getElementById('DetailSection_EssLabel1');
var childNodes = outputDiv.childNodes;
// nodeType == 3 is a text node
if (!(childNodes.length == 1 && childNodes[0].nodeType == 3)) {
outputDiv.innerHTML = ''; // one way to clear any existing content
outputDiv.appendChild(document.createTextNode(''));
}
outputDiv.childNodes[0].nodeValue = 'Revised Text';
Fiddle: https://jsfiddle.net/4m0wpjdo/1/
EDIT: I also wanted to mention that using innerHTML to inject text is really not a good idea. It's all too easy to forget to escape special characters when using this approach. This opens you up to incorrect display of the text at best and XSS attacks at worst (if user-supplied text is included).
Use innertext
document.getElementById('DetailSection_EssLabel1').innerText="Revised Date";
Native Javascript objects do not have a text property, but they do have innerHTML and innerText properties. To change the text of an element, you can use either:
document.getElementById('DetailSection_EssLabel1').innerHTML = "Revised Date";.
or document.getElementById('DetailSection_EssLabel1').innerText = "Revised Date";.
That's it :) I have a div with the id #toCopy, and a button with the id #copy.
What's the best way to copy #toCopy content to clipboard when pressing #copy?
You can copy to clipboard almost in any browser from input elements only (elements that has .value property), but you can't from elements like <div>, <p>, <span>... (elements that has .innerHTML property).
But I use this trick to do so:
Create a temporary input element, say <textarea>
Copy innerHTML from <div> to the newly created <textarea>
Copy .value of <textarea> to clipboard
Remove the temporary <textarea> element we just created
function CopyToClipboard (containerid) {
// Create a new textarea element and give it id='temp_element'
const textarea = document.createElement('textarea')
textarea.id = 'temp_element'
// Optional step to make less noise on the page, if any!
textarea.style.height = 0
// Now append it to your page somewhere, I chose <body>
document.body.appendChild(textarea)
// Give our textarea a value of whatever inside the div of id=containerid
textarea.value = document.getElementById(containerid).innerText
// Now copy whatever inside the textarea to clipboard
const selector = document.querySelector('#temp_element')
selector.select()
document.execCommand('copy')
// Remove the textarea
document.body.removeChild(textarea)
}
<div id="to-copy">
This text will be copied to your clipboard when you click the button!
</div>
<button onClick="CopyToClipboard('to-copy')">Copy</button>
The same without id:
function copyClipboard(el, win){
var textarea,
parent;
if(!win || (win !== win.self) || (win !== win.window))
win = window;
textarea = document.createElement('textarea');
textarea.style.height = 0;
if(el.parentElement)
parent = el.parentElement;
else
parent = win.document;
parent.appendChild(textarea);
textarea.value = el.innerText;
textarea.select();
win.document.execCommand('copy');
parent.removeChild(textarea);
}
I didn't tested for different windows (iframes) though!
UPDATED ANSWER
Javascript was restricted from using the clipboard, early on.
but nowadays it supports copy/paste commands.
See documentation of mozilla and caniuse.com.
document.execCommand('paste')
make sure that you support browsers that don't.
https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
http://caniuse.com/#search=command
Javascript is not allowed to use the clipboard, but other plugins like flash do have access.
How do I copy to the clipboard in JavaScript?
I'm trying to make a page that has some editabable fields, but I only want them to display as input boxes once the user clicks on them (the rest of the time showing as plain text). Is there a simple way to do this in Javascript?
Introduction
Fairly simple, yes. I can think of two basic approaches:
Using the contenteditable attribute
Using an input you add on-the-fly
Handy references for both of the below:
DOM2 Core
DOM2 HTML
DOM3 Core
HTML5 spec - "user interaction" section
Using the contenteditable attribute
The contentEditable attribute (W3C, MDC, MSDN) can be "true" indicating that the element can be edited directly. This has the advantage of not requiring any JavaScript at all (live example):
<p id="container">The <span contenteditable="true">colored items</span> in this paragraph
are <span contenteditable="true">editable</span>.</p>
Lest you think this is some l33t new thing, IE has supported it since IE 5.5 and other major browsers for very nearly that long. (In fact, this was one of many Microsoft innovations from the IE5.5 / IE6 timeframe; they also gave us innerHTML and Ajax.)
If you want to grab the (edited) content, you just grab innerHTML from the elements you've made editable. Here's an example of some JavaScript that will flag up when contenteditable spans blur (live copy):
var spans = document.getElementsByTagName("span"),
index,
span;
for (index = 0; index < spans.length; ++index) {
span = spans[index];
if (span.contentEditable) {
span.onblur = function() {
var text = this.innerHTML;
text = text.replace(/&/g, "&").replace(/</g, "<");
console.log("Content committed, span " +
(this.id || "anonymous") +
": '" +
text + "'");
};
}
}
#container span {
background-color: #ff6;
}
<p id="container">The <span id="span1" contenteditable="true">colored items</span> in this paragraph
are <span contenteditable="true">editable</span>.</p>
Using an input you add on-the-fly
You need to get a reference to the element that you're using for display (a span, perhaps) and then hook its click event (or hook the click event on a parent of the desired element(s)). In the click event, hide the span and insert a input[type=text] alongside it.
Here's a very simple example of using an input:
window.onload = function() {
document.getElementById('container').onclick = function(event) {
var span, input, text;
// Get the event (handle MS difference)
event = event || window.event;
// Get the root element of the event (handle MS difference)
span = event.target || event.srcElement;
// If it's a span...
if (span && span.tagName.toUpperCase() === "SPAN") {
// Hide it
span.style.display = "none";
// Get its text
text = span.innerHTML;
// Create an input
input = document.createElement("input");
input.type = "text";
input.value = text;
input.size = Math.max(text.length / 4 * 3, 4);
span.parentNode.insertBefore(input, span);
// Focus it, hook blur to undo
input.focus();
input.onblur = function() {
// Remove the input
span.parentNode.removeChild(input);
// Update the span
span.innerHTML = input.value == "" ? " " : input.value;
// Show the span again
span.style.display = "";
};
}
};
};
#container span {
background-color: #ff6;
}
<p id="container">The <span>colored items</span> in this paragraph
are <span>editable</span>.</p>
There I'm hooking the click on the parent p element, not the individual spans, because I wanted to have more than one and it's easier to do that. (It's called "event delegation.") You can find the various functions used above in the references I gave at the beginning of the answer.
In this case I used blur to take the edit down again, but you may wish to have an OK button and/or other triggers (like the Enter key).
Off-topic: You may have noticed in the JavaScript code above that I had to handle a couple of "MS differences" (e.g., things that IE does differently from other browsers), and I've used the old "DOM0" style of event handler where you just assign a function to a property, which isn't ideal, but it avoids my having to handle yet another difference where some versions of IE don't have the DOM2 addEventListener and so you have to fall back to attachEvent.
My point here is: You can smooth over browser differences and get a lot of utility functions as well by using a decent JavaScript library like jQuery, Prototype, YUI, Closure, or any of several others. You didn't say you were using any libraries, so I didn't in the above, but there are compelling reasons to use them so you don't have to worry about all the little browser niggles and can just get on with addressing your actual business need.
A trivial example using plain JavaScript would be along the lines of: http://jsfiddle.net/vzxW4/.
document.getElementById('test').onclick = function() {
document.body.removeChild(this);
var input = document.createElement('input');
input.id = 'test';
input.value = this.innerHTML;
document.body.appendChild(input);
input.select();
}
Using a library would save you time and headaches, though. For example, using jQuery: http://jsfiddle.net/vzxW4/1/.
$("#test").click(function() {
var input = $("<input>", { val: $(this).text(),
type: "text" });
$(this).replaceWith(input);
input.select();
});
Can we do it simple guys?
Just keep textbox with readonly property true and some CSS which makes text box looks like span with border.
Then as soon as user clicks on text box remove readonly attribute.
On blur restore the CSS and readonly attributes.
I'm stuck trying to get the following javascript to work in IE:
var lastMonthBn = document.createElement('input');
td.appendChild(lastMonthBn);
lastMonthBn.value='<';
lastMonthBn.type = 'button'; // Fails in IE
lastMonthBn.setAttribute('type','button'); // Also fails in IE
For some reason, i cannot set the input to a button, it fails. Works in chrome and firefox. So i'm a little confused and haven't had any luck trying to get it working.
I've isolated it to those lines by using alert()'s.
Thanks a lot
For IE, you need to set up the button first, before adding it to the document. I.e.:
var lastMonthBn = document.createElement('input');
lastMonthBn.value='<';
lastMonthBn.type = 'button';
td.appendChild(lastMonthBn); // put this last
Would this be the reason? From: http://msdn.microsoft.com/en-us/library/ms536389(v=VS.85).aspx
You must perform a second step when you use createElement to create the input element.
The createElement method generates an input text box, because that is the default input
type property. To insert any other kind of input element, first invoke createElement for
input, and then set the type property to the appropriate value in the next line of code.