execCommand('copy') does not work in Ajax / XHR callback? - javascript
(Tested using Chrome 44)
Desired behaviour: Make XHR request, put result in text area, select text, and copy to clipboard.
Actual behaviour: On successful XHR request, puts the result in text area and selects it, but fails to copy result to clipboard. But if I initiate the copy outside of the XHR callback, it works.
Example html page:
var selectAndCopy = function() {
// Select text
var cutTextarea = document.querySelector('#textarea');
cutTextarea.select();
// Execute copy
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Cutting text command was ' + msg);
};
var fetchCopyButton = document.querySelector('#fetch_copy');
fetchCopyButton.addEventListener('click', function(event) {
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://httpbin.org/ip');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// Set text
var textarea = document.querySelector('#textarea');
textarea.value = xhr.responseText;
selectAndCopy();
}
}
};
xhr.send();
});
var copyButton = document.querySelector('#copy');
copyButton.addEventListener('click', function(event) {
selectAndCopy();
});
<html>
<head>
</head>
<body>
<p>
<textarea id="textarea">Hello, I'm some text!</textarea>
</p>
<p>
<button id="fetch_copy">Fetch Data and Copy Textarea</button>
<button id="copy">Copy Textarea</button>
</p>
</body>
</html>
If you press the "Fetch Data and Copy Textarea" button the data is successfully fetched but not copied. If you press the "Copy Textarea" button the text is copied as expected. I've tried many combinations of request/copy to try and get it to work but to no avail (including programmatically pressing the copy button after fetching data). Does anyone know what's going on here? Is this a security feature or something?
I don't want the user to have to press two buttons to fetch and copy if possible.
You can only trigger a copy to the system clipboard in direct response to a trusted user action, such as a click event.
Spec: http://www.w3.org/TR/clipboard-apis/#integration-with-rich-text-editing-apis
DISCLAIMER: Synchronous XMLHttpRequests are not recommended on the main thread. Please read this and make sure you know what you're doing before using this solution. THIS IS NOT RECOMMENDED FOR PRODUCTION USE.
If you make the XMLHttpRequest synchronous, this will work. You just have to add false as the third parameter to xhr.open(...):
var selectAndCopy = function() {
// Select text
var cutTextarea = document.querySelector('#textarea');
cutTextarea.select();
// Execute copy
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Cutting text command was ' + msg);
};
var fetchCopyButton = document.querySelector('#fetch_copy');
fetchCopyButton.addEventListener('click', function(event) {
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://httpbin.org/ip', false);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// Set text
var textarea = document.querySelector('#textarea');
textarea.value = xhr.responseText;
selectAndCopy();
}
}
};
xhr.send();
});
var copyButton = document.querySelector('#copy');
copyButton.addEventListener('click', function(event) {
selectAndCopy();
});
<html>
<head>
</head>
<body>
<p>
<textarea id="textarea">Hello, I'm some text!</textarea>
</p>
<p>
<button id="fetch_copy">Fetch Data and Copy Textarea</button>
<button id="copy">Copy Textarea</button>
</p>
</body>
</html>
Related
HTML- How can I insert the contents of a .txt file into a variable to use .innerHTML to change the contents of <body>?
Im trying to create an automated system for HTML page handling where I will be able to change the contents of a<div> inside <body> by writing into an external .txt file and uploading it to the server. Im still an early student in university and I havent learned PHP and JQuery yet. So I am trying to accomplish this by using only Javascript and HTML. I just need a way for whatever I write inside the .txt file to be written again inside the <div class="CONTENT" id="target"> which is inside the <body> automatically. Any thoughts and suggestions are greatly appreciated!
You can solve your problem by using the FileReader. Have a look to this answer. function readSingleFile(e) { var file = e.target.files[0]; if (!file) { return; } var reader = new FileReader(); reader.onload = function (e) { var contents = e.target.result; displayContents(contents); }; reader.readAsText(file); } function displayContents(contents) { var element = document.getElementById('target'); element.textContent = contents; } document.getElementById('file-input') .addEventListener('change', readSingleFile, false); <html> <head></head> <body> <input type="file" id="file-input" /> <h3>Contents of the file:</h3> <div id="target" class="CONTENT"></div> </body> </html>
You can make an AJAX call for the text file and take the response from that call and set that as the .textContent of the div. Here's an example (see comments inline): const output = document.getElementById("output"); // Create XHR object var xhr = new XMLHttpRequest(); // Configure the request (substitute a URL // to the file below) xhr.open("GET", filePathHere, false); // Set up the callback for when the response has // been recieved xhr.onreadystatechange = function (){ if(xhr.readyState === 4) { // Was the request successful? if(xhr.status === 200 || xhr.status == 0) { // Populate the <div> with the response text output.textContent = xhr.responseText; } } } xhr.send(null); // Make the call <div id="output"></div>
XMLHttpRequest Getting old values
I'm trying to read a file with XMLHttpRequest, get its content and add it to a chart from chart.js. function loadFile() { var xhr = new XMLHttpRequest(); xhr.open('GET', 'file.txt'); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { val = xhr.responseText; } } xhr.send(); } file.txt : 123 I have a button, when I click on it it adds val to an array (for my chart).It works, but val does not changes when the file is getting changed by the server. So it keeps adding '123' while the content of file.txt has changed.
Answer is in comment from Paulo Diogo: have you tried check the cache? Like: Press CTRL + F5 before fire another request. Or add xhr.setRequestHeader("Cache-Control", "max-age=0"); I added xhr.setRequestHeader("Cache-Control", "max-age=0"); in my button click.
Auto Link shorting via PHP&AJAX (bit.ly)
I would like to build a form (VIA POST METHOD) with just one field (url - link shortening). Now the question is how and if is it possible to build a form that detects the value of the URL field is a link and automatically shortens it rather than waiting you click Send (for exmaple like the web of Bit.ly). The main idea is once the field is an identifier that value is a proper Hyperlink is directly sends and shortens (And the field is replaced by a shortened link) it without waiting for the click on the SEND. index.html <html> <head> <script> function showHint(str) { if (str.length == 0) { document.getElementById("txtHint").innerHTML = ""; return; } else { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("txtHint").innerHTML = this.responseText; } }; xmlhttp.open("GET", "gethint.php?q=" + str, true); xmlhttp.send(); } } </script> </head> <body> <p><b>Start typing a url in the input field below:</b></p> <form> Url: <input type="text" onkeyup="showHint(this.value)"> </form> <p><span id="txtHint"></span></p> </body> </html> gethint.php <?php // get the q parameter from URL $q = $_REQUEST["q"]; $hint = ""; if (!filter_var($q, FILTER_VALIDATE_URL) === FALSE) { // short the link $rand = rand(1,1000); $hint = 'http://domain.com/'.$rand; } echo $hint === "" ? "Not a valid URL" : $hint; ?>
I'd use jQuery for the event triggering/AJAX and https://gist.github.com/dperini/729294 for weburl regex. I'm not that at home on pure JavaScript AJAX calls, but is xmlhttp.open("GET") the right way to go at it if you want to make a POST? Anyway the main thing you're missing is function isUrl(url){ var regex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i; if(regex.test(url)){ return regex.test(url); }else{ return regex.test("http://"+url); } } So this should be your new index.html <html> <head> <script> var extensions = [".aero",".biz",".cat",".com",".coop",".edu",".gov",".info",".int",".jobs",".mil",".mobi",".museum",".name",".net",".org",".travel",".ac",".ad",".ae",".af",".ag",".ai",".al",".am",".an",".ao",".aq",".ar",".as",".at",".au",".aw",".az",".ba",".bb",".bd",".be",".bf",".bg",".bh",".bi",".bj",".bm",".bn",".bo",".br",".bs",".bt",".bv",".bw",".by",".bz",".ca",".cc",".cd",".cf",".cg",".ch",".ci",".ck",".cl",".cm",".cn",".co",".cr",".cs",".cu",".cv",".cx",".cy",".cz",".de",".dj",".dk",".dm",".do",".dz",".ec",".ee",".eg",".eh",".er",".es",".et",".eu",".fi",".fj",".fk",".fm",".fo",".fr",".ga",".gb",".gd",".ge",".gf",".gg",".gh",".gi",".gl",".gm",".gn",".gp",".gq",".gr",".gs",".gt",".gu",".gw",".gy",".hk",".hm",".hn",".hr",".ht",".hu",".id",".ie",".il",".im",".in",".io",".iq",".ir",".is",".it",".je",".jm",".jo",".jp",".ke",".kg",".kh",".ki",".km",".kn",".kp",".kr",".kw",".ky",".kz",".la",".lb",".lc",".li",".lk",".lr",".ls",".lt",".lu",".lv",".ly",".ma",".mc",".md",".mg",".mh",".mk",".ml",".mm",".mn",".mo",".mp",".mq",".mr",".ms",".mt",".mu",".mv",".mw",".mx",".my",".mz",".na",".nc",".ne",".nf",".ng",".ni",".nl",".no",".np",".nr",".nu",".nz",".om",".pa",".pe",".pf",".pg",".ph",".pk",".pl",".pm",".pn",".pr",".ps",".pt",".pw",".py",".qa",".re",".ro",".ru",".rw",".sa",".sb",".sc",".sd",".se",".sg",".sh",".si",".sj",".sk",".sl",".sm",".sn",".so",".sr",".st",".su",".sv",".sy",".sz",".tc",".td",".tf",".tg",".th",".tj",".tk",".tm",".tn",".to",".tp",".tr",".tt",".tv",".tw",".tz",".ua",".ug",".uk",".um",".us",".uy",".uz", ".va",".vc",".ve",".vg",".vi",".vn",".vu",".wf",".ws",".ye",".yt",".yu",".za",".zm",".zr",".zw"]; var delay = (function(){ var timer = 0; return function(callback, ms){ clearTimeout (timer); timer = setTimeout(callback, ms); }; })(); function isUrl(url){ var regex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i; if(regex.test(url)){ return regex.test(url); }else{ return regex.test("http://"+url); } } function showHint(str) { delay(function(){ str = str.toLowerCase(); var dot = str.lastIndexOf("."); var extension = str.substr(dot); extension = extension.split('/')[0]; var found = $.inArray(extension, extensions) > -1; if (!isUrl(str)||!found) { document.getElementById("txtHint").innerHTML = ""; return; } else { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("txtHint").innerHTML = this.responseText; } }; xmlhttp.open("GET", "gethint.php?q=" + str, true); xmlhttp.send(); } }, 500) } </script> </head> <body> <p><b>Start typing a url in the input field below:</b></p> <form> Url: <input type="text" onkeyup="showHint(this.value)"> </form> <p><span id="txtHint"></span></p> </body> </html> edit: Say you will start typing in http://www.example.net.. The AJAX will trigger on "http://www.example.ne" and then again when you add the last letter. To avoid that, you might try "change" instead of "keyup" event. edit2: Now checks against list of valid domain extensions edit3: Now waits half a second before posting the result. edit4: Small oversight while checking for extensions, fixed with extension = extension.split('/')[0]; Also if you want to enable users to write URL's without "http://" and similar, you'll need an edited regex or write a small hack that adds that to your string before you send it into "isUrl()".
Error in extraction of tweets from twitter
<!doctype html> <html> <head> <title>Twitter</title> <meta charset="utf-8"> <script> window.onload = function () { // set up the click handler for the form button var button = document.getElementById("submit"); button.onclick = getTweets; } // when you click "Get Tweets" we call this function function getTweets() { // set up a new XHR request var xhr = new XMLHttpRequest(); // we're calling search.php and passing in a query string var url = "search.php?query="; var query = document.getElementById("query").value; if (!query) { query = "html5"; } // we encode the query to handle any special characters properly url += encodeURIComponent(query); // this is the function that is called when the XHR request // to our search.php script is handled, and a response sent back xhr.onload = function () { // if everything went okay, then send the response data // to the displayTweets() function if (xhr.status == 200) { displayTweets(xhr.responseText); } else { var errorDiv = document.getElementById("error"); errorDiv.innerHTML = "Error getting tweets: " + xhr.status; } }; // make the request! xhr.open("GET", url); xhr.send(null); } function displayTweets(tweets) { // tweets is a big long string, so we need to parse it // into JSON first tweets = JSON.parse(tweets); var ul = document.querySelector("ul"); // clear existing tweets from list while (ul.hasChildNodes()) { ul.removeChild(ul.lastChild); } // add new tweets for (var i = 0; i < tweets.length; i++) { var li = document.createElement("li"); li.innerHTML = tweets[i].tweet; ul.appendChild(li); } } </script> </head> <body> <form> Query: <input type="text" id="query"> <input type="button" id="submit" value="Get Tweets"> </form> <div id="error"></div> <ul></ul> </body> </html> In the above code when I enter some text in the textbox and click on "Get Tweets" button it gives an error as Error getting tweets: 0. The search.php when executed independently without embedding in html and javascript gives accurate and required results.Can you please check the html and js code and suggest any changes in code??
Seems that the issue is CROSS-DOMAIN Ajax issue. When you execute the search.php independently, then there is no X-domain issue. But when you are embedding the code in some html, check if the html is part of the same domain or not. Also, if you are trying to run the html file from file:/// it will not work.
Popup preview of a textarea using a PHP function
I'd like to make a popup preview of a textarea, using a PHP function inside the popup. Let's say you type "Hello world" in the textarea, then you click "preview" and you get your text converted to "Hey you" by a PHP function in a popup (of course the function is not that simple, that's the reason why I can't adapt this in pure javascript). Is it possible to do so ? I know it could easily send the form to an intermediate page, but I must keep the form in background... that's why I need a quick preview on fly. I did the following: function PreviewMe() { var newWin = window.open("", "_blank"); newWin.document.write("<html><body>"+document.getElementById('myText').value+"</body></html>"); newWin.document.close(); } and <textarea id="myText" ... /> <input type="submit" ... onclick="PreviewMe();"> Obviously it works without reformatting anything, so how to reformat this result in the popup please ? Would it be possible (and mayber a better option) to use XMLHttpRequest ? Thx !
Yes , you should use an XHR request to send data to a script which will return you data to be manipulated on the client side.
Thanks, it was by far easier in the end. In case it might help others, here is what I've done. Js function became : function PreviewMe() { var xhr = null; if (window.XMLHttpRequest || window.ActiveXObject) { if (window.ActiveXObject) { try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } } else { xhr = new XMLHttpRequest(); } } else { alert("XMLHTTPRequest not supported..."); return; } xhr.open("POST", "page.php", true); xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 0)) { document.getElementById('show').innerHTML = xhr.responseText; } }; xhr.send("var="+document.getElementById('myText').value+""); return; } Of course page.php includes my PHP function, show is the id of the div where the result is printed.