Copy to clipboard without Flash - javascript

I found many solutions for copying to the clipboard, but they all either with flash, or for websites side.
I'm looking for method copy to clipboard automatically, without flash and for user side, it's for userscripts and of course cross-browser.

Without flash, it's simply not possible in most browsers. The user's clipboard is a security-relevant resource since it could contain things like passwords or credit card numbers. Thus, browsers rightly don't allow Javascript access to it (some allow it with a warning shown that the user has confirm, or with signed Javascript code, but none of that is cross-browser).

I had tryed the flash solution and I don't liked too. Too complex and too slow. What I did was to create a textarea, put the data into that and use the browser "CTRL + C" behavior.
The jQuery javascript part:
// catch the "ctrl" combination keydown
$.ctrl = function(key, callback, args) {
$(document).keydown(function(e) {
if(!args) args=[]; // IE barks when args is null
if(e.keyCode == key && e.ctrlKey) {
callback.apply(this, args);
return false;
}
});
};
// put your data on the textarea and select all
var performCopy = function() {
var textArea = $("#textArea1");
textArea.text('PUT THE TEXT TO COPY HERE. CAN BE A FUNCTION.');
textArea[0].focus();
textArea[0].select();
};
// bind CTRL + C
$.ctrl('C'.charCodeAt(0), performCopy);
The HTML part:
<textarea id="textArea1"></textarea>
Now, put what do you want to copy in 'PUT THE TEXT TO COPY HERE. CAN BE A FUNCTION.' area.
Works fine for me me. You just have to make one CTRL+C combination. The only drawback is that you are going to have an ugly textarea displayed in you site. If you use the style="display:none" the copy solution will not work.

clipboard.js has just been released to copy to clipboard without the need of Flash
See it in action here > http://zenorocha.github.io/clipboard.js/#example-action

It's finally here! (As long as you don't support Safari or IE8... -_- )
You can now actually handle clipboard actions without Flash. Here's the relevant documentation:
https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
https://developers.google.com/web/updates/2015/04/cut-and-copy-commands?hl=en
https://msdn.microsoft.com/en-us/library/hh801227%28v=vs.85%29.aspx#copy

While waiting impatiently for Xbrowser support of the Clipboard API...
This will work beautifully in Chrome, Firefox, Edge, IE
IE will only prompt the user once to access the Clipboard.
Safari (5.1 at the time of writing) does not support execCommand for copy/cut
/**
* CLIPBOARD
* https://stackoverflow.com/a/33337109/383904
*/
const clip = e => {
e.preventDefault();
const cont = e.target.innerHTML;
const area = document.createElement("textarea");
area.value = e.target.innerHTML; // or use .textContent
document.body.appendChild(area);
area.select();
if(document.execCommand('copy')) console.log("Copied to clipboard");
else prompt("Copy to clipboard:\nSelect, Cmd+C, Enter", cont); // Saf, Other
area.remove();
};
[...document.querySelectorAll(".clip")].forEach(el =>
el.addEventListener("click", clip)
);
<a class="clip" href="#!">Click an item to copy</a><br>
<a class="clip" href="#!"><i>Lorem</i></a><br>
<a class="clip" href="#!"><b>IPSUM</b></a><br>
<textarea placeholder="Paste here to test"></textarea>
All browsers (except Firefox which is able to only handle mime type "plain/text" as far as I've tested) have not implemented the Clipboard API. I.e, trying to read the clipboard event in Chrome using
var clipboardEvent = new ClipboardEvent("copy", {
dataType: "plain/text",
data: "Text to be sent to clipboard"
});
throws: Uncaught TypeError: Illegal constructor
The best resource of the unbelievable mess that's happening among browsers and the Clipboard can be seen here (caniuse.com) (→ Follow the comments under "Notes").
MDN says that basic support is "(YES)" for all browsers which is inaccurate cause one would expect at least the API to work, at all.

You can use a clipboard local to the HTML page. This allows you to copy/cut/paste content WITHIN the HTML page, but not from/to third party applications or between two HTML pages.
This is how you can write a custom function to do this (tested in chrome and firefox):
Here is the FIDDLE that demonstrates how you can do this.
I will also paste the fiddle here for reference.
HTML
<p id="textToCopy">This is the text to be copied</p>
<input id="inputNode" type="text" placeholder="Copied text will be pasted here" /> <br/>
copy
cut
paste
JS
function Clipboard() {
/* Here we're hardcoding the range of the copy
and paste. Change to achieve desire behavior. You can
get the range for a user selection using
window.getSelection or document.selection on Opera*/
this.oRange = document.createRange();
var textNode = document.getElementById("textToCopy");
var inputNode = document.getElementById("inputNode");
this.oRange.setStart(textNode,0);
this.oRange.setEndAfter(textNode);
/* --------------------------------- */
}
Clipboard.prototype.copy = function() {
this.oFragment= this.oRange.cloneContents();
};
Clipboard.prototype.cut = function() {
this.oFragment = this.oRange.extractContents();
};
Clipboard.prototype.paste = function() {
var cloneFragment=this.oFragment.cloneNode(true)
inputNode.value = cloneFragment.textContent;
};
window.cb = new Clipboard();

document.execCommand('copy') will do what you want. But there was no directly usable examples in this thread without cruft, so here it is:
var textNode = document.querySelector('p').firstChild
var range = document.createRange()
var sel = window.getSelection()
range.setStart(textNode, 0)
range.setEndAfter(textNode)
sel.removeAllRanges()
sel.addRange(range)
document.execCommand('copy')

There is not way around, you have to use flash. There is a JQuery plugin called jquery.copy that provided cross browser copy and paste by using a flash (swf) file. This is similar to how the syntax highlighter on my blog works.
Once you reference the jquery.copy.js file all you need to do to push data into the clipboard is run the following:
$.copy("some text to copy");
Nice and easy ;)

