├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.md ├── background.js ├── chrome-store-icon.png ├── icon.png └── manifest.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: georgemandis 4 | patreon: # 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 George Mandis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Copy URLs 2 | 3 | Minimal-fuss Chrome extension to copy URLs to your clipboard from various sources including: 4 | 5 | - Open tabs in your current window 6 | - Links within the current page 7 | - Links within a selection 8 | 9 | ## How to use 10 | 11 | - Right-click anywhere on the page and select "Copy URLs to clipboard from..." from the context menu 12 | - Select the source you wish to copy from from the sub-menu: 13 | - "Links in this selection" will copy links within any selected text on the current page 14 | - "Open tabs in this window" will copy the URLs from all the tabs in your current window 15 | - "Links on this page" will copy any links found on the page you are currently viewing 16 | - If you keep the extension pinned in your browser you can right-click the icon to reveal the context menu there as well 17 | 18 | That's it! 19 | 20 | You can find it in the Chrome Web Store here: 21 | 22 | [https://chrome.google.com/webstore/detail/copy-open-tab-urls/gpmnhkeajnnnkjkgcopciocmdcdkapbh](https://chrome.google.com/webstore/detail/copy-open-tab-urls/gpmnhkeajnnnkjkgcopciocmdcdkapbh) 23 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 📋 Copy URLs 3 | * === 4 | * Quickly copy URLs from: 5 | * - All your open tabs 6 | * - Links within the currently active tab 7 | * - Links within a selection of text 8 | * 9 | * George Mandis (george@mand.is) 10 | * https://george.mand.is 11 | */ 12 | 13 | function copyURLsToClipboard(urls) { 14 | navigator.clipboard.writeText(urls.join("\n")); 15 | } 16 | 17 | function getLinksOnPage() { 18 | return Array.from(document.links).map(a => a.href); 19 | } 20 | 21 | function getLinksWithingSelection() { 22 | const selection = document.getSelection(); 23 | const range = selection.getRangeAt(0); 24 | const links = range.cloneContents().querySelectorAll("a[href]"); 25 | return Array.from(links).map(a => a.href); 26 | } 27 | 28 | async function getURLs(req, sender) { 29 | const tabs = await chrome.tabs.query({}); 30 | const activeTab = tabs.find(t => t.active); 31 | let urls; 32 | 33 | if (req?.menuItemId == "copy-open-tab-urls") { 34 | urls = tabs.map((value) => value.url); 35 | } 36 | 37 | if (req?.menuItemId == "copy-link-urls-within-page") { 38 | urls = (await chrome.scripting.executeScript({ 39 | target: { tabId: activeTab.id }, 40 | function: getLinksOnPage 41 | }))[0].result; 42 | } 43 | 44 | if (req?.menuItemId == "copy-link-urls-within-selection") { 45 | urls = (await chrome.scripting.executeScript({ 46 | target: { tabId: activeTab.id }, 47 | function: getLinksWithingSelection 48 | }))[0].result; 49 | } 50 | 51 | chrome.scripting.executeScript({ 52 | target: { tabId: activeTab.id }, 53 | function: copyURLsToClipboard, 54 | args: [urls], 55 | }); 56 | 57 | } 58 | 59 | /** 60 | * Add handlers for context menu + action clicks 61 | */ 62 | chrome.contextMenus.onClicked.addListener(getURLs); 63 | 64 | /** 65 | * Add our context menus 66 | */ 67 | chrome.runtime.onInstalled.addListener(function () { 68 | const mainMenuId = "copy-urls"; 69 | chrome.contextMenus.create({ 70 | title: "Copy URLs to clipboard from...", 71 | id: mainMenuId, 72 | contexts: ["page", "action", "selection"] 73 | }); 74 | chrome.contextMenus.create({ 75 | title: "Links in this selection", 76 | id: "copy-link-urls-within-selection", 77 | parentId: mainMenuId, 78 | contexts: ["selection"] 79 | }); 80 | chrome.contextMenus.create({ 81 | title: "Open tabs in this window", 82 | id: "copy-open-tab-urls", 83 | parentId: mainMenuId, 84 | contexts: ["page", "action", "selection"] 85 | }); 86 | chrome.contextMenus.create({ 87 | title: "Links on this page", 88 | id: "copy-link-urls-within-page", 89 | parentId: mainMenuId, 90 | contexts: ["page", "action", "selection"] 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /chrome-store-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgemandis/copy-open-tabs-urls/a8bfc0dfd84fc36f3b53079d5e62690a944fe0b6/chrome-store-icon.png -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/georgemandis/copy-open-tabs-urls/a8bfc0dfd84fc36f3b53079d5e62690a944fe0b6/icon.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Copy URLs", 3 | "version": "2.0.0", 4 | "description": "Quickly copy URLs from your open tabs, links within a page and more to the clipboard", 5 | "author": "George Mandis ", 6 | "homepage_url": "https://george.mand.is/hire", 7 | "permissions": [ 8 | "activeTab", 9 | "contextMenus", 10 | "scripting", 11 | "tabs" 12 | ], 13 | "icons": { 14 | "128": "icon.png" 15 | }, 16 | "action": {}, 17 | "background": { 18 | "service_worker": "background.js" 19 | }, 20 | "manifest_version": 3 21 | } --------------------------------------------------------------------------------