admin管理员组文章数量:1356260
I want clicking my Chrome extension’s browser action button to copy some text, but the methods used on websites don’t work.
(I realize there are some similar questions, however they answer copying text in injected scripts or browser action popup scripts, not browser action scripts.)
Boilerplate
manifest.json:
{
"name": "Example",
"version": "0.0.0",
"manifest_version": 2,
"permissions": ["clipboardWrite"],
"browser_action": {"default_title": "Copy some text"},
"background": {
"scripts": ["events.js"],
"persistent": false
}
}
events.js:
chrome.browserAction.onClicked.addListener(_ => {
copy(new Date().toISOString().slice(0, 19))
})
// Define copy() here.
Approach 1
Don’t define copy
and hope it’s defined globally as in the console.
It isn’t.
Approach 2
function copy(text) {
navigator.clipboard.writeText(text)
}
This fails with the error message “DOMException: Document is not focused”.
Approach 3
function copy(text) {
focus()
navigator.clipboard.writeText(text)
}
This behaves the same as approach 2.
Approach 4
function copy(text) {
const ta = document.createElement('textarea')
ta.value = text
ta.select()
document.execCommand('copy')
ta.remove()
}
This fails without an error message.
Approach 5
Inject a copying script into the active tab. I didn’t code this one because it would break if there are no accessible active tabs, tabs messed with their globals, JS is paused on the active tab, etc, and would also need excessive permissions.
Approach 6
function copy(text) {
open('copy.html?' + encodeURIComponent(text), '', 'width=1,height=1')
}
(Setting width and height forces opening a window, not a tab, in order to preserve the user’s tab selection and reduce visual impact.)
copy.html:
<!doctype html>
<meta charset="utf-8">
<title>Copying…</title>
<div></div>
<script src="copy.js"></script>
copy.js:
(async _ => {
await navigator.clipboard.writeText(decodeURIComponent(location.search.slice(1)))
close()
})()
This works but isn’t great because it’s visually glitchy, slow, and circuitous.
I want clicking my Chrome extension’s browser action button to copy some text, but the methods used on websites don’t work.
(I realize there are some similar questions, however they answer copying text in injected scripts or browser action popup scripts, not browser action scripts.)
Boilerplate
manifest.json:
{
"name": "Example",
"version": "0.0.0",
"manifest_version": 2,
"permissions": ["clipboardWrite"],
"browser_action": {"default_title": "Copy some text"},
"background": {
"scripts": ["events.js"],
"persistent": false
}
}
events.js:
chrome.browserAction.onClicked.addListener(_ => {
copy(new Date().toISOString().slice(0, 19))
})
// Define copy() here.
Approach 1
Don’t define copy
and hope it’s defined globally as in the console.
It isn’t.
Approach 2
function copy(text) {
navigator.clipboard.writeText(text)
}
This fails with the error message “DOMException: Document is not focused”.
Approach 3
function copy(text) {
focus()
navigator.clipboard.writeText(text)
}
This behaves the same as approach 2.
Approach 4
function copy(text) {
const ta = document.createElement('textarea')
ta.value = text
ta.select()
document.execCommand('copy')
ta.remove()
}
This fails without an error message.
Approach 5
Inject a copying script into the active tab. I didn’t code this one because it would break if there are no accessible active tabs, tabs messed with their globals, JS is paused on the active tab, etc, and would also need excessive permissions.
Approach 6
function copy(text) {
open('copy.html?' + encodeURIComponent(text), '', 'width=1,height=1')
}
(Setting width and height forces opening a window, not a tab, in order to preserve the user’s tab selection and reduce visual impact.)
copy.html:
<!doctype html>
<meta charset="utf-8">
<title>Copying…</title>
<div></div>
<script src="copy.js"></script>
copy.js:
(async _ => {
await navigator.clipboard.writeText(decodeURIComponent(location.search.slice(1)))
close()
})()
This works but isn’t great because it’s visually glitchy, slow, and circuitous.
Share Improve this question asked Feb 22, 2020 at 4:04 twhbtwhb 4,6042 gold badges23 silver badges24 bronze badges2 Answers
Reset to default 7The textarea
element should be added to the live DOM first e.g. to document.body
and focused because execCommand
operates on document.activeElement
. You can hide the textarea so it doesn't flicker.
function copy(text) {
const ta = document.createElement('textarea');
ta.style.cssText = 'opacity:0; position:fixed; width:1px; height:1px; top:0; left:0;';
ta.value = text;
document.body.appendChild(ta);
ta.focus();
ta.select();
document.execCommand('copy');
ta.remove();
}
Might wanna set a few more CSS props to none
or 0
like border/padding/margin just in case.
@wOxxOm’s answer is correct for manifest v2, but manifest v3 unfortunately made it even worse. The manifest v3 solution:
manifest.json
{
"manifest_version": 3,
"name": "Copy on Action Example",
"version": "1.0.0",
"permissions": ["clipboardWrite", "offscreen"],
"background": {"service_worker": "events.js"},
"action": {"default_title": "Copy “Hello, world!”"}
}
events.js
chrome.action.onClicked.addListener((tab) => {
copy('Hello, world!');
});
async function copy(text) {
await chrome.offscreen.createDocument({
url: chrome.runtime.getURL('copy.html'),
reasons: ['CLIPBOARD'],
justification: 'Required by Chrome to copy text.',
});
chrome.runtime.sendMessage(text);
}
copy.html
<!doctype html>
<title>Copy – Copy on Action Example</title>
<textarea id="ta"></textarea>
<script src="copy.js"></script>
copy.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const ta = document.querySelector('#ta');
ta.value = message;
ta.select();
document.execCommand('copy');
close();
});
Explanation
- As before,
copy
andnavigator.clipboard.writeText
are unavailable, even if you try to focus the document. Chrome seems to be planning on supportingnavigator.clipboard.writeText
in background pages at some point, maybe, so you might want to test it when you read this and leave a ment if it’s been added. - As before, approaches 5 and 6 are a bad idea.
- The background page is now a service worker and doesn’t have access to a document, so the
document.execCommand
method no longer works in it. Thechrome.offscreen
API was added in 2023 to fill this gap. - Offscreen pages are closed soon after creation, but timing is unreliable, and trying to open the same URL twice at once throws an error. The simplest solution is to manually close the page each time you use it, but, if you expect this to be triggered a lot in quick succession, you could be a little more efficient (and a little more plex) by instead leaving it open and later using
chrome.runtime.getContexts
to see if it’s still around. - The example simply passes the string to copy as the message, but real code will likely want to pass something like
{mand: 'copy', text: 'some text'}
, to allowsendMessage
to be used for other mands, too. document.execCommand
is actually deprecated, but I guess we’re meant to care about that about as much as Chrome does.
Links
- A very similar example from the Chrome team
chrome.offscreen
docs- Offscreen page caching example, in the above docs
本文标签: javascriptCopy text to clipboard when a Chrome extension’s browser action is clickedStack Overflow
版权声明:本文标题:javascript - Copy text to clipboard when a Chrome extension’s browser action is clicked - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744053308a2582793.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论