mirror of
https://github.com/mdn/webextensions-examples.git
synced 2026-04-16 06:18:35 +02:00
Add example with advanced clipboard manipulation (#207)
(tested with Firefox 52 and 54)
This commit is contained in:
35
context-menu-copy-link-with-types/README.md
Normal file
35
context-menu-copy-link-with-types/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Context menu: Copy link with types
|
||||
|
||||
This example adds a context menu item to every link that copies the URL to the
|
||||
clipboard, as plain text and as rich HTML.
|
||||
|
||||
## What it does
|
||||
|
||||
This extension includes:
|
||||
|
||||
* a background script that:
|
||||
- Registers a context menu item for every link.
|
||||
- Upon click, it invokes the function to copy text and HTML to the clipboard.
|
||||
* a helper script, "clipboard-helper.js" that provides the copy-to-clipboard functionality.
|
||||
In the example, this script is run as a content script, but the actual functionality can also
|
||||
be used in visible extension pages such as extension button popups or extension tabs.
|
||||
* a page, "preview.html" for testing the effect of copying to the clipboard.
|
||||
This page does not need to be part of the extension, and can directly be opened in the browser.
|
||||
|
||||
To test the extension, right-click on any link to open a context menu, and choose the
|
||||
"Copy link to clipboard" option. Then open preview.html and paste the clipboard content
|
||||
in the two displayed boxes. The first box will display "This is text: ..." and the second
|
||||
box will display "This is HTML: ...".
|
||||
|
||||
Note: since the add-on relies on a content script for copying the text, the copy operation
|
||||
will only succeed if the add-on is allowed to run scripts in the current page.
|
||||
If you wish to successfully copy the text even if the current page cannot be scripted, then
|
||||
you can open an (extension) page in a new tab as a fallback.
|
||||
|
||||
## What it shows
|
||||
|
||||
* how to put data on the [clipboard](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard)
|
||||
with custom types ("text/plain" and "text/html" in the example).
|
||||
* how to safely construct HTML from given text.
|
||||
* how to safely create JavaScript code to run as a dynamic content script.
|
||||
* how to dynamically run a static content script only once.
|
||||
54
context-menu-copy-link-with-types/background.js
Normal file
54
context-menu-copy-link-with-types/background.js
Normal file
@@ -0,0 +1,54 @@
|
||||
browser.contextMenus.create({
|
||||
id: "copy-link-to-clipboard",
|
||||
title: "Copy link to clipboard",
|
||||
contexts: ["link"],
|
||||
});
|
||||
browser.contextMenus.onClicked.addListener(function(info, tab) {
|
||||
if (info.menuItemId === "copy-link-to-clipboard") {
|
||||
// Examples: text and HTML to be copied.
|
||||
const text = "This is text: " + info.linkUrl;
|
||||
// Always HTML-escape external input to avoid XSS.
|
||||
const safeUrl = escapeHTML(info.linkUrl);
|
||||
const html = `This is HTML: <a href="${safeUrl}">${safeUrl}</a>`;
|
||||
|
||||
// The example will show how data can be copied, but since background
|
||||
// pages cannot directly write to the clipboard, we will run a content
|
||||
// script that copies the actual content.
|
||||
|
||||
// clipboard-helper.js defines function copyToClipboard.
|
||||
const code = "copyToClipboard(" +
|
||||
JSON.stringify(text) + "," +
|
||||
JSON.stringify(html) + ");";
|
||||
|
||||
browser.tabs.executeScript({
|
||||
code: "typeof copyToClipboard === 'function';",
|
||||
}).then(function(results) {
|
||||
// The content script's last expression will be true if the function
|
||||
// has been defined. If this is not the case, then we need to run
|
||||
// clipboard-helper.js to define function copyToClipboard.
|
||||
if (!results || results[0] !== true) {
|
||||
return browser.tabs.executeScript(tab.id, {
|
||||
file: "clipboard-helper.js",
|
||||
});
|
||||
}
|
||||
}).then(function() {
|
||||
return browser.tabs.executeScript(tab.id, {
|
||||
code,
|
||||
});
|
||||
}).catch(function(error) {
|
||||
// This could happen if the extension is not allowed to run code in
|
||||
// the page, for example if the tab is a privileged page.
|
||||
console.error("Failed to copy text: " + error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// https://gist.github.com/Rob--W/ec23b9d6db9e56b7e4563f1544e0d546
|
||||
function escapeHTML(str) {
|
||||
// Note: string cast using String; may throw if `str` is non-serializable, e.g. a Symbol.
|
||||
// Most often this is not the case though.
|
||||
return String(str)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """).replace(/'/g, "'")
|
||||
.replace(/</g, "<").replace(/>/g, ">");
|
||||
}
|
||||
18
context-menu-copy-link-with-types/clipboard-helper.js
Normal file
18
context-menu-copy-link-with-types/clipboard-helper.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// This function must be called in a visible page, such as a browserAction popup
|
||||
// or a content script. Calling it in a background page has no effect!
|
||||
function copyToClipboard(text, html) {
|
||||
function oncopy(event) {
|
||||
document.removeEventListener("copy", oncopy, true);
|
||||
// Hide the event from the page to prevent tampering.
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
// Overwrite the clipboard content.
|
||||
event.preventDefault();
|
||||
event.clipboardData.setData("text/plain", text);
|
||||
event.clipboardData.setData("text/html", html);
|
||||
}
|
||||
document.addEventListener("copy", oncopy, true);
|
||||
|
||||
// Requires the clipboardWrite permission, or a user gesture:
|
||||
document.execCommand("copy");
|
||||
}
|
||||
19
context-menu-copy-link-with-types/manifest.json
Normal file
19
context-menu-copy-link-with-types/manifest.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Context menu: Copy link with types",
|
||||
"description": "Add a context menu option to links to copy the link to the clipboard, as plain text and as a link in rich HTML.",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/context-menu-copy-link-with-types",
|
||||
|
||||
"background": {
|
||||
"scripts": [
|
||||
"background.js"
|
||||
]
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"contextMenus",
|
||||
"clipboardWrite"
|
||||
]
|
||||
}
|
||||
22
context-menu-copy-link-with-types/preview.html
Normal file
22
context-menu-copy-link-with-types/preview.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
textarea, div[contentEditable] {
|
||||
display: block;
|
||||
border: 1px solid;
|
||||
height: 5em;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Use Ctrl+V (or Cmd+V) to paste plain text here:
|
||||
<textarea></textarea>
|
||||
|
||||
Use Ctrl+V (or Cmd+V) to paste rich text (HTML) here:
|
||||
<div contentEditable></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user