Skip to content

Commit c855fd0

Browse files
authored
Copy rich text to the clipboard
1 parent 3d37c28 commit c855fd0

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copy rich text to the clipboard
2+
3+
I've been experimenting with a tool for generating the content for a weekly Substack newsletter by querying the Datasette API for my blog and assembling HTML for the last week of content.
4+
5+
I haven't started sending this out yet, but I figured out how to write rich text to the clipboard as part of my initial prototype.
6+
7+
Substack allows you to paste in rich text (e.g. copied-and-pasted rendered HTML), so it's useful to be able to programatically add rich text to the user's clipboard in order to conveniently paste into Substack.
8+
9+
Initially I tried to get this working using the new [Clipboard.write()](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write), but I spotted this warning on the [Interact with the clipboard](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard) page of MDN:
10+
11+
> However, while `navigator.clipboard.readText()` and `navigator.clipboard.writeText()` work on all browsers, `navigator.clipboard.read()` and `navigator.clipboard.write()` do not. For example, on Firefox at the time of writing, `navigator.clipboard.read()` and `navigator.clipboard.write()` are not fully implemented, such that to:
12+
>
13+
> - work with images use `browser.clipboard.setImageData()` to write images to the clipboard and `document.execCommand("paste")` to paste images to a webpage.
14+
> - write rich content (such as, HTML, rich text including images, etc.) to the clipboard, use `document.execCommand("copy")` or `document.execCommand("cut")`. Then, either `navigator.clipboard.read()` (recommended) or `document.execCommand("paste")` to read the content from the clipboard.
15+
16+
This is a bit tough to read, but the TLDR version is that for rich text copying in Firefox the `.write()` method doesn't work properly yet.
17+
18+
I actually pasted the above code into ChatGPT as a clue and got it to write me the following code, which I then tidied up and added the `document.body.appendChild()` and `document.body.removeChild()` lines (it failed without them):
19+
20+
```javascript
21+
function copyRichText(html) {
22+
const htmlContent = html;
23+
// Create a temporary element to hold the HTML content
24+
const tempElement = document.createElement("div");
25+
tempElement.innerHTML = htmlContent;
26+
document.body.appendChild(tempElement);
27+
// Select the HTML content
28+
const range = document.createRange();
29+
range.selectNode(tempElement);
30+
// Copy the selected HTML content to the clipboard
31+
const selection = window.getSelection();
32+
selection.removeAllRanges();
33+
selection.addRange(range);
34+
document.execCommand("copy");
35+
selection.removeAllRanges();
36+
document.body.removeChild(tempElement);
37+
}
38+
```
39+
## In an Observable notebook
40+
41+
I used this to add a "copy" button to my Observable notebook like this:
42+
```javascript
43+
Object.assign(html`<button>Copy rich text newsletter to clipboard`, {
44+
onclick: () => {
45+
const htmlContent = newsletterHTML;
46+
// Create a temporary element to hold the HTML content
47+
const tempElement = document.createElement("div");
48+
tempElement.innerHTML = htmlContent;
49+
document.body.appendChild(tempElement);
50+
// Select the HTML content
51+
const range = document.createRange();
52+
range.selectNode(tempElement);
53+
// Copy the selected HTML content to the clipboard
54+
const selection = window.getSelection();
55+
selection.removeAllRanges();
56+
selection.addRange(range);
57+
document.execCommand("copy");
58+
selection.removeAllRanges();
59+
document.body.removeChild(tempElement);
60+
}
61+
})
62+
```
63+
This depends on some other cell defining `newsletterHTML` as a string of HTML.
64+
65+
Here's [the notebook](https://observablehq.com/d/81869763464a0735) that uses that.

0 commit comments

Comments
 (0)