Related

How to tell if pasted data was copied from my page?

I'm trying to write a wysiwyg editor. I don't want people to be able to paste in foriegn html, so I figured I could convert it to text. But I still want the html to be pasted if it originated from the same element (or across the site if possible).
So is there a way to detect from a paste event where the content came from?
Detect the copy event (https://developer.mozilla.org/en-US/docs/Web/API/Element/copy_event).
Use the setData API to include a custom data type e.g. text/whatever. This can include pretty much anything, like where the user copied from, when, etc. You can even upload your own custom data representation in there.
When pasting, grab the corresponding event and look for your custom data type.
Edit: My bad, didn't read carefully about having to preventDefault.
document.addEventListener('copy', (event) => {
event.clipboardData.setData('text/test', 'sum text here');
const selection = document.getSelection();
// Essentially brute force copying selection.
const range = selection.getRangeAt(0);
const div = document.createElement('div');
div.appendChild(range.cloneContents());
const copy = div.innerHTML;
event.clipboardData.setData('text/html', copy);
event.preventDefault();
});
document.addEventListener('paste', (event) => {
const clipboard = (event.clipboardData || window.clipboardData);
let pasteTest = clipboard.getData('text/test');
let paste = clipboard.getData('text/html');
console.log (paste, '###########', pasteTest);
});
In the copy event of your editor you should add something (unique sign) into it just like a special wrap, so when in paste event you just need to judge whether the data is from your editor according to your sign.
var let_paste = false;
function handleCopy (e) {
var clipboardData, pastedData;
pastedData = e.clipboardData.getData('Text');
// When let_paste is true the content have been copied from this site
let_paste = true;
alert('let it paste!')
}
document.getElementById('myDiv').addEventListener('copy', handleCopy);
<div id='myDiv' contenteditable='true'>Copy</div>
Consider this code above - my idea is that you set a global variable that control if the content has been copied from this site or not - make an event to set it to true when the content is copied from your site. Then, save the content itself in a variable and compare with the pasted content when the user do the "paste" event.

How to programmatically copy asynchronous dependent content to the clipboard following a click?

I'm trying to programmatically use the execCommand in Chrome (Build 43) to copy the result of an asynchronous JSONP request to the clipboard. Here is a snippet of the logic :
loadContent()
function loadContent(callback) {
$.getJSON('http://www.randomtext.me/api/lorem/p-5/10-20?&callback=myFunc',function(result){
console.log('result=',result.text_out);
$("#container").html(result.text_out);
if (callback) {
callback();
}
});
}
function copyAjax() {
loadContent(copy);
}
function copy() {
var copyDivText = $('#container').text();
console.log('copyDivText=',copyDivText);
executeCopy(copyDivText);
}
document.addEventListener("DOMContentLoaded", function(){
document.getElementById("copy").onclick = copy;
});
document.addEventListener("DOMContentLoaded", function(){
document.getElementById("copyAjax").onclick = copyAjax;
});
// Copy text as text
function executeCopy(text) {
var input = document.createElement('textarea');
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
document.execCommand('Copy');
input.remove();
}
I know that starting build 43 of Chrome you code use the execCommand with clipboard. The problem, however is that you need to do it in within the execution of a user originated event (In which the permissions are elevated).
This is a similar restriction that ZeroClipboard flash based solution has.
Except from getting an answer that it is not possible (which is what I ponder about now), these are the other options I thought of doing as last resort(warning, they are all Hail Mary Passes):
Since JSONP cannot be synchronous, turn it to something that uses regular AJAX call and make sure that AJAX call is synchronous within the execution context of the user event. This goes against my deeply rooted belief we should not do synchronous XHR calls since it degrades user experience.
As the user approaches with the mouse to the copy button, we preemptively send the server request and hope it's fast enough before the user clicks the button. This is an obvious race condition which might not part of the time and will not work for certain when the use wants to do a Ctrl/Command-C instead of clicking the copy button.
Perform a two step process. One click to trigger the call, when the content is available, show a message the content is available and press another click on the msg area to copy to clipboard. It does not seem like the best UX interaction ever. I've created this example with this alternative.Triggering a click programmatically does not constitute a user issues event.
There might be a way to create a simple Chrome extension, and let the user set the permission for that extension to copy to the clipboard. This involves but the end user having to install and extension and change local browser settings. Not sure that many users will be capable/willing to do so.
I've already looked into Stackoverflow questions such as this, but they do not address an asynchronous scenario.
Please let me know if you can find any other workable solution (or a tweak on the existing one).
This is working timeout approach based on your snippet:
HTML:
<div id="container">
Enter Text To Copy</br>
<textarea id="clipboard"></textarea>
</div>
<input type="button" value="Copy" id="copy"/>
JS:
var timeout = 600; // timeout based on ajax response time
var loaded = false;
function loadContent() {
loaded = false;
$.getJSON('http://codepen.io/gkohen/pen/QbvoQW.js',function(result){
document.getElementById("clipboard").value = result.lorem;
loaded = true;
});
}
// Copy text as text
function copy() {
clipboard = document.getElementById("clipboard");
if (!loaded || clipboard.value.length == 0) {
alert("Ajax timeout! TIP: Try to increase timeout value.");
return;
}
clipboard.focus();
clipboard.select();
if (document.execCommand('Copy'))
alert("Successfuly coppied to clipboard!");
// set defaults
clipboard.value = "";
loaded = false;
}
document.addEventListener("DOMContentLoaded", function(){
document.getElementById("copy").onmousedown = loadContent;
document.getElementById("copy").onclick = function() {
setTimeout(copy, timeout); // wait for ajax
}
});
The main issue is execCommand specification. There are some restrictions about security and trusted actions. So you have to make event calling copy and ajax call aparte. This can be done dirty way - by fixed timeout (code above) or proper way - by breakable sleep. New sleep feature is mentioned here and maybe can be modified to breakable variant via clearTimeout, but I did not try.

Copy to Clipboard for all Browsers using javascript

I was trying to make "Copy to Clipboard" work on all browsers but no luck.
Am using javascript and I don't want to use Zero Clipboard to do.
Please let us know what wrong in my code.
Appreciate for your help.
Below is the code (Currently my code is working only on IE browser):-
<script type="text/javascript">
function copyToClipboard(s)
{
if( window.clipboardData && clipboardData.setData )
{
clipboardData.setData("Text", s);
}
else
{
// You have to sign the code to enable this or allow the action in about:config by changing
user_pref("signed.applets.codebase_principal_support", true);
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var clip = Components.classes['#mozilla.org/widget/clipboard;[[[[1]]]]'].createInstance(Components.interfaces.nsIClipboard);
if (!clip) return;
// create a transferable
var trans = Components.classes['#mozilla.org/widget/transferable;[[[[1]]]]'].createInstance(Components.interfaces.nsITransferable);
if (!trans) return;
// specify the data we wish to handle. Plaintext in this case.
trans.addDataFlavor('text/unicode');
// To get the data from the transferable we need two new objects
var str = new Object();
var len = new Object();
var str = Components.classes["#mozilla.org/supports-string;[[[[1]]]]"].createInstance(Components.interfaces.nsISupportsString);
var copytext=meintext;
str.data=copytext;
trans.setTransferData("text/unicode",str,copytext.length*[[[[2]]]]);
var clipid=Components.interfaces.nsIClipboard;
if (!clip) return false;
clip.setData(trans,null,clipid.kGlobalClipboard);
}
}
</script>
<textarea id='testText' rows="10" cols="100">Enter your Sample text</textarea><br />
<button onclick="copyToClipboard(document.getElementById('testText').value);" >clipboard</button><br /><br />
<textarea rows="10" cols="100">Paste your text here</textarea><br />
This works on firefox 3.6.x and IE:
function copyToClipboardCrossbrowser(s) {
s = document.getElementById(s).value;
if( window.clipboardData && clipboardData.setData )
{
clipboardData.setData("Text", s);
}
else
{
// You have to sign the code to enable this or allow the action in about:config by changing
//user_pref("signed.applets.codebase_principal_support", true);
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var clip = Components.classes["#mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
if (!clip) return;
// create a transferable
var trans = Components.classes["#mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if (!trans) return;
// specify the data we wish to handle. Plaintext in this case.
trans.addDataFlavor('text/unicode');
// To get the data from the transferable we need two new objects
var str = new Object();
var len = new Object();
var str = Components.classes["#mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
str.data= s;
trans.setTransferData("text/unicode",str, str.data.length * 2);
var clipid=Components.interfaces.nsIClipboard;
if (!clip) return false;
clip.setData(trans,null,clipid.kGlobalClipboard);
}
}
I spent a lot of time looking for a solution to this problem too. Here's what i've found thus far:
If you want your users to be able to click on a button and copy some text, you may have to use Flash.
If you want your users to press Ctrl+C anywhere on the page, but always copy xyz to the clipboard, I wrote an all-JS solution in YUI3 (although it could easily be ported to other frameworks, or raw JS if you're feeling particularly self-loathing).
It involves creating a textbox off the screen which gets highlighted as soon as the user hits Ctrl/CMD. When they hit 'C' shortly after, they copy the hidden text. If they hit 'V', they get redirected to a container (of your choice) before the paste event fires.
This method can work well, because while you listen for the Ctrl/CMD keydown anywhere in the body, the 'A', 'C' or 'V' keydown listeners only attach to the hidden text box (and not the whole body).
It also doesn't have to break the users expectations - you only get redirected to the hidden box if you had nothing selected to copy anyway!
Here's what i've got working on my site, but check http://at.cg/js/clipboard.js for updates if there are any:
YUI.add('clipboard', function(Y) {
// Change this to the id of the text area you would like to always paste in to:
pasteBox = Y.one('#pasteDIV');
// Make a hidden textbox somewhere off the page.
Y.one('body').append('<input id="copyBox" type="text" name="result" style="position:fixed; top:-20%;" onkeyup="pasteBox.focus()">');
copyBox = Y.one('#copyBox');
// Key bindings for Ctrl+A, Ctrl+C, Ctrl+V, etc:
// Catch Ctrl/Window/Apple keydown anywhere on the page.
Y.on('key', function(e) {
copyData();
// Uncomment below alert and remove keyCodes after 'down:' to figure out keyCodes for other buttons.
// alert(e.keyCode);
// }, 'body', 'down:', Y);
}, 'body', 'down:91,224,17', Y);
// Catch V - BUT ONLY WHEN PRESSED IN THE copyBox!!!
Y.on('key', function(e) {
// Oh no! The user wants to paste, but their about to paste into the hidden #copyBox!!
// Luckily, pastes happen on keyPress (which is why if you hold down the V you get lots of pastes), and we caught the V on keyDown (before keyPress).
// Thus, if we're quick, we can redirect the user to the right box and they can unload their paste into the appropriate container. phew.
pasteBox.select();
}, '#copyBox', 'down:86', Y);
// Catch A - BUT ONLY WHEN PRESSED IN THE copyBox!!!
Y.on('key', function(e) {
// User wants to select all - but he/she is in the hidden #copyBox! That wont do.. select the pasteBox instead (which is probably where they wanted to be).
pasteBox.select();
}, '#copyBox', 'down:65', Y);
// What to do when keybindings are fired:
// User has pressed Ctrl/Meta, and is probably about to press A,C or V. If they've got nothing selected, or have selected what you want them to copy, redirect to the hidden copyBox!
function copyData() {
var txt = '';
// props to Sabarinathan Arthanari for sharing with the world how to get the selected text on a page, cheers mate!
if (window.getSelection) { txt = window.getSelection(); }
else if (document.getSelection) { txt = document.getSelection(); }
else if (document.selection) { txt = document.selection.createRange().text; }
else alert('Something went wrong and I have no idea why - please contact me with your browser type (Firefox, Safari, etc) and what you tried to copy and I will fix this immediately!');
// If the user has nothing selected after pressing Ctrl/Meta, they might want to copy what you want them to copy.
if(txt=='') {
copyBox.select();
}
// They also might have manually selected what you wanted them to copy! How unnecessary! Maybe now is the time to tell them how silly they are..?!
else if (txt == copyBox.get('value')) {
alert('This site uses advanced copy/paste technology, possibly from the future.\n \nYou do not need to select things manually - just press Ctrl+C! \n \n(Ctrl+V will always paste to the main box too.)');
copyBox.select();
} else {
// They also might have selected something completely different! If so, let them. It's only fair.
}
}
});
Hope someone else finds this useful :]
For security reasons most browsers do not allow to modify the clipboard (except IE, of course...).
The only way to make a copy-to-clipboard function cross-browser compatible is to use Flash.
I think zeroclipboard is great. this version work with latest Flash 11: http://www.itjungles.com/javascript/javascript-easy-cross-browser-copy-to-clipboard-solution.

How do I capture the input value on a paste event?

On my site users can paste text (in this case a url) into an input field. I'd like to capture the value of the text that was pasted using jQuery. I've got this to work in FF using the code below, but it doesn't work in IE (I don't think IE supports the "paste" event).
Anyone know how to make this work across all modern browsers? I've found a few other answers to this on SO but most are FF-only and none seemed to offer a complete solution.
Here's the code I have so far:
$("input.url").live('paste', function(event) {
var _this = this;
// Short pause to wait for paste to complete
setTimeout( function() {
var text = $(_this).val();
$(".display").html(text);
}, 100);
});
JSFiddle: http://jsfiddle.net/TZWsB/1/
jQuery has a problem with the live-method with the paste-event in the IE; workaround:
$(document).ready(function() {
$(".url").bind('paste', function(event) {
var _this = this;
// Short pause to wait for paste to complete
setTimeout( function() {
var text = $(_this).val();
$(".display").html(text);
}, 100);
});
});
Fiddle: http://jsfiddle.net/Trg9F/
$('input').on('paste', function(e) {
// common browser -> e.originalEvent.clipboardData
// uncommon browser -> window.clipboardData
var clipboardData = e.clipboardData || e.originalEvent.clipboardData || window.clipboardData;
var pastedData = clipboardData.getData('text');
});
Listen for the change event as well as paste. change will reliably fire on a changed field before submission, whereas paste only happens on browsers that support it on an explicit paste; it won't be triggered by other editing actions such as drag-and-drop, cut-copy, undo-redo, spellcheck, IME substitution etc.
The problem with change is that it doesn't fire straight away, only when editing in a field is finished. If you want to catch all changes as they happen, the event would be input... except that this is a new HTML5 feature that isn't supported everywhere (notably: IE<9). You could nearly do it by catching all these events:
$('.url').bind('input change paste keyup mouseup',function(e){
...
});
But if you want to definitely catch every change quickly on browsers that don't support input, you have no choice but to poll the value on a setInterval.
Even better is it to use e.originalEvent.clipboardData.getData('text'); to retrieve pasted data;
$("input").on("paste", function(e) {
var pastedData = e.originalEvent.clipboardData.getData('text');
// ... now do with pastedData whatever you like ...
});
This way you can avoid timeouts and it is supported on all major browsers.
Maybe try using the onblur event instead. So the user c/p into the input and when they leave the field the script checks what's there. This could save a whole lot of hassle, since it works for mouse and key c/p as well as manually entered input.

Copy text to clipboard from bookmarklet

I'm trying to write a little bookmarklet that can extract some text from the active page and load that into the clipboard.
The extraction is easy enough, but I'm really stuck doing the clipboard-copying part. Currently, I'm just alerting the text and hitting Ctrl+C to copy the text from the message-box, which isn't ideal.
I've read How to Copy to Clipboard in JavaScript and other questions that suggest I use zeroclipboard, but I have no idea how one would make that work from a bookmarklet, considering I have to load external flash and javascript resources to be able to use the library.
I have no issues with messing up the page's DOM to accomplish this or having to enable some permissions on my browser (Google Chrome), considering this is just a private bookmarklet.
Any pointers would be appreciated.
There is a nice little bookmarket in Github Gist that does the core of what you want -- copying to the clipboard. It does not use any external libraries, which I think of as an advantage.
As written, it copies some static text, but toward the bottom it talks about adapting it to other uses, such as copying the page title.
Since you've stated that 'The extraction is easy enough ...', you should be easily be able to adapt that gist to what you want to do.
I tried the plain vanilla version of the bookmarklet, because I have some static text that I often need to transfer to my clipboard. It works very well in Chrome 61 with no modifications. But make sure you read the comments; some people have suggestions on getting it to work in other browsers and scenarios.
Here is the code that I tested, already minified and ready to turn into a bookmarklet:
javascript:!function(a){var b=document.createElement("textarea"),c=document.getSelection();b.textContent=a,document.body.appendChild(b),c.removeAllRanges(),b.select(),document.execCommand("copy"),c.removeAllRanges(),document.body.removeChild(b)}("Text To Copy");
Gist has the pre-minified code as well.
Since the new Clipboard API, this is easy in browsers that support it:
javascript: navigator.clipboard.writeText('some text from somewhere');null;
Caveat: Any alerts or prompts in your bookmarklet will cause the document to lose focus, and the clipboard API will become unavailable. In that case you need to move focus back into the document before any subsequent clipboard operations will work:
const oldFocus = document.activeElement;
/* do popup stuff here */
oldFocus.focus();
/* do clipboard stuff here */
With recent versions of Firefox, interacting with the clipboard via a bookmarklet in general won't work due to missing permissions (see this information for more details). There may be a way, however, to have the bookmarklet display a button, and perform the clipboard interaction in the context of a button-click event handler.
A possibly more straightforward solution is to use a user-script manager, and define your bookmarklet in the form of a user-script that you can activate via a keyboard combination. See, for example this user script, reproduced here for completeness:
// Add the following as a user-script (via an extension like https://github.com/violentmonkey/violentmonkey) in order to copy the
// current webpage and selected text to the clipboard in a format suitable for pasting into an org-mode document.
// To execute the action, you need to press Alt-C on a webpage, though this can be modified by changing the keycode
// used in the onkeyup function.
// ==UserScript==
// #name Copy Org-mode Link
// #namespace Violentmonkey Scripts
// #match *://*/*
// #grant clipboardWrite
// ==/UserScript==
function main() {
function copyTextToClipboard(text) { var textArea = document.createElement("textarea"); textArea.style.position = 'fixed'; textArea.style.top = 0; textArea.style.left = 0; textArea.style.width = '2em'; textArea.style.height = '2em'; textArea.style.padding = 0; textArea.style.border = 'none'; textArea.style.outline = 'none'; textArea.style.boxShadow = 'none'; textArea.style.background = 'transparent'; textArea.value = text; document.body.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); }; var url = encodeURIComponent(location.href); url = url.replace(/%253A/g, ':').replace(/%252F/g, '/'); var title = document.title; title = title.replace(/\[/g, '{'); title = title.replace(/\]/g, '}'); var sel_text = window.getSelection(); copyTextToClipboard('[['+url+']['+title+']]'+'\n\n'+sel_text);
}
// listen for Alt-C key-combination, and then execute
document.onkeyup=function(e){
var e = e || window.event; // for IE to cover IEs window object
if(e.altKey && e.which == 67) {
main();
return false;
}
}
An answer that's a bit unusual: open a blank page from which the user will copy the text:
<a href="javascript:window.open('data:text/html, <html contenteditable>sup<script>document.execCommand(\'selectAll\')</script></html>')">
Copy the text “sup”
</a>
Just replace sup by the text you want the user to copy.
JS Bin example
Here's how I solved it, using the technique #zzzzBov mentioned in his answer, to import zeroclipboard into the page via a bookmarklet.
When the bookmarket runs, a hand cursor appears on hovering over anywhere on the body. Clicking will copy (for example) the document's title to the clipboard.
(Links to zeroclipboard resources have been replaced with placeholders, and multi-line comments have been used since Chrome appears to be removing all line-breaks from bookmarklets (or something))
javascript:
var s = document.createElement('script');
s.setAttribute('src', 'http://example.com/ZeroClipboard.js');
s.onload = s.onreadystatechange =
function()
{
ZeroClipboard.setMoviePath( 'http://example.com/ZeroClipboard.swf');
var clip = new ZeroClipboard.Client();
/* glue to the body: sample only, in reality we should
probably create a new visible element and glue to that. */
clip.glue(document.body);
clip.setHandCursor( true );
/* copy to clipboard on mouse-up */
clip.addEventListener('onMouseUp',
function (client)
{
/* example */
var toCopy = document.title;
clip.setText(toCopy);
alert(toCopy + ' copied.');
clip.hide();
});
};
document.body.appendChild(s);
A couple disclaimers:
I'm not trying to spam you
I gain nothing if you choose to use this
I made a bookmarklet generator a while back to make it easier for me to create bookmarklets.
It's jQuery enabled, but that doesn't mean you have to use jQuery.
You can check out the source to see how to import another script/library into a page via a bookmarklet.
In particular, the lines that import jQuery:
if (!window.zbooks)
{
//if zbooks hasn't been set, initialize it
//s used for the Script element
var s = document.createElement('script');
//r used for the Ready state
var r = false;
//set the script to the latest version of jQuery
s.setAttribute('src', 'http://code.jquery.com/jquery-latest.min.js');
//set the load/readystate events
s.onload = s.onreadystatechange = function()
{
/**
* LOAD/READYSTATE LOGIC
* execute if the script hasn't been ready yet and:
* - the ready state isn't set
* - the ready state is complete
* - note: readyState == 'loaded' executes before the script gets called so
* we skip this event because it wouldn't have loaded the init event yet.
*/
if ( !r && (!this.readyState || this.readyState == 'complete' ) )
{
//set the ready flag to true to keep the event from initializing again
r = true;
//prevent jQuery conflicts by placing jQuery in the zbooks object
window.zbooks = {'jQuery':jQuery.noConflict()};
//make a new zbook
window.zbooks[n] = new zbooks(c);
}
};
//append the jQuery script to the body
b.appendChild(s);
}
I hope that helps.
A solution for both HTTP and HTTPS contexts
The Clipboard API solution by #Joachim Lous was on the right track for me. However, this did not work on localhost, which used http not https. To get around this, I used a "copyToClipboard" function (adapted from this SO answer) which acts as an all-in-one wrapper function that takes into account a http context by using a clever "out of viewport hidden text area" trick.
Readable version:
javascript:
function copyToClipboard(textToCopy) {
// navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard api method
return navigator.clipboard.writeText(textToCopy);
} else {
// use the 'out of viewport hidden text area' trick
let textArea = document.createElement("textarea");
textArea.value = textToCopy;
// 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();
});
}
};
var element = document.querySelector(".myClass");
var text = element.textContent || element.value;
copyToClipboard(text);
Simply replace ".myClass" with your selector.
Minified version for bookmarklet:
javascript:void function(){var a=document.querySelector(".myClass"),b=a.textContent||a.value;(function(a){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(a);else{let b=document.createElement("textarea");return b.value=a,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select(),new Promise((a,c)=>{document.execCommand("copy")?a():c(),b.remove()})}})(b)}();
Edit:
The following is a solution for those interested in dynamically selecting text from a page.
javascript:void function(){function a(a){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(a);else{let b=document.createElement("textarea");return b.value=a,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select(),new Promise((a,c)=>{document.execCommand("copy")?a():c(),b.remove()})}}function b(a){c.style.pointerEvents="none";var b=document.elementFromPoint(a.clientX,a.clientY);return c.style.pointerEvents="auto",b}var c=document.createElement("div");Object.assign(c.style,{position:"fixed",top:0,left:0,width:"100vw",height:"100vh",zIndex:99999999,background:"transparent",cursor:"crosshair"}),document.body.append(c);document.addEventListener("mousemove",function(a){var d=b(a);if(d){var e=d.getBoundingClientRect();Object.assign(c.style,{background:"rgba(0, 128, 255, 0.25)",outline:"1px solid rgba(0, 128, 255, 0.5)",top:""+e.top+"px",left:""+e.left+"px",width:""+e.width+"px",height:""+e.height+"px"})}}),c.addEventListener("click",function(d){var e=b(d),f=e.textContent||e.value;f=f.replace(/\n[ \n]+\n/g,"\n").replace(/\n\n+/g,"\n\n").replace(/^\n+|\n+$/g,""),f.match("\n")||(f=f.replace(/^ +| +$/,"")),a(f),document.body.removeChild(c)})}();
Simply copy and paste it to the "URL" portion of your bookmark as shown below:

Categories