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

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.

Related

Quill JS - check if text change on Form Submit

I am using Quill (Rich Text) and need to find a way to checking to see if the text has changed when the page does a form submit. I am quite new to using Quill and have been looking at the events here. Using the text-change triggers everytime the text is changed (obviously) but I have other Form Input controls on the page which are checked on form submit to see if they have changed... I need my RTF boxes to do the same.
EDIT
I have managed to get the Event Firing using the example below. My problem now is that the event appears to trigger even when the editor is pre-populated on page load. I dont want to acknowledge these initial loads, only if the text has been changed by a user.
Two ways to do so:
1) listen for quill changes and if any occurred, raise a flag telling your form content has changed (flow: if you add a char, then delete it, your flag would be true even if resulting content is the same)
Using :
let changes = false
quill.on('text-change', function(delta, oldDelta, source) {
changes = true
})
2) comparing two snapshots of the document to detect front-end if changes occurred. You could either compare strings (with quill.getText()) this is the simplest, but you could miss lot of things, I would recommend to compare objects (with quill.getContents()) and use lodash or other deep equality objects method check.
Using:
const initialContents = quill.getContents()
const beforeSubmitContents = quill.getContents()
const hasChanged = _.isEqual(initialContents.ops, beforeSubmitContents.ops)
for detect if exis change only implement this function
quill.on('text-change', function(delta, oldDelta, source) {
if (source == 'api') {
console.log("An API call triggered this change.");
} else if (source == 'user') {
console.log("A user action triggered this change.");
}
});
this function detect if write or have a change on editor, detect if has change on your words or font or image...etc.. !!
In this case i use the example of official page:
page official
result :

Modify Clipboard content after copy event: JavaScript, jQuery

My requirement: When user copy some content from my web page, with text some HTML tags and carriage retun also gets copied. I need to modify the copied content in clipboard i.e. removing carriage retunn and HTML tags.
What I have tried so far:
I have captured the copy even using jQuery and get the content of clipboard. See below code.
$(document).bind('copy', function () {
//getting clipboard content
var selectedText = window.getSelection().toString();
//removing carriage retun from content
selectedText = selectedText.replace(/<\/?[^>]+(>|$)/g, "");
//Trying to set data in clipboard
window.clipboardData.setData(selectedText); //Throws error
}
Now, when I tried to setData in clipboard using window.clipboardData.setData(selectedText); , it throws error.
Questions:
1) Am I using the correct function i.e. setData() to modify the clipbard content or not?
2) Can somebody let me know how can I modify the content of clipboard here?
The currently accepted answer is overly complicated, and causes weird behavior where a user's selection is removed after copy.
Here is a much simpler solution:
document.addEventListener('copy', function(e){
var text = window.getSelection().toString().replace(/[\n\r]+/g, '');
e.clipboardData.setData('text/plain', text);
e.preventDefault();
});
To resolve this issue what I have done on copy event I have bind a function i.e. copyToClipboard which creates a textarea at run time, copy modified clipboard data to this text area and then execute a 'CUT' command (to avoid recursive call on copy event). And finally deleting textarea element in finally block.
Code:
$(document).bind('copy', function () {
var text = window.getSelection().toString().replace(/[\n\r]+/g, '');
copyToClipboard(text);
});
function copyToClipboard(text) {
var textarea = document.createElement("textarea");
textarea.textContent = text;
textarea.style.position = "fixed";
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand("cut");
} catch (ex) {
console.warn("Copy to clipboard failed.", ex);
return false;
} finally {
document.body.removeChild(textarea);
}
}
There are two things I can find out.
clipboardData object will be in callback object e passed not in window.
the correct syntax for setData is like below.
For further reference copy Event MDN
document.addEventListener('copy', function(e) {
console.log('copied');
e.clipboardData.setData('text/plain', 'Hello World!');
e.preventDefault();
});
Bind the element id with copy event and then get the selected text. You could replace or modify the text. Get the clipboard and set the new text. To get the exact formatting you need to set the type as "text/hmtl".
You may also bind it to the document instead of element.
$(ElementId).bind('copy', function(event) {
var selectedText = window.getSelection().toString();
selectedText = selectedText.replace(/\u200B/g, "");
clipboardData = event.clipboardData || window.clipboardData || event.originalEvent.clipboardData;
clipboardData.setData('text/html', selectedText);
event.preventDefault();
});

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.

Copy to clipboard without Flash

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 ;)

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